001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.ant;
019:
020: import java.io.File;
021: import java.io.FileOutputStream;
022: import java.io.IOException;
023: import java.text.ParseException;
024: import java.util.HashMap;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.Map;
028: import java.util.Set;
029:
030: import javax.xml.transform.OutputKeys;
031: import javax.xml.transform.TransformerConfigurationException;
032: import javax.xml.transform.TransformerFactoryConfigurationError;
033: import javax.xml.transform.sax.SAXTransformerFactory;
034: import javax.xml.transform.sax.TransformerHandler;
035: import javax.xml.transform.stream.StreamResult;
036:
037: import org.apache.ivy.core.cache.ArtifactOrigin;
038: import org.apache.ivy.core.cache.RepositoryCacheManager;
039: import org.apache.ivy.core.module.descriptor.Artifact;
040: import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
041: import org.apache.ivy.core.module.id.ModuleRevisionId;
042: import org.apache.ivy.core.report.ArtifactDownloadReport;
043: import org.apache.ivy.core.resolve.IvyNode;
044: import org.apache.ivy.core.resolve.ResolveOptions;
045: import org.apache.ivy.core.retrieve.RetrieveOptions;
046: import org.apache.tools.ant.BuildException;
047: import org.apache.tools.ant.Project;
048: import org.xml.sax.SAXException;
049: import org.xml.sax.helpers.AttributesImpl;
050:
051: /**
052: * Generates a report of all artifacts involved during the last resolve.
053: */
054: public class IvyArtifactReport extends IvyPostResolveTask {
055: private File tofile;
056:
057: private String pattern;
058:
059: public File getTofile() {
060: return tofile;
061: }
062:
063: public void setTofile(File aFile) {
064: tofile = aFile;
065: }
066:
067: public String getPattern() {
068: return pattern;
069: }
070:
071: public void setPattern(String aPattern) {
072: pattern = aPattern;
073: }
074:
075: public void doExecute() throws BuildException {
076: prepareAndCheck();
077: if (tofile == null) {
078: throw new BuildException(
079: "no destination file name: please provide it through parameter 'tofile'");
080: }
081:
082: pattern = getProperty(pattern, getSettings(),
083: "ivy.retrieve.pattern");
084:
085: try {
086: String[] confs = splitConfs(getConf());
087: ModuleDescriptor md = null;
088: if (getResolveId() != null) {
089: md = (ModuleDescriptor) getResolvedDescriptor(getResolveId());
090: } else {
091: md = (ModuleDescriptor) getResolvedDescriptor(
092: getOrganisation(), getModule(), false);
093: }
094: IvyNode[] dependencies = getIvyInstance()
095: .getResolveEngine().getDependencies(
096: md,
097: new ResolveOptions().setConfs(confs)
098: .setResolveId(getResolveId())
099: .setValidate(
100: doValidate(getSettings())),
101: null);
102:
103: Map artifactsToCopy = getIvyInstance().getRetrieveEngine()
104: .determineArtifactsToCopy(
105: ModuleRevisionId.newInstance(
106: getOrganisation(), getModule(),
107: getRevision()),
108: pattern,
109: new RetrieveOptions().setConfs(confs)
110: .setResolveId(getResolveId()));
111:
112: Map moduleRevToArtifactsMap = new HashMap();
113: for (Iterator iter = artifactsToCopy.keySet().iterator(); iter
114: .hasNext();) {
115: ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter
116: .next();
117: Set moduleRevArtifacts = (Set) moduleRevToArtifactsMap
118: .get(artifact.getArtifact()
119: .getModuleRevisionId());
120: if (moduleRevArtifacts == null) {
121: moduleRevArtifacts = new HashSet();
122: moduleRevToArtifactsMap.put(artifact.getArtifact()
123: .getModuleRevisionId(), moduleRevArtifacts);
124: }
125: moduleRevArtifacts.add(artifact);
126: }
127:
128: generateXml(dependencies, moduleRevToArtifactsMap,
129: artifactsToCopy);
130: } catch (ParseException e) {
131: log(e.getMessage(), Project.MSG_ERR);
132: throw new BuildException("syntax errors in ivy file: " + e,
133: e);
134: } catch (IOException e) {
135: throw new BuildException("impossible to generate report: "
136: + e, e);
137: }
138: }
139:
140: private void generateXml(IvyNode[] dependencies,
141: Map moduleRevToArtifactsMap, Map artifactsToCopy) {
142: try {
143: FileOutputStream fileOuputStream = new FileOutputStream(
144: tofile);
145: try {
146: TransformerHandler saxHandler = createTransformerHandler(fileOuputStream);
147:
148: saxHandler.startDocument();
149: saxHandler.startElement(null, "modules", "modules",
150: new AttributesImpl());
151:
152: for (int i = 0; i < dependencies.length; i++) {
153: IvyNode dependency = dependencies[i];
154: if (dependency.getModuleRevision() == null
155: || dependency.isCompletelyEvicted()) {
156: continue;
157: }
158:
159: startModule(saxHandler, dependency);
160:
161: Set artifactsOfModuleRev = (Set) moduleRevToArtifactsMap
162: .get(dependency.getModuleRevision().getId());
163: if (artifactsOfModuleRev != null) {
164: for (Iterator iter = artifactsOfModuleRev
165: .iterator(); iter.hasNext();) {
166: ArtifactDownloadReport artifact = (ArtifactDownloadReport) iter
167: .next();
168:
169: RepositoryCacheManager cache = dependency
170: .getModuleRevision()
171: .getArtifactResolver()
172: .getRepositoryCacheManager();
173:
174: startArtifact(saxHandler, artifact
175: .getArtifact());
176:
177: writeOriginLocationIfPresent(cache,
178: saxHandler, artifact);
179:
180: writeCacheLocation(cache, saxHandler,
181: artifact);
182:
183: Set artifactDestPaths = (Set) artifactsToCopy
184: .get(artifact);
185: for (Iterator iterator = artifactDestPaths
186: .iterator(); iterator.hasNext();) {
187: String artifactDestPath = (String) iterator
188: .next();
189: writeRetrieveLocation(saxHandler,
190: artifactDestPath);
191: }
192: saxHandler.endElement(null, "artifact",
193: "artifact");
194: }
195: }
196: saxHandler.endElement(null, "module", "module");
197: }
198: saxHandler.endElement(null, "modules", "modules");
199: saxHandler.endDocument();
200: } finally {
201: fileOuputStream.close();
202: }
203: } catch (SAXException e) {
204: throw new BuildException("impossible to generate report", e);
205: } catch (TransformerConfigurationException e) {
206: throw new BuildException("impossible to generate report", e);
207: } catch (IOException e) {
208: throw new BuildException("impossible to generate report", e);
209: }
210: }
211:
212: private TransformerHandler createTransformerHandler(
213: FileOutputStream fileOuputStream)
214: throws TransformerFactoryConfigurationError,
215: TransformerConfigurationException, SAXException {
216: SAXTransformerFactory transformerFact = (SAXTransformerFactory) SAXTransformerFactory
217: .newInstance();
218: TransformerHandler saxHandler = transformerFact
219: .newTransformerHandler();
220: saxHandler.getTransformer().setOutputProperty(
221: OutputKeys.ENCODING, "UTF-8");
222: saxHandler.getTransformer().setOutputProperty(
223: OutputKeys.INDENT, "yes");
224: saxHandler.setResult(new StreamResult(fileOuputStream));
225: return saxHandler;
226: }
227:
228: private void startModule(TransformerHandler saxHandler,
229: IvyNode dependency) throws SAXException {
230: AttributesImpl moduleAttrs = new AttributesImpl();
231: moduleAttrs.addAttribute(null, "organisation", "organisation",
232: "CDATA", dependency.getModuleId().getOrganisation());
233: moduleAttrs.addAttribute(null, "name", "name", "CDATA",
234: dependency.getModuleId().getName());
235: moduleAttrs.addAttribute(null, "rev", "rev", "CDATA",
236: dependency.getModuleRevision().getId().getRevision());
237: moduleAttrs.addAttribute(null, "status", "status", "CDATA",
238: dependency.getModuleRevision().getDescriptor()
239: .getStatus());
240: saxHandler.startElement(null, "module", "module", moduleAttrs);
241: }
242:
243: private void startArtifact(TransformerHandler saxHandler,
244: Artifact artifact) throws SAXException {
245: AttributesImpl artifactAttrs = new AttributesImpl();
246: artifactAttrs.addAttribute(null, "name", "name", "CDATA",
247: artifact.getName());
248: artifactAttrs.addAttribute(null, "ext", "ext", "CDATA",
249: artifact.getExt());
250: artifactAttrs.addAttribute(null, "type", "type", "CDATA",
251: artifact.getType());
252: saxHandler.startElement(null, "artifact", "artifact",
253: artifactAttrs);
254: }
255:
256: private void writeOriginLocationIfPresent(
257: RepositoryCacheManager cache,
258: TransformerHandler saxHandler,
259: ArtifactDownloadReport artifact) throws IOException,
260: SAXException {
261: ArtifactOrigin origin = artifact.getArtifactOrigin();
262: if (origin != ArtifactOrigin.UNKNOWN && origin != null) {
263: String originName = origin.getLocation();
264: boolean isOriginLocal = origin.isLocal();
265:
266: String originLocation;
267: AttributesImpl originLocationAttrs = new AttributesImpl();
268: if (isOriginLocal) {
269: originLocationAttrs.addAttribute(null, "is-local",
270: "is-local", "CDATA", "true");
271: originLocation = originName.replace('\\', '/');
272: } else {
273: originLocationAttrs.addAttribute(null, "is-local",
274: "is-local", "CDATA", "false");
275: originLocation = originName;
276: }
277: saxHandler.startElement(null, "origin-location",
278: "origin-location", originLocationAttrs);
279: char[] originLocationAsChars = originLocation.toCharArray();
280: saxHandler.characters(originLocationAsChars, 0,
281: originLocationAsChars.length);
282: saxHandler.endElement(null, "origin-location",
283: "origin-location");
284: }
285: }
286:
287: private void writeCacheLocation(RepositoryCacheManager cache,
288: TransformerHandler saxHandler,
289: ArtifactDownloadReport artifact) throws SAXException {
290: File archiveInCache = artifact.getLocalFile();
291:
292: saxHandler.startElement(null, "cache-location",
293: "cache-location", new AttributesImpl());
294: char[] archiveInCacheAsChars = archiveInCache.getPath()
295: .replace('\\', '/').toCharArray();
296: saxHandler.characters(archiveInCacheAsChars, 0,
297: archiveInCacheAsChars.length);
298: saxHandler.endElement(null, "cache-location", "cache-location");
299: }
300:
301: private void writeRetrieveLocation(TransformerHandler saxHandler,
302: String artifactDestPath) throws SAXException {
303: artifactDestPath = removeLeadingPath(getProject().getBaseDir(),
304: new File(artifactDestPath));
305:
306: saxHandler.startElement(null, "retrieve-location",
307: "retrieve-location", new AttributesImpl());
308: char[] artifactDestPathAsChars = artifactDestPath.replace('\\',
309: '/').toCharArray();
310: saxHandler.characters(artifactDestPathAsChars, 0,
311: artifactDestPathAsChars.length);
312: saxHandler.endElement(null, "retrieve-location",
313: "retrieve-location");
314: }
315:
316: // method largely inspired by ant 1.6.5 FileUtils method
317: public String removeLeadingPath(File leading, File path) {
318: String l = leading.getAbsolutePath();
319: String p = path.getAbsolutePath();
320: if (l.equals(p)) {
321: return "";
322: }
323:
324: // ensure that l ends with a /
325: // so we never think /foo was a parent directory of /foobar
326: if (!l.endsWith(File.separator)) {
327: l += File.separator;
328: }
329: return (p.startsWith(l)) ? p.substring(l.length()) : p;
330: }
331:
332: }
|