blob: dc9f5b0420a86dc9a5229429fca6325aaf83993c [file] [log] [blame]
/*
* 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.anttasks;
import org.apache.commons.io.IOUtils;
import org.apache.rat.Defaults;
import org.apache.rat.ReportConfiguration;
import org.apache.rat.analysis.IHeaderMatcher;
import org.apache.rat.analysis.util.HeaderMatcherMultiplexer;
import org.apache.rat.api.RatException;
import org.apache.rat.license.ILicenseFamily;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.LogOutputStream;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.Union;
import org.apache.tools.ant.util.FileUtils;
import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
* A basic Ant task that generates a report on all files specified by
* the nested resource collection(s).
*
* <p>IHeaderMatcher(s) can be specified as nested elements as well.</p>
*
* <p>The attribute <code>format</code> defines the output format and
* can take the values
* <ul>
* <li>xml - Rat's native XML output.</li>
* <li>styled - transforms the XML output using the given
* stylesheet. The stylesheet attribute must be set as well if this
* attribute is used.</li>
* <li>plain - plain text using Rat's built-in stylesheet. This is
* the default.</li>
* </ul>
*/
public class Report extends Task {
/**
* will hold any nested resource collection
*/
private Union nestedResources;
/**
* The licenses we want to match on.
*/
private ArrayList<IHeaderMatcher> licenseMatchers = new ArrayList<IHeaderMatcher>();
private ArrayList<ILicenseFamily> licenseNames = new ArrayList<ILicenseFamily>();
/**
* Whether to add the default list of license matchers.
*/
private boolean addDefaultLicenseMatchers = true;
/**
* Where to send the report.
*/
private File reportFile;
/**
* Which format to use.
*/
private Format format = Format.PLAIN;
/**
* Which stylesheet to use.
*/
private Resource stylesheet;
/**
* Whether to add license headers.
*/
private AddLicenseHeaders addLicenseHeaders = new AddLicenseHeaders(AddLicenseHeaders.FALSE);
/**
* The copyright message.
*/
private String copyrightMessage;
/**
* Adds resources that will be checked.
* @param rc resource to check.
*/
public void add(ResourceCollection rc) {
if (nestedResources == null) {
nestedResources = new Union();
}
nestedResources.add(rc);
}
/**
* @param matcher Adds a license matcher.
*/
public void add(IHeaderMatcher matcher) {
licenseMatchers.add(matcher);
}
public void add(ILicenseFamily license) {
licenseNames.add(license);
}
/**
* @param addDefaultLicenseMatchers Whether to add the default list of license matchers.
*/
public void setAddDefaultLicenseMatchers(boolean addDefaultLicenseMatchers) {
this.addDefaultLicenseMatchers = addDefaultLicenseMatchers;
}
/**
* Where to send the report to.
* @param f report output file.
*/
public void setReportFile(File f) {
reportFile = f;
}
/**
* Which format to use.
* @param f format.
*/
public void setFormat(Format f) {
if (f == null) {
throw new IllegalArgumentException("format must not be null");
}
format = f;
}
/**
* @param pAdd Whether to add license headers.
*/
public void setAddLicenseHeaders(AddLicenseHeaders pAdd) {
if (pAdd == null) {
throw new IllegalArgumentException("addLicenseHeaders must not be null");
}
addLicenseHeaders = pAdd;
}
/**
* @param pMessage copyright message to set.
*/
public void setCopyrightMessage(String pMessage) {
copyrightMessage = pMessage;
}
/**
* Which stylesheet to use (only meaningful with format='styled').
* @param u stylesheet.
*/
public void addConfiguredStylesheet(Union u) {
if (stylesheet != null || u.size() != 1) {
throw new BuildException("You must not specify more than one"
+ " stylesheet.");
}
stylesheet = (Resource) u.iterator().next();
}
/**
* Generates the report.
*/
@Override
public void execute() {
validate();
PrintWriter out = null;
try {
if (reportFile == null) {
out = new PrintWriter(
new OutputStreamWriter(
new LogOutputStream(this, Project.MSG_INFO)
)
);
} else {
out = new PrintWriter(new FileWriter(reportFile));
}
createReport(out);
out.flush();
} catch (IOException ioex) {
throw new BuildException(ioex);
} catch (TransformerException e) {
throw new BuildException(e);
} catch (InterruptedException e) {
throw new BuildException(e);
} catch (RatException e) {
throw new BuildException(e);
} finally {
IOUtils.closeQuietly(out);
}
}
/**
* validates the task's configuration.
*/
private void validate() {
if (nestedResources == null) {
throw new BuildException("You must specify at least one file to"
+ " create the report for.");
}
if (!addDefaultLicenseMatchers && licenseMatchers.size() == 0) {
throw new BuildException("You must specify at least one license"
+ " matcher");
}
if (format.getValue().equals(Format.STYLED_KEY)) {
if (stylesheet == null) {
throw new BuildException("You must specify a stylesheet when"
+ " using the 'styled' format");
}
if (!stylesheet.isExists()) {
throw new BuildException("Cannot find specified stylesheet '"
+ stylesheet + "'");
}
} else if (stylesheet != null) {
log("Ignoring stylesheet '" + stylesheet + "' when using format '"
+ format.getValue() + "'", Project.MSG_WARN);
}
}
/**
* Writes the report to the given stream.
*
* @param out stream to write report to.
*
* @throws IOException in case of I/O errors.
* @throws InterruptedException in case of threading errors.
* @throws TransformerException in case of XML errors.
* @throws RatException in case of general errors.
*/
private void createReport(PrintWriter out) throws IOException, TransformerException, InterruptedException, RatException {
final ReportConfiguration configuration = new ReportConfiguration();
configuration.setHeaderMatcher(new HeaderMatcherMultiplexer(getLicenseMatchers()));
configuration.setApprovedLicenseNames(getApprovedLicenseNames());
configuration.setApproveDefaultLicenses(addDefaultLicenseMatchers);
if (AddLicenseHeaders.FORCED.equalsIgnoreCase(addLicenseHeaders.getValue())) {
configuration.setAddingLicenses(true);
configuration.setAddingLicensesForced(true);
configuration.setCopyrightMessage(copyrightMessage);
} else if (AddLicenseHeaders.TRUE.equalsIgnoreCase(addLicenseHeaders.getValue())) {
configuration.setAddingLicenses(true);
configuration.setCopyrightMessage(copyrightMessage);
} else if (!AddLicenseHeaders.FALSE.equalsIgnoreCase(addLicenseHeaders.getValue())) {
throw new BuildException("Invalid value for addLicenseHeaders: " + addLicenseHeaders.getValue());
}
ResourceCollectionContainer rcElement = new ResourceCollectionContainer(nestedResources);
if (format.getValue().equals(Format.XML_KEY)) {
org.apache.rat.Report.report(rcElement, out, configuration);
} else {
InputStream style = null;
try {
if (format.getValue().equals(Format.PLAIN_KEY)) {
style = Defaults.getPlainStyleSheet();
} else if (format.getValue().equals(Format.STYLED_KEY)) {
style = stylesheet.getInputStream();
} else {
throw new BuildException("unsupported format '"
+ format.getValue() + "'");
}
org.apache.rat.Report.report(out, rcElement, style,
configuration);
} finally {
FileUtils.close(style);
}
}
}
/**
* Flattens all nested matchers plus the default matchers (if
* required) into a single array.
*/
private List<IHeaderMatcher> getLicenseMatchers() {
List<IHeaderMatcher> matchers = new ArrayList<IHeaderMatcher>(Defaults.DEFAULT_MATCHERS);
if (addDefaultLicenseMatchers) {
int nestedSize = licenseMatchers.size();
if (nestedSize != 0) {
matchers.addAll(licenseMatchers);
}
} else {
matchers = new ArrayList<IHeaderMatcher>();
}
return matchers;
}
private ILicenseFamily[] getApprovedLicenseNames() {
// TODO: add support for adding default licenses
ILicenseFamily[] results = null;
if (licenseNames.size() > 0) {
results = licenseNames.toArray(new ILicenseFamily[0]);
}
return results;
}
/**
* Type for the format attribute.
*/
public static class Format extends EnumeratedAttribute {
static final String XML_KEY = "xml";
static final String STYLED_KEY = "styled";
static final String PLAIN_KEY = "plain";
static final Format PLAIN = new Format(PLAIN_KEY);
public Format() { super(); }
private Format(String s) {
this();
setValue(s);
}
@Override
public String[] getValues() {
return new String[] {
XML_KEY, STYLED_KEY, PLAIN_KEY
};
}
}
/**
* Type for the addLicenseHeaders attribute.
*/
public static class AddLicenseHeaders extends EnumeratedAttribute {
static final String TRUE = "true";
static final String FALSE = "false";
static final String FORCED = "forced";
public AddLicenseHeaders() {}
public AddLicenseHeaders(String s) {
setValue(s);
}
@Override
public String[] getValues() {
return new String[] {
TRUE, FALSE, FORCED
};
}
}
}