AbstractRatMojo.java
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.rat.mp;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SortedSet;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.cli.Option;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.rat.Defaults;
import org.apache.rat.OptionCollection;
import org.apache.rat.ReportConfiguration;
import org.apache.rat.analysis.license.DeprecatedConfig;
import org.apache.rat.commandline.Arg;
import org.apache.rat.config.exclusion.StandardCollection;
import org.apache.rat.configuration.Format;
import org.apache.rat.configuration.LicenseReader;
import org.apache.rat.configuration.MatcherReader;
import org.apache.rat.document.DocumentName;
import org.apache.rat.document.FileDocument;
import org.apache.rat.license.ILicense;
import org.apache.rat.license.ILicenseFamily;
import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
import org.apache.rat.license.SimpleLicenseFamily;
import org.apache.rat.plugin.BaseRatMojo;
import org.apache.rat.utils.DefaultLog;
import org.apache.rat.utils.Log;
import org.apache.rat.walker.DirectoryWalker;
import static java.lang.String.format;
/**
* Abstract base class for Mojos, which are running Rat.
*/
public abstract class AbstractRatMojo extends BaseRatMojo {
/** Report configuration for report */
private ReportConfiguration reportConfiguration;
/**
* The base directory, in which to search for files.
*/
@Parameter(property = "rat.basedir", defaultValue = "${basedir}", required = true)
protected File basedir;
/**
* Specifies the verbose output.
* @since 0.8
*/
@Parameter(property = "rat.verbose", defaultValue = "false")
protected boolean verbose;
/**
* Specifies the licenses to accept. By default, these are added to the default
* licenses, unless you set <addDefaultLicenseMatchers> to false. Arguments should be
* file name of <Configs> file structure.
* @deprecated Use specific configuration under <configuration>.
* @since 0.8
*/
@Parameter
@Deprecated
private String[] defaultLicenseFiles;
/**
* Specifies the additional licenses file.
* @deprecated Use specific configuration under <configuration>.
*/
@Parameter
@Deprecated
private String[] additionalLicenseFiles;
/**
* Whether to add the default list of licenses.
* @deprecated Deprecated for removal since 0.17: Use <configurationNoDefaults> instead (note the change of state).
*/
@Deprecated
@Parameter(property = "rat.addDefaultLicenses", name = "addDefaultLicenses")
public void setAddDefaultLicenses(final boolean addDefaultLicenses) {
setNoDefaultLicenses(!addDefaultLicenses);
}
/**
* Whether to add the default list of license matchers.
* @deprecated Use specific configuration under <configuration>.
*/
@Deprecated
@Parameter(property = "rat.addDefaultLicenseMatchers")
private boolean addDefaultLicenseMatchers;
/** The list of approved licenses
* @deprecated Use specific configuration under <configuration>.
*/
@Deprecated
@Parameter
private String[] approvedLicenses;
/** The file of approved licenses
* @deprecated Use specific configuration under <configuration>.
*/
@Deprecated
@Parameter(property = "rat.approvedFile")
private String approvedLicenseFile;
/**
* Specifies the license families to accept.
*
* @since 0.8
* @deprecated Use LicenseFamily section of configuration file.
*/
@Deprecated
@Parameter
private SimpleLicenseFamily[] licenseFamilies;
/** The list of license definitions.
* @deprecated Deprecated for removal since 0.17: Use specific configuration under <configuration>. See configuration file documentation.
*/
@Deprecated
@Parameter
private Object[] licenses;
/** The list of family definitions.
* @deprecated Use specific configuration under <configuration>.
*/
@Deprecated
@Parameter
private Family[] families;
/**
* Specifies the include files character set.
* If ${project.build.sourceEncoding} is not set defaults to UTF-8.
*/
@Parameter(property = "rat.includesFileCharset", defaultValue = "${project.build.sourceEncoding}")
private String includesFileCharset;
/**
* Specifies the include files character set.
* If ${project.build.sourceEncoding} is not set defaults to UTF-8.
*/
@Parameter(property = "rat.excludesFileCharset", defaultValue = "${project.build.sourceEncoding}")
private String excludesFileCharset;
/**
* Whether to use the default excludes when scanning for files. The default
* excludes are:
* <ul>
* <li>meta data files for source code management / revision control systems,
* see {@link org.apache.rat.config.exclusion.StandardCollection}</li>
* <li>temporary files used by Maven, see
* <a href="#useMavenDefaultExcludes">useMavenDefaultExcludes</a></li>
* <li>configuration files for Eclipse, see
* <a href="#useEclipseDefaultExcludes">useEclipseDefaultExcludes</a></li>
* <li>configuration files for IDEA, see
* <a href="#useIdeaDefaultExcludes">useIdeaDefaultExcludes</a></li>
* </ul>
* @deprecated When set to true specifies that the STANDARD_PATTERNS are excluded, as are
* the STANDARD_SCMS patterns. Use the various InputExclude and InputInclude elements to
* explicitly specify what to include or exclude.
*/
@Parameter(property = "rat.useDefaultExcludes", defaultValue = "true")
@Deprecated
private boolean useDefaultExcludes;
/**
* Whether to use the Maven specific default excludes when scanning for files.
* Maven specific default excludes are given by the constant
* MAVEN_DEFAULT_EXCLUDES: The <code>target</code> directory, the
* <code>cobertura.ser</code> file, and so on.
* @deprecated When set to true specifies that the MAVEN patterns are excluded.
* Use "inputIncludeStd MAVEN" to override.
*/
@Parameter(property = "rat.useMavenDefaultExcludes", defaultValue = "true")
@Deprecated
private boolean useMavenDefaultExcludes;
/**
* Whether to parse source code management system (SCM) ignore files and use
* their contents as excludes. At the moment this works for the following SCMs:
*
* @see org.apache.rat.config.exclusion.StandardCollection
* @deprecated When set to true specifies that the STANDARD_SCMS exclusion file
* processors are used to exclude files and directories (e.g. ".gitignore" or ".hgignore").
* Use "inputIncludeStd STANDARD_SCMS" to override.
*/
@Parameter(property = "rat.parseSCMIgnoresAsExcludes", defaultValue = "true")
@Deprecated
private boolean parseSCMIgnoresAsExcludes;
/**
* Whether to use the Eclipse specific default excludes when scanning for files.
* Eclipse specific default excludes are given by the constant
* ECLIPSE_DEFAULT_EXCLUDES: The <code>.classpath</code> and
* <code>.project</code> files, the <code>.settings</code> directory, and so on.
* @deprecated When set to true specifies that the ECLIPSE patterns are excluded.
* Use "inputIncludeStd ECLIPSE" to override.
*/
@Parameter(property = "rat.useEclipseDefaultExcludes", defaultValue = "true")
@Deprecated
private boolean useEclipseDefaultExcludes;
/**
* Whether to use the IDEA specific default excludes when scanning for files.
* IDEA specific default excludes are given by the constant
* IDEA_DEFAULT_EXCLUDES: The <code>*.iml</code>, <code>*.ipr</code> and
* <code>*.iws</code> files and the <code>.idea</code> directory.
* @deprecated When set to true specifies that the IDEA patterns are excluded.
* Use "inputIncludeStd IDEA" to override.
*/
@Deprecated
@Parameter(property = "rat.useIdeaDefaultExcludes", defaultValue = "true")
private boolean useIdeaDefaultExcludes;
/**
* Whether to exclude subprojects. This is recommended, if you want a separate
* apache-rat-plugin report for each subproject.
*/
@Parameter(property = "rat.excludeSubprojects", defaultValue = "true")
private boolean excludeSubProjects;
/**
* Will skip the plugin execution, e.g. for technical builds that do not take
* license compliance into account.
*
* @since 0.11
*/
@Parameter(property = "rat.skip", defaultValue = "false")
protected boolean skip;
/**
* Holds the maven-internal project to allow resolution of artifact properties
* during mojo runs.
*/
@Parameter(defaultValue = "${project}", required = true, readonly = true)
protected MavenProject project;
protected AbstractRatMojo() {
DefaultLog.setInstance(makeLog());
}
/**
* @return the Maven project.
*/
protected MavenProject getProject() {
return project;
}
protected Defaults.Builder getDefaultsBuilder() {
Defaults.Builder result = Defaults.builder().noDefault();
if (defaultLicenseFiles != null) {
for (String defaultLicenseFile : defaultLicenseFiles) {
result.add(defaultLicenseFile);
}
}
return result;
}
@Deprecated // remove this for version 1.0
private Stream<License> getLicenses() {
if (licenses == null) {
return Stream.empty();
}
return Arrays.stream(licenses).filter(s -> s instanceof License).map(License.class::cast);
}
@Deprecated // remove this for version 1.0
private Stream<DeprecatedConfig> getDeprecatedConfigs() {
if (licenses == null) {
return Stream.empty();
}
return Arrays.stream(licenses).filter(s -> s instanceof DeprecatedConfig).map(DeprecatedConfig.class::cast);
}
@Deprecated // remove this for version 1.0
private void reportDeprecatedProcessing() {
if (getDeprecatedConfigs().findAny().isPresent()) {
DefaultLog.getInstance().warn("Configuration uses deprecated configuration. You need to upgrade to v0.17 configuration options.");
}
}
@Deprecated // remove this for version 1.0
private void processLicenseFamilies(final ReportConfiguration config) {
List<ILicenseFamily> families = getDeprecatedConfigs().map(DeprecatedConfig::getLicenseFamily).filter(Objects::nonNull).collect(Collectors.toList());
if (licenseFamilies != null) {
for (SimpleLicenseFamily slf : licenseFamilies) {
if (StringUtils.isBlank(slf.getFamilyCategory())) {
families.stream().filter(f -> f.getFamilyName().equalsIgnoreCase(slf.getFamilyName())).findFirst()
.ifPresent(config::addApprovedLicenseCategory);
} else {
config.addApprovedLicenseCategory(ILicenseFamily.builder().setLicenseFamilyCategory(slf.getFamilyCategory())
.setLicenseFamilyName(StringUtils.defaultIfBlank(slf.getFamilyName(), slf.getFamilyCategory()))
.build());
}
}
}
}
/**
* Reads values for the Arg.
*
* @param arg The Arg to get the values for.
* @return The list of values or an empty list.
*/
protected List<String> getValues(final Arg arg) {
List<String> result = new ArrayList<>();
for (Option option : arg.group().getOptions()) {
if (option.getLongOpt() != null) {
List<String> args = getArg(option.getLongOpt());
if (args != null) {
result.addAll(args);
}
}
}
return result;
}
/**
* Removes all values for an Arg.
* @param arg The arg to remove values for.
*/
protected void removeKey(final Arg arg) {
for (Option option : arg.group().getOptions()) {
if (option.getLongOpt() != null) {
removeArg(option.getLongOpt());
}
}
}
private org.apache.rat.utils.Log makeLog() {
return new org.apache.rat.utils.Log() {
@Override
public Level getLevel() {
final org.apache.maven.plugin.logging.Log log = getLog();
if (log.isDebugEnabled()) {
return Level.DEBUG;
}
if (log.isInfoEnabled()) {
return Level.INFO;
}
if (log.isWarnEnabled()) {
return Level.WARN;
}
if (log.isErrorEnabled()) {
return Level.ERROR;
}
return Level.OFF;
}
@Override
public void log(final Level level, final String message, final Throwable throwable) {
final org.apache.maven.plugin.logging.Log log = getLog();
switch (level) {
case DEBUG:
if (throwable != null) {
log.debug(message, throwable);
} else {
log.debug(message);
}
break;
case INFO:
if (throwable != null) {
log.info(message, throwable);
} else {
log.info(message);
}
break;
case WARN:
if (throwable != null) {
log.warn(message, throwable);
} else {
log.warn(message);
}
break;
case ERROR:
if (throwable != null) {
log.error(message, throwable);
} else {
log.error(message);
}
break;
case OFF:
break;
}
}
@Override
public void log(final Level level, final String msg) {
final org.apache.maven.plugin.logging.Log log = getLog();
switch (level) {
case DEBUG:
log.debug(msg);
break;
case INFO:
log.info(msg);
break;
case WARN:
log.warn(msg);
break;
case ERROR:
log.error(msg);
break;
case OFF:
break;
}
}
};
}
private void setIncludeExclude() {
if (excludeSubProjects && project != null && project.getModules() != null) {
List<String> subModules = new ArrayList<>();
project.getModules().forEach(s -> subModules.add(format("%s/**", s)));
setInputExcludes(subModules.toArray(new String[0]));
}
List<String> values = getValues(Arg.EXCLUDE);
if (values.isEmpty() && useDefaultExcludes) {
DefaultLog.getInstance().debug("Adding plexus default exclusions...");
setInputExcludes(StandardCollection.STANDARD_PATTERNS.patterns().toArray(new String[0]));
DefaultLog.getInstance().debug("Adding SCM default exclusions...");
setInputExcludes(StandardCollection.STANDARD_SCMS.patterns().toArray(new String[0]));
}
if (useMavenDefaultExcludes) {
setInputExcludeStd(StandardCollection.MAVEN.name());
}
if (useEclipseDefaultExcludes) {
setInputExcludeStd(StandardCollection.ECLIPSE.name());
}
if (useIdeaDefaultExcludes) {
setInputExcludeStd(StandardCollection.IDEA.name());
}
if (parseSCMIgnoresAsExcludes) {
setInputExcludeParsedScm(StandardCollection.STANDARD_SCMS.name());
}
}
protected ReportConfiguration getConfiguration() throws MojoExecutionException {
Log log = DefaultLog.getInstance();
if (reportConfiguration == null) {
try {
if (getLog().isDebugEnabled()) {
log.debug("Start BaseRatMojo Configuration options");
for (Map.Entry<String, List<String>> entry : args.entrySet()) {
log.debug(format(" * %s %s", entry.getKey(), String.join(", ", entry.getValue())));
}
log.debug("End BaseRatMojo Configuration options");
}
boolean helpLicenses = !getValues(Arg.HELP_LICENSES).isEmpty();
removeKey(Arg.HELP_LICENSES);
setIncludeExclude();
getLog().debug("Basedir is : " + basedir);
ReportConfiguration config = OptionCollection.parseCommands(basedir, args().toArray(new String[0]),
o -> getLog().warn("Help option not supported"),
true);
reportDeprecatedProcessing();
if (additionalLicenseFiles != null) {
for (String licenseFile : additionalLicenseFiles) {
URI uri = new File(licenseFile).toURI();
Format fmt = Format.from(licenseFile);
MatcherReader mReader = fmt.matcherReader();
if (mReader != null) {
mReader.addMatchers(uri);
}
LicenseReader lReader = fmt.licenseReader();
if (lReader != null) {
lReader.addLicenses(uri);
config.addLicenses(lReader.readLicenses());
config.addApprovedLicenseCategories(lReader.approvedLicenseId());
}
}
}
if (families != null || getDeprecatedConfigs().findAny().isPresent()) {
if (log.isEnabled(Log.Level.DEBUG) && families != null) {
log.debug(format("%s license families loaded from pom", families.length));
}
Consumer<ILicenseFamily> logger = super.getLog().isDebugEnabled() ? l -> log.debug(format("Family: %s", l))
: l -> {
};
Consumer<ILicenseFamily> process = logger.andThen(config::addFamily);
getDeprecatedConfigs().map(DeprecatedConfig::getLicenseFamily).filter(Objects::nonNull).forEach(process);
if (families != null) { // TODO remove if check in v1.0
Arrays.stream(families).map(Family::build).forEach(process);
}
}
processLicenseFamilies(config);
if (approvedLicenses != null && approvedLicenses.length > 0) {
Arrays.stream(approvedLicenses).forEach(config::addApprovedLicenseCategory);
}
if (licenses != null) {
if (log.isEnabled(Log.Level.DEBUG)) {
log.debug(format("%s licenses loaded from pom", licenses.length));
}
Consumer<ILicense> logger = log.isEnabled(Log.Level.DEBUG) ? l -> log.debug(format("License: %s", l))
: l -> {
};
Consumer<ILicense> addApproved = (approvedLicenses == null || approvedLicenses.length == 0)
? l -> config.addApprovedLicenseCategory(l.getLicenseFamily())
: l -> {
};
Consumer<ILicense> process = logger.andThen(config::addLicense).andThen(addApproved);
SortedSet<ILicenseFamily> families = config.getLicenseFamilies(LicenseFilter.ALL);
getDeprecatedConfigs().map(DeprecatedConfig::getLicense).filter(Objects::nonNull)
.map(x -> x.setLicenseFamilies(families).build()).forEach(process);
getLicenses().map(x -> x.build(families)).forEach(process);
}
DocumentName dirName = DocumentName.builder(basedir).build();
config.addSource(new DirectoryWalker(new FileDocument(dirName, basedir, config.getDocumentExcluder(dirName))));
if (helpLicenses) {
new org.apache.rat.help.Licenses(config, new PrintWriter(log.asWriter())).printHelp();
}
reportConfiguration = config;
} catch (IOException e) {
throw new MojoExecutionException(e);
}
}
return reportConfiguration;
}
protected void logLicenses(final Collection<ILicense> licenses) {
if (getLog().isDebugEnabled()) {
getLog().debug("The following " + licenses.size() + " licenses are activated:");
for (ILicense license : licenses) {
getLog().debug("* " + license.toString());
}
}
}
}