1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat;
20
21 import org.apache.commons.cli.CommandLine;
22 import org.apache.commons.cli.HelpFormatter;
23 import org.apache.commons.cli.Option;
24 import org.apache.commons.cli.OptionBuilder;
25 import org.apache.commons.cli.OptionGroup;
26 import org.apache.commons.cli.Options;
27 import org.apache.commons.cli.ParseException;
28 import org.apache.commons.cli.PosixParser;
29 import org.apache.commons.io.FileUtils;
30 import org.apache.commons.io.filefilter.NotFileFilter;
31 import org.apache.commons.io.filefilter.OrFileFilter;
32 import org.apache.commons.io.filefilter.RegexFileFilter;
33 import org.apache.commons.io.filefilter.WildcardFileFilter;
34 import org.apache.rat.api.RatException;
35 import org.apache.rat.report.IReportable;
36 import org.apache.rat.report.RatReport;
37 import org.apache.rat.report.claim.ClaimStatistic;
38 import org.apache.rat.report.xml.XmlReportFactory;
39 import org.apache.rat.report.xml.writer.IXmlWriter;
40 import org.apache.rat.report.xml.writer.impl.base.XmlWriter;
41 import org.apache.rat.walker.ArchiveWalker;
42 import org.apache.rat.walker.DirectoryWalker;
43
44 import javax.xml.transform.TransformerConfigurationException;
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.FileNotFoundException;
48 import java.io.FilenameFilter;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.io.OutputStreamWriter;
52 import java.io.PipedReader;
53 import java.io.PipedWriter;
54 import java.io.PrintStream;
55 import java.io.Writer;
56 import java.util.List;
57
58
59 public class Report {
60 private static final char EXCLUDE_CLI = 'e';
61 private static final char EXCLUDE_FILE_CLI = 'E';
62 private static final char STYLESHEET_CLI = 's';
63
64
65 public static final void main(String args[]) throws Exception {
66 final ReportConfiguration configuration = new ReportConfiguration();
67 configuration.setHeaderMatcher(Defaults.createDefaultMatcher());
68 configuration.setApproveDefaultLicenses(true);
69 Options opts = buildOptions();
70
71 PosixParser parser = new PosixParser();
72 CommandLine cl = null;
73 try {
74 cl = parser.parse(opts, args);
75 } catch (ParseException e) {
76 System.err.println("Please use the \"--help\" option to see a list of valid commands and options");
77 System.exit(1);
78 return;
79 }
80
81 if (cl.hasOption('h')) {
82 printUsage(opts);
83 }
84
85 args = cl.getArgs();
86 if (args == null || args.length != 1) {
87 printUsage(opts);
88 } else {
89 Report report = new Report(args[0]);
90
91 if (cl.hasOption('a') || cl.hasOption('A')) {
92 configuration.setAddingLicenses(true);
93 configuration.setAddingLicensesForced(cl.hasOption('f'));
94 configuration.setCopyrightMessage(cl.getOptionValue("c"));
95 }
96
97 if (cl.hasOption(EXCLUDE_CLI)) {
98 String[] excludes = cl.getOptionValues(EXCLUDE_CLI);
99 if (excludes != null) {
100 final FilenameFilter filter = new NotFileFilter(new WildcardFileFilter(excludes));
101 report.setInputFileFilter(filter);
102 }
103 } else if (cl.hasOption(EXCLUDE_FILE_CLI)) {
104 String excludeFileName = cl.getOptionValue(EXCLUDE_FILE_CLI);
105 if (excludeFileName != null) {
106 List<String> excludes = FileUtils.readLines(new File(excludeFileName));
107 final OrFileFilter orFilter = new OrFileFilter();
108 for (String exclude : excludes) {
109 orFilter.addFileFilter(new RegexFileFilter(exclude));
110 }
111 final FilenameFilter filter = new NotFileFilter(orFilter);
112 report.setInputFileFilter(filter);
113 }
114 }
115 if (cl.hasOption('x')) {
116 report.report(System.out, configuration);
117 } else {
118 if (!cl.hasOption(STYLESHEET_CLI)) {
119 report.styleReport(System.out, configuration);
120 } else {
121 String[] style = cl.getOptionValues(STYLESHEET_CLI);
122 if (style.length != 1) {
123 System.err.println("please specify a single stylesheet");
124 System.exit(1);
125 }
126 try {
127 report(System.out,
128 report.getDirectory(System.out),
129 new FileInputStream(style[0]),
130 configuration);
131 } catch (FileNotFoundException fnfe) {
132 System.err.println("stylesheet " + style[0]
133 + " doesn't exist");
134 System.exit(1);
135 }
136 }
137 }
138 }
139 }
140
141 private static Options buildOptions() {
142 Options opts = new Options();
143
144 Option help = new Option("h", "help", false,
145 "Print help for the Rat command line interface and exit");
146 opts.addOption(help);
147
148 OptionGroup addLicenseGroup = new OptionGroup();
149 String addLicenseDesc = "Add the default license header to any file with an unknown license that is not in the exclusion list. " +
150 "By default new files will be created with the license header, " +
151 "to force the modification of existing files use the --force option.";
152
153
154 Option addLicence = new Option(
155 "a",
156 "addLicence",
157 false,
158 addLicenseDesc);
159 addLicenseGroup.addOption(addLicence);
160 Option addLicense = new Option(
161 "A",
162 "addLicense",
163 false,
164 addLicenseDesc);
165 addLicenseGroup.addOption(addLicense);
166 opts.addOptionGroup(addLicenseGroup);
167
168 Option write = new Option(
169 "f",
170 "force",
171 false,
172 "Forces any changes in files to be written directly to the source files (i.e. new files are not created)");
173 opts.addOption(write);
174
175 Option copyright = new Option(
176 "c",
177 "copyright",
178 true,
179 "The copyright message to use in the license headers, usually in the form of \"Copyright 2008 Foo\"");
180 opts.addOption(copyright);
181
182 @SuppressWarnings("static-access")
183 final Option exclude = OptionBuilder
184 .withArgName("expression")
185 .withLongOpt("exclude")
186 .hasArgs()
187 .withDescription("Excludes files matching wildcard <expression>. " +
188 "Note that --dir is required when using this parameter. " +
189 "Allows multiple arguments.")
190 .create(EXCLUDE_CLI);
191 opts.addOption(exclude);
192
193 @SuppressWarnings("static-access")
194 final Option excludeFile = OptionBuilder
195 .withArgName("fileName")
196 .withLongOpt("exclude-file")
197 .hasArgs()
198 .withDescription("Excludes files matching regular expression in <file> " +
199 "Note that --dir is required when using this parameter. ")
200 .create(EXCLUDE_FILE_CLI);
201 opts.addOption(excludeFile);
202
203 Option dir = new Option(
204 "d",
205 "dir",
206 false,
207 "Used to indicate source when using --exclude");
208 opts.addOption(dir);
209
210 OptionGroup outputType = new OptionGroup();
211
212 Option xml = new Option(
213 "x",
214 "xml",
215 false,
216 "Output the report in raw XML format. Not compatible with -s");
217 outputType.addOption(xml);
218
219 Option xslt = new Option(String.valueOf(STYLESHEET_CLI),
220 "stylesheet",
221 true,
222 "XSLT stylesheet to use when creating the"
223 + " report. Not compatible with -x");
224 outputType.addOption(xslt);
225 opts.addOptionGroup(outputType);
226
227 return opts;
228 }
229
230 private static final void printUsage(Options opts) {
231 HelpFormatter f = new HelpFormatter();
232 String header = "Options";
233
234 StringBuilder footer = new StringBuilder("\nNOTE:\n");
235 footer.append("Rat is really little more than a grep ATM\n");
236 footer.append("Rat is also rather memory hungry ATM\n");
237 footer.append("Rat is very basic ATM\n");
238 footer.append("Rat highlights possible issues\n");
239 footer.append("Rat reports require interpretation\n");
240 footer.append("Rat often requires some tuning before it runs well against a project\n");
241 footer.append("Rat relies on heuristics: it may miss issues\n");
242
243 f.printHelp("java rat.report [options] [DIR|TARBALL]",
244 header, opts, footer.toString(), false);
245 System.exit(0);
246 }
247
248 private final String baseDirectory;
249
250 private FilenameFilter inputFileFilter = null;
251
252 private Report(String baseDirectory) {
253 this.baseDirectory = baseDirectory;
254 }
255
256
257
258
259
260
261 public FilenameFilter getInputFileFilter() {
262 return inputFileFilter;
263 }
264
265
266
267
268
269
270 public void setInputFileFilter(FilenameFilter inputFileFilter) {
271 this.inputFileFilter = inputFileFilter;
272 }
273
274
275
276
277
278
279
280 @Deprecated
281 public ClaimStatistic report(PrintStream out) throws Exception {
282 final ReportConfiguration configuration = new ReportConfiguration();
283 configuration.setHeaderMatcher(Defaults.createDefaultMatcher());
284 configuration.setApproveDefaultLicenses(true);
285 return report(out, configuration);
286 }
287
288
289
290
291
292
293
294
295 public ClaimStatistic report(PrintStream out,
296 ReportConfiguration configuration)
297 throws Exception {
298 final IReportable base = getDirectory(out);
299 if (base != null) {
300 return report(base, new OutputStreamWriter(out), configuration);
301 }
302 return null;
303 }
304
305 private IReportable getDirectory(PrintStream out) {
306 File base = new File(baseDirectory);
307 if (!base.exists()) {
308 out.print("ERROR: ");
309 out.print(baseDirectory);
310 out.print(" does not exist.\n");
311 return null;
312 }
313
314 if (base.isDirectory()) {
315 return new DirectoryWalker(base, inputFileFilter);
316 }
317
318 try {
319 return new ArchiveWalker(base, inputFileFilter);
320 } catch (IOException ex) {
321 out.print("ERROR: ");
322 out.print(baseDirectory);
323 out.print(" is not valid gzip data.\n");
324 return null;
325 }
326 }
327
328
329
330
331
332
333
334
335
336 @Deprecated
337 public void styleReport(PrintStream out) throws Exception {
338 final ReportConfiguration configuration = new ReportConfiguration();
339 configuration.setHeaderMatcher(Defaults.createDefaultMatcher());
340 configuration.setApproveDefaultLicenses(true);
341 styleReport(out, configuration);
342 }
343
344
345
346
347
348
349
350
351
352
353 public void styleReport(PrintStream out,
354 ReportConfiguration configuration)
355 throws Exception {
356 final IReportable base = getDirectory(out);
357 if (base != null) {
358 InputStream style = Defaults.getDefaultStyleSheet();
359 report(out, base, style, configuration);
360 }
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375 public static void report(PrintStream out, IReportable base, final InputStream style,
376 ReportConfiguration pConfiguration)
377 throws IOException, TransformerConfigurationException, InterruptedException, RatException {
378 report(new OutputStreamWriter(out), base, style, pConfiguration);
379 }
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394 public static ClaimStatistic report(Writer out, IReportable base, final InputStream style,
395 ReportConfiguration pConfiguration)
396 throws IOException, TransformerConfigurationException, InterruptedException, RatException {
397 PipedReader reader = new PipedReader();
398 PipedWriter writer = new PipedWriter(reader);
399 ReportTransformer transformer = new ReportTransformer(out, style, reader);
400 Thread transformerThread = new Thread(transformer);
401 transformerThread.start();
402 final ClaimStatistic statistic = report(base, writer, pConfiguration);
403 writer.flush();
404 writer.close();
405 transformerThread.join();
406 return statistic;
407 }
408
409
410
411
412
413
414
415
416
417 public static ClaimStatistic report(final IReportable container, final Writer out,
418 ReportConfiguration pConfiguration) throws IOException, RatException {
419 IXmlWriter writer = new XmlWriter(out);
420 final ClaimStatistic statistic = new ClaimStatistic();
421 RatReport report = XmlReportFactory.createStandardReport(writer, statistic, pConfiguration);
422 report.startReport();
423 container.run(report);
424 report.endReport();
425 writer.closeDocument();
426 return statistic;
427 }
428 }