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.core.publish;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.net.MalformedURLException;
023: import java.net.URL;
024: import java.text.ParseException;
025: import java.util.ArrayList;
026: import java.util.Arrays;
027: import java.util.Collection;
028: import java.util.Date;
029: import java.util.HashMap;
030: import java.util.HashSet;
031: import java.util.Iterator;
032: import java.util.Set;
033:
034: import org.apache.ivy.core.IvyContext;
035: import org.apache.ivy.core.IvyPatternHelper;
036: import org.apache.ivy.core.cache.ResolutionCacheManager;
037: import org.apache.ivy.core.event.EventManager;
038: import org.apache.ivy.core.event.publish.EndArtifactPublishEvent;
039: import org.apache.ivy.core.event.publish.StartArtifactPublishEvent;
040: import org.apache.ivy.core.module.descriptor.Artifact;
041: import org.apache.ivy.core.module.descriptor.DefaultArtifact;
042: import org.apache.ivy.core.module.descriptor.MDArtifact;
043: import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
044: import org.apache.ivy.core.module.id.ModuleRevisionId;
045: import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser;
046: import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorUpdater;
047: import org.apache.ivy.plugins.resolver.DependencyResolver;
048: import org.apache.ivy.util.ConfigurationUtils;
049: import org.apache.ivy.util.Message;
050: import org.xml.sax.SAXException;
051:
052: public class PublishEngine {
053: private PublishEngineSettings settings;
054: private EventManager eventManager;
055:
056: public PublishEngine(PublishEngineSettings settings,
057: EventManager eventManager) {
058: this .settings = settings;
059: this .eventManager = eventManager;
060: }
061:
062: /**
063: * Publishes a module to the repository. The publish can update the ivy file to publish if
064: * update is set to true. In this case it will use the given pubrevision, pubdate and status. If
065: * pubdate is null it will default to the current date. If status is null it will default to the
066: * current ivy file status (which itself defaults to integration if none is found). If update is
067: * false, then if the revision is not the same in the ivy file than the one expected (given as
068: * parameter), this method will fail with an IllegalArgumentException. pubdate and status are
069: * not used if update is false. extra artifacts can be used to publish more artifacts than
070: * actually declared in the ivy file. This can be useful to publish additional metadata or
071: * reports. The extra artifacts array can be null (= no extra artifacts), and if non null only
072: * the name, type, ext url and extra attributes of the artifacts are really used. Other methods
073: * can return null safely.
074: */
075: public Collection publish(ModuleRevisionId mrid,
076: Collection srcArtifactPattern, String resolverName,
077: PublishOptions options) throws IOException {
078: Message.info(":: publishing :: " + mrid.getModuleId());
079: Message.verbose("\tvalidate = " + options.isValidate());
080: long start = System.currentTimeMillis();
081:
082: options.setSrcIvyPattern(settings.substitute(options
083: .getSrcIvyPattern()));
084: if (options.getPubrevision() == null) {
085: options.setPubrevision(mrid.getRevision());
086: }
087: ModuleRevisionId pubmrid = ModuleRevisionId.newInstance(mrid,
088: options.getPubrevision());
089: File ivyFile;
090: if (options.getSrcIvyPattern() != null) {
091: ivyFile = new File(IvyPatternHelper.substitute(options
092: .getSrcIvyPattern(), DefaultArtifact
093: .newIvyArtifact(pubmrid, new Date())));
094: if (!ivyFile.exists()) {
095: throw new IllegalArgumentException(
096: "ivy file to publish not found for " + mrid
097: + ": call deliver before (" + ivyFile
098: + ")");
099: }
100: } else {
101: ResolutionCacheManager cacheManager = settings
102: .getResolutionCacheManager();
103: ivyFile = cacheManager.getResolvedIvyFileInCache(mrid);
104: if (!ivyFile.exists()) {
105: throw new IllegalStateException(
106: "ivy file not found in cache for "
107: + mrid
108: + ": please resolve dependencies before publishing ("
109: + ivyFile + ")");
110: }
111: }
112:
113: // let's find the resolved module descriptor
114: ModuleDescriptor md = null;
115: URL ivyFileURL = null;
116: try {
117: ivyFileURL = ivyFile.toURL();
118: md = XmlModuleDescriptorParser.getInstance()
119: .parseDescriptor(settings, ivyFileURL, false);
120: if (options.getSrcIvyPattern() != null) {
121: if (options.isUpdate()) {
122: File tmp = File.createTempFile("ivy", ".xml");
123: tmp.deleteOnExit();
124:
125: String[] confs = ConfigurationUtils
126: .replaceWildcards(options.getConfs(), md);
127: Set confsToRemove = new HashSet(Arrays.asList(md
128: .getConfigurationsNames()));
129: confsToRemove.removeAll(Arrays.asList(confs));
130:
131: try {
132: XmlModuleDescriptorUpdater
133: .update(
134: settings,
135: ivyFileURL,
136: tmp,
137: new HashMap(),
138: options.getStatus() == null ? md
139: .getStatus()
140: : options.getStatus(),
141: options.getPubrevision(),
142: options.getPubdate() == null ? new Date()
143: : options.getPubdate(),
144: null,
145: true,
146: (String[]) confsToRemove
147: .toArray(new String[confsToRemove
148: .size()]));
149: ivyFile = tmp;
150: // we parse the new file to get updated module descriptor
151: md = XmlModuleDescriptorParser.getInstance()
152: .parseDescriptor(settings,
153: ivyFile.toURL(), false);
154: options.setSrcIvyPattern(ivyFile
155: .getAbsolutePath());
156: } catch (SAXException e) {
157: throw new IllegalStateException(
158: "bad ivy file for " + mrid + ": "
159: + ivyFile + ": " + e);
160: }
161: } else if (!options.getPubrevision().equals(
162: md.getModuleRevisionId().getRevision())) {
163: throw new IllegalArgumentException(
164: "cannot publish "
165: + ivyFile
166: + " as "
167: + options.getPubrevision()
168: + ": bad revision found in ivy file (Revision: "
169: + md.getModuleRevisionId()
170: .getRevision()
171: + "). Use forcedeliver or update.");
172: }
173: } else {
174: md.setResolvedModuleRevisionId(pubmrid);
175: }
176: } catch (MalformedURLException e) {
177: throw new RuntimeException(
178: "malformed url obtained for file " + ivyFile);
179: } catch (ParseException e) {
180: throw new IllegalStateException("bad ivy file for " + mrid
181: + ": " + ivyFile + ": " + e);
182: }
183:
184: DependencyResolver resolver = settings
185: .getResolver(resolverName);
186: if (resolver == null) {
187: throw new IllegalArgumentException("unknown resolver "
188: + resolverName);
189: }
190:
191: // collect all declared artifacts of this module
192: Collection missing = publish(md, srcArtifactPattern, resolver,
193: options);
194: Message.verbose("\tpublish done ("
195: + (System.currentTimeMillis() - start) + "ms)");
196: return missing;
197: }
198:
199: public Collection publish(ModuleDescriptor md,
200: Collection srcArtifactPattern, DependencyResolver resolver,
201: PublishOptions options) throws IOException {
202: Collection missing = new ArrayList();
203: Set artifactsSet = new HashSet();
204: String[] confs = options.getConfs();
205: if (confs == null
206: || (confs.length == 1 && "*".equals(confs[0]))) {
207: confs = md.getConfigurationsNames();
208: }
209:
210: for (int i = 0; i < confs.length; i++) {
211: Artifact[] artifacts = md.getArtifacts(confs[i]);
212: for (int j = 0; j < artifacts.length; j++) {
213: artifactsSet.add(artifacts[j]);
214: }
215: }
216: Artifact[] extraArtifacts = options.getExtraArtifacts();
217: if (extraArtifacts != null) {
218: for (int i = 0; i < extraArtifacts.length; i++) {
219: artifactsSet.add(new MDArtifact(md, extraArtifacts[i]
220: .getName(), extraArtifacts[i].getType(),
221: extraArtifacts[i].getExt(), extraArtifacts[i]
222: .getUrl(), extraArtifacts[i]
223: .getExtraAttributes()));
224: }
225: }
226: boolean successfullyPublished = false;
227: try {
228: resolver.beginPublishTransaction(md.getModuleRevisionId(),
229: options.isOverwrite());
230: // for each declared published artifact in this descriptor, do:
231: for (Iterator iter = artifactsSet.iterator(); iter
232: .hasNext();) {
233: Artifact artifact = (Artifact) iter.next();
234: // copy the artifact using src patterns and resolver
235: boolean published = false;
236: for (Iterator iterator = srcArtifactPattern.iterator(); iterator
237: .hasNext()
238: && !published;) {
239: String pattern = (String) iterator.next();
240: published = publish(artifact, settings
241: .substitute(pattern), resolver, options
242: .isOverwrite());
243: }
244: if (!published) {
245: Message.info("missing artifact " + artifact + ":");
246: for (Iterator iterator = srcArtifactPattern
247: .iterator(); iterator.hasNext();) {
248: String pattern = (String) iterator.next();
249: Message.info("\t"
250: + new File(IvyPatternHelper.substitute(
251: pattern, artifact))
252: + " file does not exist");
253: }
254: missing.add(artifact);
255: }
256: }
257: if (options.getSrcIvyPattern() != null) {
258: Artifact artifact = MDArtifact.newIvyArtifact(md);
259: if (!publish(artifact, options.getSrcIvyPattern(),
260: resolver, options.isOverwrite())) {
261: Message
262: .info("missing ivy file for "
263: + md.getModuleRevisionId()
264: + ": "
265: + new File(
266: IvyPatternHelper
267: .substitute(
268: options
269: .getSrcIvyPattern(),
270: artifact))
271: + " file does not exist");
272: missing.add(artifact);
273: }
274: }
275: resolver.commitPublishTransaction();
276: successfullyPublished = true;
277: } finally {
278: if (!successfullyPublished) {
279: resolver.abortPublishTransaction();
280: }
281: }
282: return missing;
283: }
284:
285: private boolean publish(Artifact artifact,
286: String srcArtifactPattern, DependencyResolver resolver,
287: boolean overwrite) throws IOException {
288: File src = new File(IvyPatternHelper.substitute(
289: srcArtifactPattern, artifact));
290:
291: IvyContext.getContext().checkInterrupted();
292: //notify triggers that an artifact is about to be published
293: eventManager.fireIvyEvent(new StartArtifactPublishEvent(
294: resolver, artifact, src, overwrite));
295: boolean successful = false; //set to true once the publish succeeds
296: try {
297: if (src.exists()) {
298: resolver.publish(artifact, src, overwrite);
299: successful = true;
300: }
301: return successful;
302: } finally {
303: //notify triggers that the publish is finished, successfully or not.
304: eventManager.fireIvyEvent(new EndArtifactPublishEvent(
305: resolver, artifact, src, overwrite, successful));
306: }
307: }
308: }
|