1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.config.exclusion;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Set;
27 import java.util.TreeSet;
28 import java.util.stream.Collectors;
29
30 import org.apache.rat.document.DocumentName;
31 import org.apache.rat.document.DocumentNameMatcher;
32 import org.apache.rat.utils.DefaultLog;
33 import org.apache.rat.utils.ExtendedIterator;
34
35 import static java.lang.String.format;
36
37
38
39
40
41 public class ExclusionProcessor {
42
43 private final Set<String> excludedPatterns;
44
45 private final List<DocumentNameMatcher> excludedPaths;
46
47 private final Set<String> includedPatterns;
48
49 private final List<DocumentNameMatcher> includedPaths;
50
51
52
53
54 private final Set<StandardCollection> fileProcessors;
55
56 private final Set<StandardCollection> includedCollections;
57
58 private final Set<StandardCollection> excludedCollections;
59
60 private DocumentNameMatcher lastMatcher;
61
62 private DocumentName lastMatcherBaseDir;
63
64
65
66
67 public ExclusionProcessor() {
68 excludedPatterns = new HashSet<>();
69 excludedPaths = new ArrayList<>();
70 includedPatterns = new HashSet<>();
71 includedPaths = new ArrayList<>();
72 fileProcessors = new HashSet<>();
73 includedCollections = new HashSet<>();
74 excludedCollections = new HashSet<>();
75 }
76
77
78 private void resetLastMatcher() {
79 lastMatcher = null;
80 lastMatcherBaseDir = null;
81 }
82
83
84
85
86
87
88 public ExclusionProcessor addIncludedPatterns(final Iterable<String> patterns) {
89 DefaultLog.getInstance().debug(format("Including patterns: %s", String.join(", ", patterns)));
90 patterns.forEach(includedPatterns::add);
91 resetLastMatcher();
92 return this;
93 }
94
95
96
97
98
99
100 public ExclusionProcessor addIncludedMatcher(final DocumentNameMatcher matcher) {
101 if (matcher != null) {
102 includedPaths.add(matcher);
103 resetLastMatcher();
104 }
105 return this;
106 }
107
108
109
110
111
112
113 public ExclusionProcessor addFileProcessor(final StandardCollection collection) {
114 if (collection != null) {
115 DefaultLog.getInstance().debug(format("Processing exclude file from %s.", collection));
116 fileProcessors.add(collection);
117 resetLastMatcher();
118 }
119 return this;
120 }
121
122
123
124
125
126
127 public ExclusionProcessor addIncludedCollection(final StandardCollection collection) {
128 if (collection != null) {
129 DefaultLog.getInstance().debug(format("Including %s collection.", collection));
130 includedCollections.add(collection);
131 resetLastMatcher();
132 }
133 return this;
134 }
135
136
137
138
139
140
141 public ExclusionProcessor addExcludedPatterns(final Iterable<String> patterns) {
142 DefaultLog.getInstance().debug(format("Excluding patterns: %s", String.join(", ", patterns)));
143 patterns.forEach(excludedPatterns::add);
144 resetLastMatcher();
145 return this;
146 }
147
148
149
150
151
152
153 public ExclusionProcessor addExcludedMatcher(final DocumentNameMatcher matcher) {
154 if (matcher != null) {
155 excludedPaths.add(matcher);
156 resetLastMatcher();
157 }
158 return this;
159 }
160
161
162
163
164
165 public void reportExclusions(final Appendable appendable) throws IOException {
166 appendable.append(format("Excluding patterns: %s%n", String.join(", ", excludedPatterns)));
167 appendable.append(format("Including patterns: %s%n", String.join(", ", includedPatterns)));
168 for (StandardCollection sc : excludedCollections) {
169 appendable.append(format("Excluding %s collection.%n", sc.name()));
170 }
171 for (StandardCollection sc : includedCollections) {
172 appendable.append(format("Including %s collection.%n", sc.name()));
173 }
174 for (StandardCollection sc : fileProcessors) {
175 appendable.append(format("Processing exclude file from %s.%n", sc.name()));
176 }
177 for (DocumentNameMatcher nameMatcher : excludedPaths) {
178 appendable.append(format("Excluding %s.%n", nameMatcher.toString()));
179 }
180 }
181
182
183
184
185
186
187
188 public ExclusionProcessor addExcludedCollection(final StandardCollection collection) {
189 if (collection != null) {
190 DefaultLog.getInstance().debug(format("Excluding %s collection.", collection));
191 excludedCollections.add(collection);
192 resetLastMatcher();
193 }
194 return this;
195 }
196
197
198
199
200
201
202
203 public DocumentNameMatcher getNameMatcher(final DocumentName basedir) {
204
205
206
207 if (lastMatcher == null || !basedir.equals(lastMatcherBaseDir)) {
208 lastMatcherBaseDir = basedir;
209
210
211 final List<MatcherSet> matchers = extractFileProcessors(basedir);
212 final MatcherSet.Builder fromCommandLine = new MatcherSet.Builder();
213 DocumentName.Builder nameBuilder = DocumentName.builder(basedir).setBaseName(basedir);
214 extractPatterns(nameBuilder, fromCommandLine);
215 extractCollectionPatterns(nameBuilder, fromCommandLine);
216 extractCollectionMatchers(fromCommandLine);
217 extractPaths(fromCommandLine);
218 matchers.add(fromCommandLine.build());
219
220 lastMatcher = MatcherSet.merge(matchers).createMatcher();
221 DefaultLog.getInstance().debug(format("Created matcher set for %s%n%s", basedir.getName(),
222 lastMatcher));
223 }
224 return lastMatcher;
225 }
226
227
228
229
230
231
232 private List<MatcherSet> extractFileProcessors(final DocumentName basedir) {
233 final List<MatcherSet> fileProcessorList = new ArrayList<>();
234 for (StandardCollection sc : fileProcessors) {
235 ExtendedIterator<List<MatcherSet>> iter = sc.fileProcessorBuilder().map(builder -> builder.build(basedir));
236 if (iter.hasNext()) {
237 iter.forEachRemaining(fileProcessorList::addAll);
238 } else {
239 DefaultLog.getInstance().debug(String.format("%s does not have a fileProcessor.", sc));
240 }
241 }
242 return fileProcessorList;
243 }
244
245
246
247
248
249
250
251
252 private String preparePattern(final DocumentName documentName, final String pattern) {
253 return ExclusionUtils.qualifyPattern(documentName,
254 ExclusionUtils.convertSeparator(pattern, "/", documentName.getDirectorySeparator()));
255 }
256
257
258
259
260
261
262 private void extractPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) {
263 DocumentName name = nameBuilder.setName("Patterns").build();
264 if (!excludedPatterns.isEmpty()) {
265 matcherBuilder.addExcluded(name, excludedPatterns.stream()
266 .map(s -> preparePattern(name, s))
267 .collect(Collectors.toSet()));
268 }
269 if (!includedPatterns.isEmpty()) {
270 matcherBuilder.addIncluded(name, includedPatterns.stream()
271 .map(s -> preparePattern(name, s)).collect(Collectors.toSet()));
272 }
273 }
274
275
276
277
278
279
280 private void extractCollectionPatterns(final DocumentName.Builder nameBuilder, final MatcherSet.Builder matcherBuilder) {
281 final Set<String> incl = new TreeSet<>();
282 final Set<String> excl = new TreeSet<>();
283 for (StandardCollection sc : includedCollections) {
284 Set<String> patterns = sc.patterns();
285 if (patterns.isEmpty()) {
286 DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for inclusion.", sc));
287 } else {
288 MatcherSet.Builder.segregateList(incl, excl, sc.patterns());
289 }
290 }
291 for (StandardCollection sc : excludedCollections) {
292 Set<String> patterns = sc.patterns();
293 if (patterns.isEmpty()) {
294 DefaultLog.getInstance().debug(String.format("%s does not have a defined collection for exclusion.", sc));
295 } else {
296 MatcherSet.Builder.segregateList(excl, incl, sc.patterns());
297 }
298 }
299 DocumentName name = nameBuilder.setName("Collections").build();
300 matcherBuilder
301 .addExcluded(name, excl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet()))
302 .addIncluded(name, incl.stream().map(s -> preparePattern(name.getBaseDocumentName(), s)).collect(Collectors.toSet()));
303 }
304
305
306
307
308
309 private void extractCollectionMatchers(final MatcherSet.Builder matcherBuilder) {
310 ExtendedIterator.create(includedCollections.iterator())
311 .map(StandardCollection::staticDocumentNameMatcher)
312 .filter(Objects::nonNull)
313 .forEachRemaining(matcherBuilder::addIncluded);
314
315 ExtendedIterator.create(excludedCollections.iterator())
316 .map(StandardCollection::staticDocumentNameMatcher)
317 .filter(Objects::nonNull)
318 .forEachRemaining(matcherBuilder::addExcluded);
319 }
320
321
322
323
324
325 private void extractPaths(final MatcherSet.Builder matcherBuilder) {
326 if (!includedPaths.isEmpty()) {
327 for (DocumentNameMatcher matcher : includedPaths) {
328 DefaultLog.getInstance().debug(format("Including path matcher %s", matcher));
329 matcherBuilder.addIncluded(matcher);
330 }
331 }
332 if (!excludedPaths.isEmpty()) {
333 for (DocumentNameMatcher matcher : excludedPaths) {
334 DefaultLog.getInstance().debug(format("Excluding path matcher %s", matcher));
335 matcherBuilder.addExcluded(matcher);
336 }
337 }
338 }
339
340 }