1 package org.apache.rat.mp;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static org.apache.rat.mp.util.ConfigurationHelper.newInstance;
23 import static org.apache.rat.mp.util.ExclusionHelper.addEclipseDefaults;
24 import static org.apache.rat.mp.util.ExclusionHelper.addIdeaDefaults;
25 import static org.apache.rat.mp.util.ExclusionHelper.addMavenDefaults;
26 import static org.apache.rat.mp.util.ExclusionHelper.addPlexusAndScmDefaults;
27
28 import java.io.BufferedInputStream;
29 import java.io.BufferedReader;
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.InputStreamReader;
35 import java.io.PrintWriter;
36 import java.io.Reader;
37 import java.io.StringWriter;
38 import java.io.Writer;
39 import java.lang.reflect.UndeclaredThrowableException;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Set;
46
47 import javax.xml.transform.TransformerConfigurationException;
48
49
50 import org.apache.commons.io.IOUtils;
51 import org.apache.maven.plugin.AbstractMojo;
52 import org.apache.maven.plugin.MojoExecutionException;
53 import org.apache.maven.plugin.MojoFailureException;
54 import org.apache.maven.plugins.annotations.Parameter;
55 import org.apache.maven.project.MavenProject;
56 import org.apache.rat.Defaults;
57 import org.apache.rat.Report;
58 import org.apache.rat.ReportConfiguration;
59 import org.apache.rat.analysis.IHeaderMatcher;
60 import org.apache.rat.analysis.util.HeaderMatcherMultiplexer;
61 import org.apache.rat.api.RatException;
62 import org.apache.rat.config.SourceCodeManagementSystems;
63 import org.apache.rat.license.ILicenseFamily;
64 import org.apache.rat.mp.util.ScmIgnoreParser;
65 import org.apache.rat.report.IReportable;
66 import org.apache.rat.report.claim.ClaimStatistic;
67 import org.codehaus.plexus.util.DirectoryScanner;
68
69
70
71
72 public abstract class AbstractRatMojo extends AbstractMojo {
73
74
75
76
77 @Parameter(property = "rat.basedir", defaultValue = "${basedir}", required = true)
78 private File basedir;
79
80
81
82
83
84
85
86 @Deprecated
87 @Parameter
88 private HeaderMatcherSpecification[] licenseMatchers;
89
90
91
92
93
94
95
96
97 @Parameter
98 private IHeaderMatcher[] licenses;
99
100
101
102
103
104
105 @Deprecated
106 private LicenseFamilySpecification[] licenseFamilyNames;
107
108
109
110
111
112
113 @Parameter
114 private ILicenseFamily[] licenseFamilies;
115
116
117
118
119 @Parameter(property = "rat.addDefaultLicenseMatchers", defaultValue = "true")
120 private boolean addDefaultLicenseMatchers;
121
122
123
124
125
126 @Parameter
127 private String[] includes;
128
129
130
131
132
133 @Parameter(property="rat.includesFile")
134 private String includesFile;
135
136
137
138
139
140 @Parameter(property="rat.includesFileCharset", defaultValue="${project.build.sourceEncoding}")
141 private String includesFileCharset;
142
143
144
145
146
147 @Parameter
148 private String[] excludes;
149
150
151
152
153
154
155 @Parameter(property="rat.excludesFile")
156 private String excludesFile;
157
158
159
160
161
162 @Parameter(property="rat.excludesFileCharset", defaultValue="${project.build.sourceEncoding}")
163 private String excludesFileCharset;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179 @Parameter(property = "rat.useDefaultExcludes", defaultValue = "true")
180 private boolean useDefaultExcludes;
181
182
183
184
185
186
187
188 @Parameter(property = "rat.useMavenDefaultExcludes", defaultValue = "true")
189 private boolean useMavenDefaultExcludes;
190
191
192
193
194
195
196
197 @Parameter(property = "rat.parseSCMIgnoresAsExcludes", defaultValue = "true")
198 private boolean parseSCMIgnoresAsExcludes;
199
200
201
202
203
204
205
206
207 @Parameter(property = "rat.useEclipseDefaultExcludes", defaultValue = "true")
208 private boolean useEclipseDefaultExcludes;
209
210
211
212
213
214
215
216 @Parameter(property = "rat.useIdeaDefaultExcludes", defaultValue = "true")
217 private boolean useIdeaDefaultExcludes;
218
219
220
221
222
223 @Parameter(property = "rat.excludeSubprojects", defaultValue = "true")
224 private boolean excludeSubProjects;
225
226
227
228
229
230
231 @Parameter(property = "rat.skip", defaultValue = "false")
232 protected boolean skip;
233
234
235
236
237 @Parameter(defaultValue = "${project}", required = true, readonly = true)
238 private MavenProject project;
239
240
241
242
243 protected MavenProject getProject() {
244 return project;
245 }
246
247
248
249
250
251
252
253
254 private List<IHeaderMatcher> mergeLicenseMatchers()
255 throws MojoFailureException, MojoExecutionException {
256 List<IHeaderMatcher> matchers = new ArrayList<IHeaderMatcher>();
257
258 if (licenses != null) {
259 matchers.addAll(Arrays.asList(licenses));
260 getLog().info("Added " + licenses.length + " additional default licenses.");
261 }
262
263 if (licenseMatchers != null) {
264 for (final HeaderMatcherSpecification spec : licenseMatchers) {
265 matchers.add(newInstance(IHeaderMatcher.class, spec.getClassName()));
266 }
267 }
268
269 if (addDefaultLicenseMatchers) {
270 getLog().info("Enabled default license matchers.");
271 matchers.addAll(Defaults.DEFAULT_MATCHERS);
272 }
273 logLicenseMatchers(matchers);
274
275 return matchers;
276 }
277
278 private void logLicenseMatchers(List<IHeaderMatcher> matchers) {
279 if (getLog().isDebugEnabled()) {
280 getLog().debug("The following license matchers are activated:");
281 for (IHeaderMatcher matcher : matchers) {
282 getLog().debug("* " + matcher.toString());
283 }
284 }
285
286 }
287
288
289
290
291
292
293
294 protected IReportable getResources() throws MojoExecutionException {
295 final DirectoryScanner ds = new DirectoryScanner();
296 ds.setBasedir(basedir);
297 setExcludes(ds);
298 setIncludes(ds);
299 ds.scan();
300 whenDebuggingLogExcludedFiles(ds);
301 final String[] files = ds.getIncludedFiles();
302 logAboutIncludedFiles(files);
303 try {
304 return new FilesReportable(basedir, files);
305 } catch (final IOException e) {
306 throw new UndeclaredThrowableException(e);
307 }
308 }
309
310 private void logAboutIncludedFiles(final String[] files) {
311 if (files.length == 0) {
312 getLog().warn("No resources included.");
313 } else {
314 getLog().info(
315 files.length
316 + " resources included (use -debug for more details)");
317 if (getLog().isDebugEnabled()) {
318 for (final String resource : files) {
319 getLog().debug(" - included " + resource);
320 }
321 }
322 }
323 }
324
325 private void whenDebuggingLogExcludedFiles(final DirectoryScanner ds) {
326 if (getLog().isDebugEnabled()) {
327 final String[] excludedFiles = ds.getExcludedFiles();
328 if (excludedFiles.length == 0) {
329 getLog().debug("No excluded resources.");
330 } else {
331 getLog().debug(
332 "Excluded " + excludedFiles.length + " resources:");
333 for (final String resource : excludedFiles) {
334 getLog().debug(" - excluded " + resource);
335 }
336 }
337 }
338 }
339
340 private void setIncludes(DirectoryScanner ds) throws MojoExecutionException {
341 if ((includes != null && includes.length > 0) || includesFile != null) {
342 final List<String> includeList = new ArrayList<String>();
343 if (includes != null) {
344 includeList.addAll(Arrays.asList(includes));
345 }
346 if (includesFile != null) {
347 final String charset = includesFileCharset == null ? "UTF8" : includesFileCharset;
348 final File f = new File(includesFile);
349 if (!f.isFile()) {
350 getLog().error("IncludesFile not found: " + f.getAbsolutePath());
351 } else {
352 getLog().info("Includes loaded from file " + includesFile + ", using character set " + charset);
353 }
354 includeList.addAll(getPatternsFromFile(f, charset));
355 }
356 ds.setIncludes(includeList.toArray(new String[includeList.size()]));
357 }
358 }
359
360 private List<String> getPatternsFromFile(File pFile, String pCharset) throws MojoExecutionException {
361 InputStream is = null;
362 BufferedInputStream bis = null;
363 Reader r = null;
364 BufferedReader br = null;
365 Throwable th = null;
366 final List<String> patterns = new ArrayList<String>();
367 try {
368 is = new FileInputStream(pFile);
369 bis = new BufferedInputStream(is);
370 r = new InputStreamReader(bis, pCharset);
371 br = new BufferedReader(r);
372 for (;;) {
373 final String s = br.readLine();
374 if (s == null) {
375 break;
376 }
377 patterns.add(s);
378 }
379 br.close();
380 br = null;
381 r.close();
382 r = null;
383 bis.close();
384 bis = null;
385 is.close();
386 is = null;
387 } catch (Throwable t) {
388 th = t;
389 } finally {
390 if (br != null) { try { br.close(); } catch (Throwable t) { if (th == null) { th = t; } } }
391 if (r != null) { try { r.close(); } catch (Throwable t) { if (th == null) { th = t; } } }
392 if (bis != null) { try { bis.close(); } catch (Throwable t) { if (th == null) { th = t; } } }
393 if (is != null) { try { is.close(); } catch (Throwable t) { if (th == null) { th = t; } } }
394 }
395 if (th != null) {
396 if (th instanceof RuntimeException) { throw (RuntimeException) th; }
397 if (th instanceof Error) { throw (Error) th; }
398 throw new MojoExecutionException(th.getMessage(), th);
399 }
400 return patterns;
401 }
402
403 private void setExcludes(DirectoryScanner ds) throws MojoExecutionException {
404 final List<String> excludeList = mergeDefaultExclusions();
405 if (excludes == null || excludes.length == 0) {
406 getLog().info("No excludes explicitly specified.");
407 } else {
408 for (final String exclude : excludes) {
409 getLog().info("Exclude: " + exclude);
410 }
411 }
412 if (excludes != null) {
413 Collections.addAll(excludeList, excludes);
414 }
415 if (!excludeList.isEmpty()) {
416 final String[] allExcludes = excludeList.toArray(new String[excludeList
417 .size()]);
418 ds.setExcludes(allExcludes);
419 }
420 }
421
422 private List<String> mergeDefaultExclusions() throws MojoExecutionException {
423 final Set<String> results = new HashSet<String>();
424
425 addPlexusAndScmDefaults(getLog(), useDefaultExcludes, results);
426 addMavenDefaults(getLog(), useMavenDefaultExcludes, results);
427 addEclipseDefaults(getLog(), useEclipseDefaultExcludes, results);
428 addIdeaDefaults(getLog(), useIdeaDefaultExcludes, results);
429
430 if (parseSCMIgnoresAsExcludes) {
431 getLog().info("Will parse SCM ignores for exclusions...");
432 results.addAll(ScmIgnoreParser.getExclusionsFromSCM(getLog(), project.getBasedir()));
433 getLog().info("Finished adding exclusions from SCM ignore files.");
434 }
435
436 if (excludeSubProjects && project != null
437 && project.getModules() != null) {
438 for (final Object o : project.getModules()) {
439 final String moduleSubPath = (String) o;
440 results.add(moduleSubPath + "/**/*");
441 }
442 }
443
444 getLog().debug("Finished creating list of implicit excludes.");
445 if (results.isEmpty()) {
446 getLog().info("No excludes implicitly specified.");
447 } else {
448 getLog().info(
449 results.size()
450 + " implicit excludes (use -debug for more details).");
451 for (final String exclude : results) {
452 getLog().debug("Implicit exclude: " + exclude);
453 }
454 }
455 if (excludesFile != null) {
456 final File f = new File(excludesFile);
457 if (!f.isFile()) {
458 getLog().error("Excludes file not found: " + f.getAbsolutePath());
459 }
460 if (!f.canRead()) {
461 getLog().error("Excludes file not readable: " + f.getAbsolutePath());
462 }
463 final String charset = excludesFileCharset == null ? "UTF8" : excludesFileCharset;
464 getLog().info("Loading excludes from file " + f + ", using character set " + charset);
465 results.addAll(getPatternsFromFile(f, charset));
466 }
467
468 return new ArrayList<String>(results);
469 }
470
471
472
473
474
475
476
477
478
479 protected String createReport(InputStream styleSheet)
480 throws MojoExecutionException, MojoFailureException {
481 StringWriter sw = new StringWriter();
482 PrintWriter pw = null;
483 try {
484 pw = new PrintWriter(sw);
485 createReport(new PrintWriter(sw), styleSheet);
486 final String result = sw.toString();
487 pw.close();
488 pw = null;
489 sw.close();
490 sw = null;
491 return result;
492 } catch (IOException e) {
493 throw new MojoExecutionException(e.getMessage(), e);
494 } finally {
495 IOUtils.closeQuietly(pw);
496 IOUtils.closeQuietly(sw);
497 }
498 }
499
500
501
502
503
504
505
506
507
508
509 protected ClaimStatistic createReport(Writer out, InputStream style)
510 throws MojoExecutionException, MojoFailureException {
511 final ReportConfiguration configuration = getConfiguration();
512 try {
513 if (style != null) {
514 return Report.report(out, getResources(), style, configuration);
515 } else {
516 return Report.report(getResources(), out, configuration);
517 }
518 } catch (final TransformerConfigurationException e) {
519 throw new MojoExecutionException(e.getMessage(), e);
520 } catch (final IOException e) {
521 throw new MojoExecutionException(e.getMessage(), e);
522 } catch (final InterruptedException e) {
523 throw new MojoExecutionException(e.getMessage(), e);
524 } catch (final RatException e) {
525 throw new MojoExecutionException(e.getMessage(), e);
526 }
527 }
528
529 protected ReportConfiguration getConfiguration()
530 throws MojoFailureException, MojoExecutionException {
531 final ReportConfiguration configuration = new ReportConfiguration();
532 configuration.setHeaderMatcher(new HeaderMatcherMultiplexer(
533 mergeLicenseMatchers()));
534 configuration.setApprovedLicenseNames(mergeApprovedLicenseNames());
535 configuration.setApproveDefaultLicenses(addDefaultLicenseMatchers);
536 return configuration;
537 }
538
539 private List<ILicenseFamily> mergeApprovedLicenseNames()
540 throws MojoExecutionException, MojoFailureException {
541 final List<ILicenseFamily> list = new ArrayList<ILicenseFamily>();
542 if (licenseFamilies != null) {
543 getLog().info("Added " + licenseFamilies.length + " custom approved licenses.");
544 list.addAll(Arrays.asList(licenseFamilies));
545 }
546 if (licenseFamilyNames != null) {
547 for (final LicenseFamilySpecification spec : licenseFamilyNames) {
548 list.add(newInstance(ILicenseFamily.class, spec.getClassName()));
549 }
550 }
551 return list;
552 }
553 }