blob: 66ce7d91465dca1c9599417b0685b14fa1cf4510 [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.core.deliver;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.ivy.core.IvyPatternHelper;
import org.apache.ivy.core.cache.ResolutionCacheManager;
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.plugins.parser.xml.UpdateOptions;
import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorUpdater;
import org.apache.ivy.plugins.report.XmlReportParser;
import org.apache.ivy.plugins.repository.Resource;
import org.apache.ivy.util.ConfigurationUtils;
import org.apache.ivy.util.Message;
import org.xml.sax.SAXException;
public class DeliverEngine {
private DeliverEngineSettings settings;
public DeliverEngine(DeliverEngineSettings settings) {
this.settings = settings;
}
/**
* Delivers a resolved ivy file based upon last resolve call status. If resolve report file
* cannot be found in cache, then it throws an IllegalStateException (maybe resolve has not been
* called before ?).
*
* @param revision
* the revision to which the module should be delivered
* @param destIvyPattern
* the pattern to which the delivered ivy file should be written
* @param options
* the options with which deliver should be done
* @throws IOException if something goes wrong
* @throws ParseException if something goes wrong
*/
public void deliver(String revision, String destIvyPattern, DeliverOptions options)
throws IOException, ParseException {
String resolveId = options.getResolveId();
if (resolveId == null) {
throw new IllegalArgumentException("A resolveId must be specified for delivering.");
}
File[] files = getCache().getConfigurationResolveReportsInCache(resolveId);
if (files.length == 0) {
throw new IllegalStateException("No previous resolve found for id '" + resolveId
+ "' Please resolve dependencies before delivering.");
}
XmlReportParser parser = new XmlReportParser();
parser.parse(files[0]);
ModuleRevisionId mrid = parser.getResolvedModule();
deliver(mrid, revision, destIvyPattern, options);
}
private ResolutionCacheManager getCache() {
return settings.getResolutionCacheManager();
}
/**
* Delivers a resolved ivy file based upon last resolve call status. If resolve report file
* cannot be found in cache, then it throws an IllegalStateException (maybe resolve has not been
* called before ?).
*
* @param mrid
* the module revision id of the module to deliver
* @param revision
* the revision to which the module should be delivered
* @param destIvyPattern
* the pattern to which the delivered ivy file should be written
* @param options
* the options with which deliver should be done
* @throws IOException if something goes wrong
* @throws ParseException if something goes wrong
*/
public void deliver(ModuleRevisionId mrid, String revision, String destIvyPattern,
DeliverOptions options) throws IOException, ParseException {
Message.info(":: delivering :: " + mrid + " :: " + revision + " :: " + options.getStatus()
+ " :: " + options.getPubdate());
Message.verbose("\toptions = " + options);
long start = System.currentTimeMillis();
destIvyPattern = settings.substitute(destIvyPattern);
// 1) find the resolved module descriptor in cache
ModuleDescriptor md = getCache().getResolvedModuleDescriptor(mrid);
md.setResolvedModuleRevisionId(ModuleRevisionId.newInstance(md.getModuleRevisionId(),
options.getPubBranch() == null ? mrid.getBranch() : options.getPubBranch(), revision));
md.setResolvedPublicationDate(options.getPubdate());
// 2) parse resolvedRevisions From properties file
Map<ModuleRevisionId, String> resolvedRevisions = new HashMap<>(); // Map (ModuleId -> String revision)
Map<ModuleRevisionId, String> resolvedBranches = new HashMap<>(); // Map (ModuleId -> String branch)
Map<ModuleRevisionId, String> dependenciesStatus = new HashMap<>(); // Map (ModuleId -> String status)
File ivyProperties = getCache().getResolvedIvyPropertiesInCache(mrid);
if (!ivyProperties.exists()) {
throw new IllegalStateException("ivy properties not found in cache for " + mrid
+ "; please resolve dependencies before delivering!");
}
Properties props = new Properties();
FileInputStream in = new FileInputStream(ivyProperties);
props.load(in);
in.close();
for (Object o : props.keySet()) {
String depMridStr = (String) o;
String[] parts = props.getProperty(depMridStr).split(" ");
ModuleRevisionId decodedMrid = ModuleRevisionId.decode(depMridStr);
if (options.isResolveDynamicRevisions()) {
resolvedRevisions.put(decodedMrid, parts[0]);
if (parts.length >= 4) {
if (parts[3] != null && !"null".equals(parts[3])) {
resolvedBranches.put(decodedMrid, parts[3]);
}
}
}
dependenciesStatus.put(decodedMrid, parts[1]);
if (options.isReplaceForcedRevisions()) {
if (parts.length <= 2) {
// maybe the properties file was generated by an older Ivy version
// so it is possible that this part doesn't exist.
throw new IllegalStateException("ivy properties file generated by an older"
+ " version of Ivy which doesn't support replacing forced revisions!");
}
resolvedRevisions.put(decodedMrid, parts[2]);
}
}
// 3) use pdrResolver to resolve dependencies info
Map<ModuleRevisionId, String> resolvedDependencies = new HashMap<>();
// Map (ModuleRevisionId -> String revision)
for (DependencyDescriptor dependency : md.getDependencies()) {
String rev = resolvedRevisions.get(dependency.getDependencyRevisionId());
if (rev == null) {
rev = dependency.getDependencyRevisionId().getRevision();
}
String bra = resolvedBranches.get(dependency.getDependencyRevisionId());
if (bra == null || "null".equals(bra)) {
bra = dependency.getDependencyRevisionId().getBranch();
}
String depStatus = dependenciesStatus.get(dependency.getDependencyRevisionId());
ModuleRevisionId mrid2 = (bra == null)
? ModuleRevisionId.newInstance(dependency.getDependencyRevisionId(), rev)
: ModuleRevisionId.newInstance(dependency.getDependencyRevisionId(), bra, rev);
resolvedDependencies.put(dependency.getDependencyRevisionId(),
options.getPdrResolver().resolve(md, options.getStatus(), mrid2, depStatus));
}
// 4) copy the source resolved ivy to the destination specified,
// updating status, revision and dependency revisions obtained by
// PublishingDependencyRevisionResolver
File publishedIvy = settings.resolveFile(IvyPatternHelper.substitute(destIvyPattern,
md.getResolvedModuleRevisionId()));
Message.info("\tdelivering ivy file to " + publishedIvy);
String[] confs = ConfigurationUtils.replaceWildcards(options.getConfs(), md);
Set<String> confsToRemove = new HashSet<>(Arrays.asList(md.getConfigurationsNames()));
confsToRemove.removeAll(Arrays.asList(confs));
try {
UpdateOptions opts = new UpdateOptions()
.setSettings(settings)
.setResolvedRevisions(resolvedDependencies)
.setStatus(options.getStatus())
.setRevision(revision)
.setBranch(options.getPubBranch())
.setPubdate(options.getPubdate())
.setGenerateRevConstraint(options.isGenerateRevConstraint())
.setMerge(options.isMerge())
.setMergedDescriptor(md)
.setConfsToExclude(
confsToRemove.toArray(new String[confsToRemove.size()]));
if (!resolvedBranches.isEmpty()) {
opts = opts.setResolvedBranches(resolvedBranches);
}
Resource res = md.getResource();
XmlModuleDescriptorUpdater.update(res.openStream(), res, publishedIvy, opts);
} catch (SAXException ex) {
throw new RuntimeException("bad ivy file in cache for " + mrid, ex);
}
Message.verbose("\tdeliver done (" + (System.currentTimeMillis() - start) + "ms)");
}
}