| /* |
| * 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; |
| } |
| |
| } |