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.anttasks;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.PrintWriter;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  import java.util.stream.Collectors;
30  
31  import org.apache.commons.io.filefilter.IOFileFilter;
32  import org.apache.commons.io.filefilter.OrFileFilter;
33  import org.apache.rat.ConfigurationException;
34  import org.apache.rat.ImplementationException;
35  import org.apache.rat.OptionCollection;
36  import org.apache.rat.ReportConfiguration;
37  import org.apache.rat.Reporter;
38  import org.apache.rat.license.LicenseSetFactory;
39  import org.apache.rat.utils.DefaultLog;
40  import org.apache.rat.utils.Log;
41  import org.apache.tools.ant.BuildException;
42  import org.apache.tools.ant.Project;
43  import org.apache.tools.ant.taskdefs.LogOutputStream;
44  import org.apache.tools.ant.types.EnumeratedAttribute;
45  import org.apache.tools.ant.types.Resource;
46  import org.apache.tools.ant.types.ResourceCollection;
47  import org.apache.tools.ant.types.resources.Union;
48  
49  /**
50   * A basic Ant task that generates a report on all files specified by the nested
51   * resource collection(s).
52   *
53   * <p>
54   * IHeaderMatcher(s) can be specified as nested elements as well.
55   * </p>
56   *
57   * <p>
58   * The attribute <code>format</code> defines the output format and can take the
59   * values
60   * <ul>
61   * <li>xml - Rat's native XML output.</li>
62   * <li>styled - transforms the XML output using the given stylesheet. The
63   * stylesheet attribute must be set as well if this attribute is used.</li>
64   * <li>plain - plain text using Rat's built-in stylesheet. This is the
65   * default.</li>
66   * </ul>
67   */
68  public class Report extends BaseAntTask {
69      /** The list of licenses */
70      private final List<License> licenses = new ArrayList<>();
71      /** The list of license families */
72      private final List<Family> families = new ArrayList<>();
73      /** the options that are deprecated.  TODO remove this. */
74      private final DeprecatedConfig deprecatedConfig = new DeprecatedConfig();
75      /**
76       * will hold any nested resource collection
77       */
78      private Union nestedResources;
79  
80      /**
81       * Collection of objects that support Ant specific deprecated options
82       */
83      private static class DeprecatedConfig {
84          /** The input file filter */
85          private IOFileFilter inputFileFilter;
86          /** the set of approved licence categories */
87          private final Set<String> approvedLicenseCategories = new HashSet<>();
88          /** the set of removed (unapproved) license categories */
89          private final Set<String> removedLicenseCategories = new HashSet<>();
90      }
91  
92      /**
93       * Constructor.
94       */
95      public Report() {
96          Logger log = new Logger();
97          DefaultLog.setInstance(log);
98      }
99  
100     /**
101      * Adds resources that will be checked.
102      * @param rc resource to check.
103      */
104     public void add(final ResourceCollection rc) {
105         if (nestedResources == null) {
106             nestedResources = new Union();
107         }
108         nestedResources.add(rc);
109     }
110 
111     /**
112      * Adds an input file filter.
113      * @param inputFileFilter The input file filter to add.
114      */
115     @Deprecated
116     public void setInputFileFilter(final IOFileFilter inputFileFilter) {
117         deprecatedConfig.inputFileFilter = inputFileFilter;
118     }
119 
120     /**
121      * Sets the report file.
122      * @param reportFile the report file.
123      * @deprecated use {@link #setOut(String)}
124      */
125     @Deprecated
126     public void setReportFile(final File reportFile) {
127         setOut(reportFile.getAbsolutePath());
128     }
129 
130     /**
131      * Adds an inline License definition to the system.
132      * @param license the license to add.
133      */
134     public void addLicense(final License license) {
135         licenses.add(license);
136     }
137 
138     /**
139      * Add an inline license family definition to the system.
140      * @param family the license family to add.
141      */
142     public void addFamily(final Family family) {
143         families.add(family);
144     }
145 
146     /**
147      * Adds a style sheet to the system.
148      * @param styleSheet
149      * @deprecated use {@link #setStylesheet(String)}
150      */
151     @Deprecated
152     public void addStylesheet(final Resource styleSheet) {
153         setStylesheet(styleSheet.getName());
154     }
155 
156     /**
157      * Adds a given style sheet to the report.
158      * @param styleSheet style sheet to use in this report.
159      * @deprecated use {@link #setStylesheet(String)}
160      */
161     @Deprecated
162     public void addStyleSheet(final Resource styleSheet) {
163         setStylesheet(styleSheet.getName());
164     }
165 
166     /**
167      * Sets a stylesheet for the report.
168      * @param styleReport
169      * @deprecated use {@link #setXml(boolean)}.  Note reversal of boolean value
170      */
171     @Deprecated
172     public void setStyleReport(final boolean styleReport) {
173         setXml(!styleReport);
174     }
175 
176     /**
177      * Determines if the output should be styled.
178      * @param style
179      * @deprecated use {@link #setStylesheet(String)} or {@link #setXml(boolean)}
180      */
181     @Deprecated
182     public void setFormat(final String style) {
183         setStyleReport("styled".equalsIgnoreCase(style));
184     }
185 
186     /**
187      * Adds as a file containing the definitions of licenses to the system.
188      * @param fileName the file to add.
189      * @deprecated use licenses child element.
190      */
191     public void setLicenses(final File fileName) {
192         try {
193             createLicenses().addText(fileName.getCanonicalPath());
194         } catch (IOException e) {
195             throw new BuildException("Unable to read license file " + fileName, e);
196         }
197     }
198 
199     /**
200      * Specifies whether to add the default list of license matchers.
201      * @param useDefaultLicenses if {@code true} use the default licenses.
202      * @deprecated  use noDefaultLicenses attribute
203      */
204     @Deprecated
205     public void setUseDefaultLicenses(final boolean useDefaultLicenses) {
206         setNoDefaultLicenses(!useDefaultLicenses);
207     }
208 
209     /**
210      * Adds a family category to the list of approved licenses.
211      * @param familyCategory the category to add.
212      * @deprecated use addApprovedLicense child element.
213      */
214     @Deprecated
215     public void setAddApprovedLicense(final String familyCategory) {
216         deprecatedConfig.approvedLicenseCategories.add(familyCategory);
217     }
218 
219     /**
220      * Adds a family category to the list of approved licenses.
221      * @param familyCategory the category to add
222      */
223     public void addAddApprovedLicense(final String familyCategory) {
224         deprecatedConfig.approvedLicenseCategories.add(familyCategory);
225     }
226 
227     /**
228      * Removes a family category to the list of approved licenses.
229      * @param familyCategory the category to add.
230      * @deprecated use removeApprovedLicense child element}
231      */
232     @Deprecated
233     public void setRemoveApprovedLicense(final String familyCategory) {
234         deprecatedConfig.removedLicenseCategories.add(familyCategory);
235     }
236 
237     /**
238      * Removes a family category to the list of approved licenses.
239      * @param familyCategory the category to add.
240      */
241     public void addRemoveApprovedLicense(final String familyCategory) {
242         deprecatedConfig.removedLicenseCategories.add(familyCategory);
243     }
244 
245     /**
246      * Removes a family category to the list of approved licenses.
247      * @param familyCategory the category to add.
248      * @deprecated use removeApprovedLicense element
249      */
250     @Deprecated
251     public void setRemoveApprovedLicense(final String[] familyCategory) {
252         deprecatedConfig.removedLicenseCategories.addAll(Arrays.asList(familyCategory));
253     }
254 
255     /**
256      * Removes a family category to the list of approved licenses.
257      * @param familyCategory the category to add.
258      */
259     public void addRemoveApprovedLicense(final String[] familyCategory) {
260         deprecatedConfig.removedLicenseCategories.addAll(Arrays.asList(familyCategory));
261     }
262     /**
263      * Sets the copyright message
264      * @param copyrightMessage the copyright message
265      * @deprecated use copyright attribute
266      */
267     @Deprecated
268     public void setCopyrightMessage(final String copyrightMessage) {
269        setCopyright(copyrightMessage);
270     }
271 
272     /**
273      * Determines if license headers should be added.
274      * @param setting the setting.
275      * @deprecated use addLicense and force attributes
276      */
277     @Deprecated
278     public void setAddLicenseHeaders(final AddLicenseHeaders setting) {
279         switch (setting.getNative()) {
280             case TRUE:
281                 setAddLicense(true);
282                 break;
283             case FALSE:
284                 setAddLicense(false);
285                 break;
286             case FORCED:
287                 setAddLicense(true);
288                 setForce(true);
289                 break;
290         }
291     }
292 
293     /**
294      * Adds definition information
295      * @param fileName the file to add
296      * @deprecated Use {@link #addLicense}
297      */
298     @Deprecated
299     public void setAddDefaultDefinitions(final File fileName) {
300         try {
301             Licenses lic = createLicenses();
302             lic.addText(fileName.getCanonicalPath());
303         } catch (IOException e) {
304             throw new BuildException("Unable to read license file " + fileName, e);
305         }
306     }
307 
308     /**
309      * Creates the ReportConfiguration from the ant options.
310      * @return the ReportConfiguration.
311      */
312     public ReportConfiguration getConfiguration() {
313         try {
314             final ReportConfiguration configuration = OptionCollection.parseCommands(args().toArray(new String[0]),
315                     o -> DefaultLog.getInstance().warn("Help option not supported"),
316                     true);
317             if (!args().contains(asKey(OptionCollection.OUT))) {
318                 configuration.setOut(() -> new LogOutputStream(this, Project.MSG_INFO));
319             }
320             configuration.setReportable(new ResourceCollectionContainer(nestedResources));
321             configuration.addApprovedLicenseCategories(deprecatedConfig.approvedLicenseCategories);
322             configuration.removeApprovedLicenseCategories(deprecatedConfig.removedLicenseCategories);
323             if (deprecatedConfig.inputFileFilter != null) {
324                 if (configuration.getFilesToIgnore() != null) {
325                     configuration.setFilesToIgnore(new OrFileFilter(configuration.getFilesToIgnore(), deprecatedConfig.inputFileFilter));
326                 } else {
327                     configuration.setFilesToIgnore(deprecatedConfig.inputFileFilter);
328                 }
329             }
330             families.stream().map(Family::build).forEach(configuration::addFamily);
331             licenses.stream().map(License::asBuilder)
332                     .forEach(l -> configuration.addApprovedLicenseCategory(configuration.addLicense(l).getLicenseFamily()));
333             return configuration;
334         } catch (IOException | ImplementationException e) {
335             throw new BuildException(e.getMessage(), e);
336         }
337     }
338 
339     /**
340      * Generates the report.
341      */
342     @Override
343     public void execute() {
344         try {
345             Reporter r = new Reporter(validate(getConfiguration()));
346             r.output(null, () -> new ReportConfiguration.NoCloseOutputStream(System.out));
347             r.output();
348         } catch (BuildException e) {
349             throw e;
350         } catch (Exception ioex) {
351             throw new BuildException(ioex);
352         }
353     }
354 
355     /**
356      * validates the task's configuration.
357      */
358     protected ReportConfiguration validate(final ReportConfiguration cfg) {
359         try {
360             cfg.validate(s -> log(s, Project.MSG_WARN));
361         } catch (ConfigurationException e) {
362             throw new BuildException(e.getMessage(), e.getCause());
363         }
364         if (nestedResources == null) {
365             throw new BuildException("You must specify at least one file to create the report for.");
366         }
367         return cfg;
368     }
369 
370     /**
371      * Type for the addLicenseHeaders attribute.
372      * @deprecated No longer required=, use stylesheet or xml attributes.
373      */
374     @Deprecated
375     public static class AddLicenseHeaders extends EnumeratedAttribute {
376         /** add license headers and create *.new file */
377         static final String TRUE = "true";
378         /** do not add license headers */
379         static final String FALSE = "false";
380         /** add license headers and overwrite existing files */
381         static final String FORCED = "forced";
382 
383         public AddLicenseHeaders() {
384         }
385 
386         public AddLicenseHeaders(final String s) {
387             setValue(s);
388         }
389 
390         @Override
391         public String[] getValues() {
392             return new String[] { TRUE, FALSE, FORCED };
393         }
394 
395         public org.apache.rat.config.AddLicenseHeaders getNative() {
396             return org.apache.rat.config.AddLicenseHeaders.valueOf(getValue().toUpperCase());
397         }
398     }
399 
400     /**
401      * Type for the addLicenseHeaders attribute.
402      * @deprecated use listLicenses or listFamilies attributes.
403      */
404     @Deprecated
405     public static class ApprovalFilter extends EnumeratedAttribute {
406 
407         public ApprovalFilter() {
408         }
409 
410         public ApprovalFilter(final String s) {
411             setValue(s);
412         }
413 
414         @Override
415         public String[] getValues() {
416             return Arrays.stream(LicenseSetFactory.LicenseFilter.values()).map(LicenseSetFactory.LicenseFilter::name)
417                     .collect(Collectors.toList()).toArray(new String[LicenseSetFactory.LicenseFilter.values().length]);
418         }
419 
420         public LicenseSetFactory.LicenseFilter internalFilter() {
421             return LicenseSetFactory.LicenseFilter.valueOf(getValue());
422         }
423     }
424 
425     /**
426      * A facade for the Logger provided by Ant.
427      */
428     private class Logger implements Log {
429 
430         private void write(final int level, final String msg) {
431             try (PrintWriter pw = new PrintWriter(new LogOutputStream(Report.this, level))) {
432                pw.write(msg);
433             }
434         }
435 
436         @Override
437         public void log(final Level level, final String msg) {
438             switch (level) {
439             case DEBUG:
440                 write(Project.MSG_DEBUG, msg);
441                 break;
442             case INFO:
443                 write(Project.MSG_INFO, msg);
444                 break;
445             case WARN:
446                 write(Project.MSG_WARN, msg);
447                 break;
448             case ERROR:
449                 write(Project.MSG_ERR, msg);
450                 break;
451             case OFF:
452             default:
453                 break;
454             }
455         }
456     }
457 }