blob: 662fd325a951e5501047cecfed6c52164f23edef [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
*
* https://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.ivy.ant;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.ivy.Ivy;
import org.apache.ivy.core.IvyPatternHelper;
import org.apache.ivy.core.cache.ResolutionCacheManager;
import org.apache.ivy.core.module.id.ModuleId;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.core.resolve.ResolveOptions;
import org.apache.ivy.core.settings.IvySettings;
import org.apache.ivy.plugins.report.XmlReportOutputter;
import org.apache.ivy.plugins.report.XmlReportParser;
import org.apache.ivy.util.FileUtil;
import org.apache.ivy.util.Message;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.XSLTProcess;
import org.apache.tools.ant.util.JAXPUtils;
import static org.apache.ivy.util.StringUtils.splitToArray;
/**
* This ant task let users generates reports (html, xml, graphml, ...) from the last resolve done.
*/
public class IvyReport extends IvyTask {
private File todir;
private String organisation;
private String module;
private String conf;
private boolean graph = true;
private boolean dot = false;
private boolean xml = false;
private boolean xsl = true;
private File xslFile;
private String outputpattern;
private String xslext = "html";
private final List<XSLTProcess.Param> params = new ArrayList<>();
private String resolveId;
private ModuleRevisionId mRevId;
public File getTodir() {
return todir;
}
public void setTodir(File todir) {
this.todir = todir;
}
public void setCache(File cache) {
cacheAttributeNotSupported();
}
public String getConf() {
return conf;
}
public void setConf(String conf) {
this.conf = conf;
}
public String getModule() {
return module;
}
public void setModule(String module) {
this.module = module;
}
public String getOrganisation() {
return organisation;
}
public void setOrganisation(String organisation) {
this.organisation = organisation;
}
public boolean isGraph() {
return graph;
}
public void setGraph(boolean graph) {
this.graph = graph;
}
public File getXslfile() {
return xslFile;
}
public void setXslfile(File xslFile) {
this.xslFile = xslFile;
}
public String getOutputpattern() {
return outputpattern;
}
public void setOutputpattern(String outputpattern) {
this.outputpattern = outputpattern;
}
public String getResolveId() {
return resolveId;
}
public void setResolveId(String resolveId) {
this.resolveId = resolveId;
}
public void doExecute() throws BuildException {
Ivy ivy = getIvyInstance();
IvySettings settings = ivy.getSettings();
conf = getProperty(conf, settings, "ivy.resolved.configurations", resolveId);
if ("*".equals(conf)) {
conf = getProperty(settings, "ivy.resolved.configurations", resolveId);
}
if (conf == null) {
throw new BuildException("no conf provided for ivy report task: "
+ "It can either be set explicitly via the attribute 'conf' or "
+ "via 'ivy.resolved.configurations' property or a prior call to <resolve/>");
}
if (todir == null) {
String t = getProperty(settings, "ivy.report.todir");
if (t != null) {
todir = getProject().resolveFile(t);
}
}
if (todir != null && todir.exists()) {
todir.mkdirs();
}
outputpattern = getProperty(outputpattern, settings, "ivy.report.output.pattern");
if (outputpattern == null) {
outputpattern = "[organisation]-[module]-[conf].[ext]";
}
if (todir != null && todir.exists() && !todir.isDirectory()) {
throw new BuildException("destination directory should be a directory !");
}
if (resolveId == null) {
organisation = getProperty(organisation, settings, "ivy.organisation", resolveId);
module = getProperty(module, settings, "ivy.module", resolveId);
if (organisation == null) {
throw new BuildException("no organisation provided for ivy report task: "
+ "It can either be set explicitly via the attribute 'organisation' or "
+ "via 'ivy.organisation' property or a prior call to <resolve/>");
}
if (module == null) {
throw new BuildException("no module name provided for ivy report task: "
+ "It can either be set explicitly via the attribute 'module' or "
+ "via 'ivy.module' property or a prior call to <resolve/>");
}
resolveId = ResolveOptions.getDefaultResolveId(new ModuleId(organisation, module));
}
try {
String[] confs = splitToArray(conf);
if (xsl) {
genreport(confs);
}
if (xml) {
genxml(confs);
}
if (graph) {
genStyled(confs, getStylePath("ivy-report-graph.xsl"), "graphml");
}
if (dot) {
genStyled(confs, getStylePath("ivy-report-dot.xsl"), "dot");
}
} catch (IOException e) {
throw new BuildException("impossible to generate report: " + e, e);
}
}
private void genxml(String[] confs) throws IOException {
ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager();
for (String config : confs) {
File xml = cacheMgr.getConfigurationResolveReportInCache(resolveId, config);
File out;
if (todir == null) {
out = getProject().resolveFile(getOutputPattern(config, "xml"));
} else {
out = new File(todir, getOutputPattern(config, "xml"));
}
FileUtil.copy(xml, out, null);
}
}
private void genreport(String[] confs) throws IOException {
genStyled(confs, getReportStylePath(), xslext);
// copy the css if required
if (xslFile == null) {
File css;
if (todir == null) {
css = getProject().resolveFile("ivy-report.css");
} else {
css = new File(todir, "ivy-report.css");
}
if (!css.exists()) {
Message.debug("copying report css to " + css.getAbsolutePath());
FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.css"), css,
null);
}
}
}
private File getReportStylePath() throws IOException {
if (xslFile != null) {
return xslFile;
}
// style should be a file (and not an url)
// so we have to copy it from classpath to cache
ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager();
File style = new File(cacheMgr.getResolutionCacheRoot(), "ivy-report.xsl");
if (!style.exists()) {
Message.debug("copying ivy-report.xsl to " + style.getAbsolutePath());
FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.xsl"), style,
null);
}
return style;
}
private String getOutputPattern(String conf, String ext) {
if (mRevId == null) {
ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager();
XmlReportParser parser = new XmlReportParser();
File reportFile = cacheMgr.getConfigurationResolveReportInCache(resolveId, conf);
try {
parser.parse(reportFile);
} catch (ParseException e) {
throw new BuildException("Error occurred while parsing reportfile '"
+ reportFile.getAbsolutePath() + "'", e);
}
// get the resolve module
mRevId = parser.getResolvedModule();
}
return IvyPatternHelper.substitute(outputpattern, mRevId.getOrganisation(),
mRevId.getName(), mRevId.getRevision(), "", "", ext, conf,
mRevId.getQualifiedExtraAttributes(), null);
}
private void genStyled(String[] confs, File style, String ext) throws IOException {
ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager();
// process the report with xslt to generate dot file
File out;
if (todir != null) {
out = todir;
} else {
out = getProject().getBaseDir();
}
try (InputStream xsltStream = new BufferedInputStream(new FileInputStream(style))) {
// create stream to stylesheet
Source xsltSource = new StreamSource(xsltStream, JAXPUtils.getSystemId(style));
// create transformer
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(xsltSource);
// add standard parameters
transformer.setParameter("confs", conf);
transformer.setParameter("extension", xslext);
// add the provided XSLT parameters
for (XSLTProcess.Param param : params) {
transformer.setParameter(param.getName(), param.getExpression());
}
// create the report
for (String config : confs) {
File reportFile = cacheMgr.getConfigurationResolveReportInCache(resolveId, config);
File outFile = new File(out, getOutputPattern(config, ext));
log("Processing " + reportFile + " to " + outFile);
// make sure the output directory exist
File outFileDir = outFile.getParentFile();
if (!outFileDir.exists()) {
if (!outFileDir.mkdirs()) {
throw new BuildException("Unable to create directory: "
+ outFileDir.getAbsolutePath());
}
}
try (InputStream inStream = new BufferedInputStream(new FileInputStream(reportFile));
OutputStream outStream = new BufferedOutputStream(new FileOutputStream(outFile))) {
StreamResult res = new StreamResult(outStream);
Source src = new StreamSource(inStream, JAXPUtils.getSystemId(style));
transformer.transform(src, res);
} catch (TransformerException e) {
throw new BuildException(e);
}
}
} catch (TransformerConfigurationException e) {
throw new BuildException(e);
}
}
private File getStylePath(String styleResourceName) throws IOException {
// style should be a file (and not an url)
// so we have to copy it from classpath to cache
ResolutionCacheManager cacheMgr = getIvyInstance().getResolutionCacheManager();
File style = new File(cacheMgr.getResolutionCacheRoot(), styleResourceName);
FileUtil.copy(XmlReportOutputter.class.getResourceAsStream(styleResourceName), style, null);
return style;
}
public boolean isXml() {
return xml;
}
public void setXml(boolean xml) {
this.xml = xml;
}
public boolean isXsl() {
return xsl;
}
public void setXsl(boolean xsl) {
this.xsl = xsl;
}
public String getXslext() {
return xslext;
}
public void setXslext(String xslext) {
this.xslext = xslext;
}
public XSLTProcess.Param createParam() {
XSLTProcess.Param result = new XSLTProcess.Param();
params.add(result);
return result;
}
public boolean isDot() {
return dot;
}
public void setDot(boolean dot) {
this.dot = dot;
}
}