View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.rat.config.exclusion;
20  
21  import java.io.File;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  import java.util.function.Predicate;
30  import java.util.function.Supplier;
31  
32  import org.apache.rat.config.exclusion.fileProcessors.AbstractFileProcessorBuilder;
33  import org.apache.rat.config.exclusion.fileProcessors.BazaarIgnoreBuilder;
34  import org.apache.rat.config.exclusion.fileProcessors.CVSIgnoreBuilder;
35  import org.apache.rat.config.exclusion.fileProcessors.GitIgnoreBuilder;
36  import org.apache.rat.config.exclusion.fileProcessors.HgIgnoreBuilder;
37  import org.apache.rat.document.DocumentName;
38  import org.apache.rat.document.DocumentNameMatcher;
39  import org.apache.rat.utils.ExtendedIterator;
40  
41  /**
42   * Collection of standard excludes.
43   * HINT: In order to work recursively each entry is prefixed with {@code "**\/"}.
44   */
45  public enum StandardCollection {
46      /**
47       * All the standard excludes combined.
48       */
49      // see getCollections() for loading
50      ALL("All of the Standard Excludes combined.", null, null, null),
51      /**
52       * The files and directories created by an ARCH source code control based tool.
53       */
54      ARCH("The files and directories created by an ARCH source code control based tool.",
55              Collections.singletonList("**/.arch-ids/**"), null, null),
56      /**
57       * The files and directories created by a Bazaar source code control based tool.
58       */
59      BAZAAR("The files and directories created by a Bazaar source code control based tool.",
60              Arrays.asList("**/.bzr/**", "**/.bzrignore"), null, BazaarIgnoreBuilder::new),
61      /**
62       * The files and directories created by a Bitkeeper source code control based tool.
63       */
64      BITKEEPER("The files and directories created by a Bitkeeper source code control based tool.",
65              Arrays.asList("**/BitKeeper/**", "**/ChangeSet/**"), null, null),
66      /**
67       * The files and directories created by a CVS source code control based tool.
68       * @see <a href="https://www.gnu.org/software/trans-coord/manual/cvs/html_node/cvsignore.html#cvsignore">Ignoring files via cvsignore</a>
69       */
70      CVS("The files and directories created by a CVS source code control based tool.",
71              Arrays.asList("**/.cvsignore",
72                      "**/RCS/**", "**/SCCS/**", "**/CVS/**", "**/CVS.adm/**",
73                      "**/RCSLOG/**", "**/cvslog.*", "**/tags/**", "**/TAGS/**",
74                      "**/.make.state", "**/.nse_depinfo",
75                      "**/*~", "**/#*", "**/.#*", "**/,*", "**/_$*", "**/*$", "**/*.old", "**/*.bak", "**/*.BAK",
76                      "**/*.orig", "**/*.rej", "**/.del-*",
77                      "**/*.a", "**/*.old", "**/*.o", "**/*.obj", "**/*.so", "**/*.exe",
78                      "**/*.Z", "**/*.elc", "**/*.ln", "**/core"),
79              null, CVSIgnoreBuilder::new),
80      /**
81       * The files and directories created by a DARCS source code control based tool.
82       */
83      DARCS("The files and directories created by a DARCS source code control based tool.",
84              Arrays.asList("**/_darcs/**", "**/.darcsrepo/**", "**/-darcs-backup*", "**/.darcs-temp-mail"), null, null),
85      /**
86       * The files and directories created by an Eclipse IDE based tool.
87       */
88      ECLIPSE("The files and directories created by an Eclipse IDE based tool.",
89              Arrays.asList("**/.checkstyle", "**/.classpath", "**/.factorypath",
90                      "**/.project", "**/.settings/**", "**/.externalToolBuilders/**", "**/bin/**"),
91              null, null),
92      /**
93       * The files and directories created by GIT source code control to support GIT, also processes files listed in '.gitignore'
94       * and (unless RAT_NO_GIT_GLOBAL_IGNORE is specified) the global gitignore.
95       */
96      GIT("The files and directories created by GIT source code control to support GIT, also processes files listed in '.gitignore' " +
97          "and (unless RAT_NO_GIT_GLOBAL_IGNORE is specified) the global gitignore.",
98              Arrays.asList("**/.git/**", "**/.gitignore"),
99              null,
100             GitIgnoreBuilder::new
101     ),
102     /**
103      * The hidden directories. Directories with names that start with {@code .}
104      */
105     HIDDEN_DIR("The hidden directories. Directories with names that start with '.'",
106             null,
107             new DocumentNameMatcher("HIDDEN_DIR", new Predicate<>() {
108                 @Override
109                 public boolean test(final DocumentName documentName) {
110                     File file = documentName.asFile();
111                     return file.isDirectory() && ExclusionUtils.isHidden(documentName.getShortName());
112                 }
113 
114                 @Override
115                 public String toString() {
116                     return "HIDDEN_DIR";
117                 }
118             }), null
119     ),
120     /**
121      * The hidden files. Directories with names that start with {@code .}
122      */
123     HIDDEN_FILE("The hidden files. Directories with names that start with '.'",
124             null,
125             new DocumentNameMatcher("HIDDEN_FILE", new Predicate<>() {
126                 @Override
127                 public boolean test(final DocumentName documentName) {
128                     File file = documentName.asFile();
129                     return file.isFile() && ExclusionUtils.isHidden(documentName.getShortName());
130                 }
131 
132                 @Override
133                 public String toString() {
134                     return "HIDDEN_FILE";
135                 }
136             }), null
137     ),
138     /**
139      * The files and directories created by an IDEA IDE based tool.
140      */
141     IDEA("The files and directories created by an IDEA IDE based tool.",
142             Arrays.asList("**/*.iml", "**/*.ipr", "**/*.iws", "**/.idea/**"), null, null),
143     /**
144      * The {@code .DS_Store} files on Mac computers.
145      */
146     MAC("The .DS_Store files on Mac computers.",
147             Collections.singletonList("**/.DS_Store"), null, null),
148     /**
149      * The files and directories created by Gradle build system based projects.
150      */
151     GRADLE("The files and directories created by Gradle build system based projects.",
152             Arrays.asList(
153                     "**/build/**",
154                     "**/.gradle/**",
155                     "**/.kotlin/**"
156                     ), null, null),
157     /**
158      * The files and directories created by Maven build system based project.
159      */
160     MAVEN("The files and directories created by Maven build system based project.",
161             Arrays.asList(
162                     "**/target/**", //
163                     "**/cobertura.ser", //
164                     "**/MANIFEST.MF", // a MANIFEST.MF file cannot contain comment lines. In other words: It is not possible, to include a license.
165                     "**/release.properties", //
166                     "**/.repository", // Used by Jenkins when a Maven job uses a private repository that is "Local to the workspace"
167                     "**/build.log", // RAT-160: until now maven-invoker-plugin runs create a build.log that is not part of a release
168                     "**/.mvn/**", // Project configuration since Maven 3.3.1 which contains maven.config, jvm.config, extensions.xml
169                     "**/pom.xml.releaseBackup"), null, null),
170     /**
171      * The files and directories created by a Mercurial source code control based tool.
172      */
173     MERCURIAL("The files and directories created by a Mercurial source code control based tool.",
174             Arrays.asList("**/.hg/**", "**/.hgignore"), null, HgIgnoreBuilder::new),
175     /**
176      * The set of miscellaneous files generally left by editors and the like.
177      */
178     MISC("The set of miscellaneous files generally left by editors and the like.",
179             Arrays.asList("**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*"),
180             null, null),
181     /**
182      * The files and directories created by an MKS source code control based tool.
183      */
184     MKS("The files and directories created by an MKS source code control based tool.",
185             Collections.singletonList("**/project.pj"), null, null),
186     /**
187      * The files and directories created by an RCS source code control based tool.
188      */
189     RCS("The files and directories created by a RCS source code control based tool.",
190             Collections.singletonList("**/RCS/**"), null, null),
191     /**
192      * The files and directories created by a SCCS source code control based tool.
193      */
194     SCCS("The files and directories created by a SCCS source code control based tool.",
195             Collections.singletonList("**/SCCS/**"), null, null),
196     /**
197      * The files and directories created by a Serena Dimensions V10 change control system based tool.
198      */
199     SERENA_DIMENSIONS_10("The files and directories created by a Serena Dimensions V10 change control system based tool.",
200             Collections.singletonList("**/.metadata/**"), null, null),
201     /**
202      * A standard collection of generally accepted patterns to ignore.
203      */
204     // see getCollections() for loading
205     STANDARD_PATTERNS("A standard collection of generally accepted patterns to ignore.", null, null, null),
206     /**
207      * A standard collection of SCMs.
208      */
209     // see getCollections() for loading
210     STANDARD_SCMS("A standard collection of SCMs", null, null, null),
211     /**
212      * The files and directories created by a Subversion source code control based tool.
213      */
214     SUBVERSION("The files and directories created by a Subversion source code control based tool.",
215             Collections.singletonList("**/.svn/**"), null, null),
216     /**
217      * The files and directories created by a Surround SCM source code control based tool.
218      */
219     SURROUND_SCM("The files and directories created by a Surround SCM source code control based tool.",
220             Collections.singletonList("**/.MySCMServerInfo"), null, null),
221     /**
222      * The files and directories created by a Visual Source Safe source code control based tool.
223      */
224     VSS("The files and directories created by a Visual Source Safe source code control based tool.",
225             Collections.singletonList("**/vssver.scc"), null, null);
226 
227     /** The collections of patterns to be excluded. May be empty.*/
228     private final Collection<String> patterns;
229     /** A document name matcher supplier to create a document name matcher. May be null */
230     private final DocumentNameMatcher staticDocumentNameMatcher;
231     /**
232      * Supplier for the AbstractFileProcessorBuilder. A Supplier is used instead of a direct
233      * instance because these builders contain mutable state ({@code levelBuilders}, and in the
234      * case of {@link HgIgnoreBuilder}, a mutable {@code state} field). Enum constants are
235      * singletons, so storing a shared builder instance would cause concurrent threads in a
236      * parallel Maven build to corrupt each other's state. The supplier creates a fresh builder
237      * for each invocation, ensuring thread safety.
238      */
239     private final Supplier<AbstractFileProcessorBuilder> fileProcessorBuilderSupplier;
240     /** The description of this collection */
241     private final String desc;
242 
243     StandardCollection(final String desc, final Collection<String> patterns, final DocumentNameMatcher documentNameMatcher,
244                        final Supplier<AbstractFileProcessorBuilder> fileProcessorBuilderSupplier) {
245         this.desc = desc;
246         this.patterns = patterns == null ? Collections.emptyList() : new HashSet<>(patterns);
247         this.staticDocumentNameMatcher = documentNameMatcher;
248         this.fileProcessorBuilderSupplier = fileProcessorBuilderSupplier;
249     }
250 
251     /**
252      * @return the description of the given collection.
253      */
254     public String desc() {
255         return desc;
256     }
257 
258     /**
259      * Handles aggregate StandardCollections (e.g. ALL) by generating the set of StandardCollection objects that
260      * comprise this StandardCollection.
261      * @return the set of StandardCollection objects that comprise this StandardCollection.
262      */
263     private Set<StandardCollection> getCollections() {
264         Set<StandardCollection> result = new HashSet<>();
265         switch (this) {
266             case ALL:
267                 for (StandardCollection sc : StandardCollection.values()) {
268                     if (sc != ALL) {
269                         result.add(sc);
270                     }
271                 }
272                 break;
273             case STANDARD_PATTERNS:
274                 result.addAll(Arrays.asList(MISC, CVS, RCS, SCCS, VSS, MKS, SUBVERSION, ARCH, BAZAAR, SURROUND_SCM, MAC,
275                         SERENA_DIMENSIONS_10, MERCURIAL, GIT, BITKEEPER, DARCS));
276                 break;
277             case STANDARD_SCMS:
278                 result.addAll(Arrays.asList(SUBVERSION, GIT, BAZAAR, MERCURIAL, CVS));
279                 break;
280 
281             default:
282                 result.add(this);
283         }
284         return result;
285     }
286 
287     /**
288      * Returns combined and deduped collection of patterns.
289      * @return the combined and deduped collection of patterns in the given collection.
290      */
291     public Set<String> patterns() {
292         Set<String> result = new HashSet<>();
293         getCollections().forEach(sc -> result.addAll(sc.patterns));
294         return result;
295     }
296 
297     /**
298      * Returns the fileProcessor if it exists.
299      *
300      * @return the fileProcessor if it exists, {@code null} otherwise.
301      */
302     public ExtendedIterator<AbstractFileProcessorBuilder> fileProcessorBuilder() {
303         List<AbstractFileProcessorBuilder> lst = new ArrayList<>();
304         for (StandardCollection sc : getCollections()) {
305             if (sc.fileProcessorBuilderSupplier != null) {
306                 lst.add(sc.fileProcessorBuilderSupplier.get());
307             }
308         }
309         return ExtendedIterator.create(lst.iterator());
310     }
311 
312     /**
313      * Returns the documentNameMatchSupplier if it exists.
314      *
315      * @return the documentNameMatchSupplier if it exists, {@code null} otherwise.
316      */
317     public DocumentNameMatcher staticDocumentNameMatcher() {
318         // account for cases where this has more than one supplier.
319         List<DocumentNameMatcher> lst = new ArrayList<>();
320         for (StandardCollection sc : getCollections()) {
321             if (sc.staticDocumentNameMatcher != null) {
322                 lst.add(sc.staticDocumentNameMatcher);
323             }
324         }
325         if (lst.isEmpty()) {
326             return null;
327         }
328         if (lst.size() == 1) {
329             return lst.get(0);
330         }
331 
332         return new DocumentNameMatcher(name() + " static DocumentNameMatchers",  DocumentNameMatcher.or(lst));
333     }
334 
335     /**
336      * Returns {@code true} if the collections has a document name match supplier.
337      *
338      * @return {@code true} if the collections has a document name match supplier.
339      */
340     public boolean hasStaticDocumentNameMatcher() {
341         // account for cases where this has more than one supplier.
342         for (StandardCollection sc : getCollections()) {
343             if (sc.staticDocumentNameMatcher != null) {
344                 return true;
345             }
346         }
347         return false;
348     }
349 }