diff --git a/CHANGES.txt b/CHANGES.txt index 157dfbf1..13f26c5b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -67,7 +67,7 @@ for detailed view of each issue, please consult http://issues.apache.org/jira/br ===================================== - NEW: Retain original dependency constraint rules in resolved ivy file (IVY-739) - NEW: Add a new resolve mode (optionally per module) to utilize dynamic constraint rule metadata (IVY-740) -- NEW: Add transitive dependency version and branch override mechanism (IVY-784) (not completed yet) +- NEW: Add transitive dependency version and branch override mechanism (IVY-784) - IMPROVEMENT: Make Ivy standalone runnable with no required dependencies (IVY-757) - IMPROVEMENT: add branch attribute in ivy:install task (IVY-727) @@ -81,7 +81,7 @@ for detailed view of each issue, please consult http://issues.apache.org/jira/br - FIX: multiple cleancache and inline retrieve error (IVY-778) - FIX: buildlist evicts modules with the same name, but different organisation (IVY-731) - FIX: Out of memory/Stack overflow for new highly coupled project (IVY-595) -- FIX: Compatibility with maven's dependencyMangement (IVY-753) (not completed yet) +- FIX: Compatibility with maven's dependencyMangement (IVY-753) - FIX: ivy:settings fails when override is not set to 'true' (IVY-771) - FIX: NPE when specifying both resolveId and inline in an Ivy:Resolve (IVY-776) - FIX: repreport task not working against a repository structured by branches (IVY-716) diff --git a/doc/ivyfile/conflict.html b/doc/ivyfile/conflict.html new file mode 100644 index 00000000..edc4b498 --- /dev/null +++ b/doc/ivyfile/conflict.html @@ -0,0 +1,66 @@ + + + + + + + + + + + + + diff --git a/doc/ivyfile/conflicts.html b/doc/ivyfile/conflicts.html index 537e5f48..2612b963 100644 --- a/doc/ivyfile/conflicts.html +++ b/doc/ivyfile/conflicts.html @@ -27,6 +27,8 @@ + + + diff --git a/doc/toc.json b/doc/toc.json index 33840f8b..a0424a9b 100644 --- a/doc/toc.json +++ b/doc/toc.json @@ -546,6 +546,20 @@ "children": [ ] + }, + { + "id":"ivyfile/override", + "title":"override", + "children": [ + + ] + }, + { + "id":"ivyfile/conflict", + "title":"conflict", + "children": [ + + ] } ] }, diff --git a/src/java/org/apache/ivy/core/module/descriptor/DefaultModuleDescriptor.java b/src/java/org/apache/ivy/core/module/descriptor/DefaultModuleDescriptor.java index 45c98e24..00eea95d 100644 --- a/src/java/org/apache/ivy/core/module/descriptor/DefaultModuleDescriptor.java +++ b/src/java/org/apache/ivy/core/module/descriptor/DefaultModuleDescriptor.java @@ -36,8 +36,10 @@ import java.util.Stack; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; +import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.core.module.status.StatusManager; import org.apache.ivy.plugins.conflict.ConflictManager; +import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.plugins.matcher.MatcherHelper; import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.NameSpaceHelper; @@ -159,8 +161,9 @@ public class DefaultModuleDescriptor implements ModuleDescriptor { nmd.setDefault(md.isDefault()); if (md instanceof DefaultModuleDescriptor) { DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) md; - nmd.conflictManagers.putAll(dmd.conflictManagers); - nmd.dependencyDescriptorMediators.putAll(dmd.dependencyDescriptorMediators); + nmd.conflictManagers = (ModuleRules) dmd.conflictManagers.clone(); + nmd.dependencyDescriptorMediators = + (ModuleRules) dmd.dependencyDescriptorMediators.clone(); } else { Message.warn( "transformed module descriptor is not a default module descriptor: " @@ -199,10 +202,9 @@ public class DefaultModuleDescriptor implements ModuleDescriptor { private boolean isDefault = false; - private Map conflictManagers = new LinkedHashMap(); // Map (ModuleId -> ) + private ModuleRules conflictManagers = new ModuleRules(); - private Map/**/ dependencyDescriptorMediators - = new LinkedHashMap(); + private ModuleRules dependencyDescriptorMediators = new ModuleRules(); private List licenses = new ArrayList(); // List(License) @@ -438,21 +440,6 @@ public class DefaultModuleDescriptor implements ModuleDescriptor { isDefault = b; } - private static class ModuleIdMatcher { - private PatternMatcher matcher; - - private ModuleId mid; - - public ModuleIdMatcher(PatternMatcher matcher, ModuleId mid) { - this.matcher = matcher; - this.mid = mid; - } - - public boolean matches(ModuleId mid) { - return MatcherHelper.matches(matcher, this.mid, mid); - } - } - /** * regular expressions as explained in Pattern class may be used in ModuleId organisation and * name @@ -463,35 +450,31 @@ public class DefaultModuleDescriptor implements ModuleDescriptor { */ public void addConflictManager(ModuleId moduleId, PatternMatcher matcher, ConflictManager manager) { - conflictManagers.put(new ModuleIdMatcher(matcher, moduleId), manager); + conflictManagers.defineRule(new MapMatcher(moduleId.getAttributes(), matcher), manager); } public ConflictManager getConflictManager(ModuleId moduleId) { - for (Iterator iter = conflictManagers.keySet().iterator(); iter.hasNext();) { - ModuleIdMatcher matcher = (ModuleIdMatcher) iter.next(); - if (matcher.matches(moduleId)) { - return (ConflictManager) conflictManagers.get(matcher); - } - } - return null; + return (ConflictManager) conflictManagers.getRule(moduleId); } public void addDependencyDescriptorMediator(ModuleId moduleId, PatternMatcher matcher, DependencyDescriptorMediator ddm) { - dependencyDescriptorMediators.put(new ModuleIdMatcher(matcher, moduleId), ddm); + dependencyDescriptorMediators.defineRule( + new MapMatcher(moduleId.getAttributes(), matcher), ddm); } public DependencyDescriptor mediate(DependencyDescriptor dd) { - for (Iterator iter = dependencyDescriptorMediators.keySet().iterator(); iter.hasNext();) { - ModuleIdMatcher matcher = (ModuleIdMatcher) iter.next(); - if (matcher.matches(dd.getDependencyId())) { - dd = ((DependencyDescriptorMediator) dependencyDescriptorMediators.get(matcher)) - .mediate(dd); - } + Object[] mediators = dependencyDescriptorMediators.getRules(dd.getDependencyId()); + for (int i = 0; i < mediators.length; i++) { + dd = ((DependencyDescriptorMediator) mediators[i]).mediate(dd); } return dd; } + public ModuleRules/**/ getAllDependencyDescriptorMediators() { + return (ModuleRules) dependencyDescriptorMediators.clone(); + } + public void addLicense(License license) { licenses.add(license); } diff --git a/src/java/org/apache/ivy/core/module/descriptor/ModuleDescriptor.java b/src/java/org/apache/ivy/core/module/descriptor/ModuleDescriptor.java index 5debb2cf..dcdb3ee1 100644 --- a/src/java/org/apache/ivy/core/module/descriptor/ModuleDescriptor.java +++ b/src/java/org/apache/ivy/core/module/descriptor/ModuleDescriptor.java @@ -26,6 +26,7 @@ import java.util.Map; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleId; import org.apache.ivy.core.module.id.ModuleRevisionId; +import org.apache.ivy.core.module.id.ModuleRules; import org.apache.ivy.plugins.conflict.ConflictManager; import org.apache.ivy.plugins.latest.ArtifactInfo; import org.apache.ivy.plugins.parser.ModuleDescriptorParser; @@ -222,6 +223,18 @@ public interface ModuleDescriptor * @return an array of {@link ExcludeRule} this module descriptor holds */ public ExcludeRule[] getAllExcludeRules(); + + /** + * Returns all the dependency descriptor mediators used by this {@link ModuleDescriptor}, as an + * instance of {@link ModuleRules}. + *

+ * All rules in the {@link ModuleRules} object returned are + * {@link DependencyDescriptorMediator}. + *

+ * + * @return all the dependency descriptor mediators used by this {@link ModuleDescriptor}. + */ + public ModuleRules/**/ getAllDependencyDescriptorMediators(); /** * Returns the list of xml namespaces used by extra attributes, as Map from prefix to namespace diff --git a/src/java/org/apache/ivy/core/module/id/ModuleId.java b/src/java/org/apache/ivy/core/module/id/ModuleId.java index 70f4d548..b55af1fd 100644 --- a/src/java/org/apache/ivy/core/module/id/ModuleId.java +++ b/src/java/org/apache/ivy/core/module/id/ModuleId.java @@ -17,11 +17,14 @@ */ package org.apache.ivy.core.module.id; +import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.ivy.core.IvyPatternHelper; + /** * Identifies a module, without revision information * @@ -70,6 +73,8 @@ public class ModuleId implements Comparable { private String name; private int hash; + + private Map/**/ attributes = new HashMap(); /** * Constructor. @@ -82,6 +87,8 @@ public class ModuleId implements Comparable { } this.organisation = organisation; this.name = name; + attributes.put(IvyPatternHelper.ORGANISATION_KEY, organisation); + attributes.put(IvyPatternHelper.MODULE_KEY, name); } /** @@ -147,6 +154,17 @@ public class ModuleId implements Comparable { public String encodeToString() { return getOrganisation() + ENCODE_SEPARATOR + getName(); } + + /** + * Returns a Map of all attributes of this module id. + * The Map keys are attribute names as Strings, and values are corresponding attribute values + * (as String too). + * + * @return A Map instance containing all the attributes and their values. + */ + public Map getAttributes() { + return attributes; + } /** * Returns a ModuleId diff --git a/src/java/org/apache/ivy/core/module/id/ModuleRules.java b/src/java/org/apache/ivy/core/module/id/ModuleRules.java index c53ddf04..edec1e38 100644 --- a/src/java/org/apache/ivy/core/module/id/ModuleRules.java +++ b/src/java/org/apache/ivy/core/module/id/ModuleRules.java @@ -17,8 +17,11 @@ */ package org.apache.ivy.core.module.id; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import org.apache.ivy.plugins.matcher.MapMatcher; @@ -49,6 +52,16 @@ import org.apache.ivy.util.filter.NoFilter; public class ModuleRules { private Map/**/ rules = new LinkedHashMap(); + /** + * Constructs an empty ModuleRules. + */ + public ModuleRules() { + } + + private ModuleRules(Map/**/ rules) { + this.rules = new LinkedHashMap(rules); + } + /** * Defines a new rule for the given condition. * @@ -64,6 +77,34 @@ public class ModuleRules { rules.put(condition, rule); } + /** + * Returns the rule object matching the given {@link ModuleId}, or null + * if no rule applies. + * + * @param mid + * the {@link ModuleId} to search the rule for. + * Must not be null. + * @return the rule object matching the given {@link ModuleId}, or null + * if no rule applies. + * @see #getRule(ModuleId, Filter) + */ + public Object getRule(ModuleId mid) { + return getRule(mid, NoFilter.INSTANCE); + } + + /** + * Returns the rules objects matching the given {@link ModuleId}, or an empty array + * if no rule applies. + * + * @param mid + * the {@link ModuleId} to search the rule for. + * Must not be null. + * @return an array of rule objects matching the given {@link ModuleId}. + */ + public Object[] getRules(ModuleId mid) { + return getRules(new ModuleRevisionId(mid, "", ""), NoFilter.INSTANCE); + } + /** * Returns the rule object matching the given {@link ModuleRevisionId}, or null * if no rule applies. @@ -132,6 +173,36 @@ public class ModuleRules { return null; } + /** + * Returns the rules object matching the given {@link ModuleRevisionId} and accepted by the + * given {@link Filter}, or an empty array if no rule applies. + * + * @param mrid + * the {@link ModuleRevisionId} to search the rule for. + * Must not be null. + * @param filter + * the filter to use to filter the rule to return. The {@link Filter#accept(Object)} + * method will be called only with rule objects matching the given + * {@link ModuleRevisionId}. Must not be null. + * @return an array of rule objects matching the given {@link ModuleRevisionId}. + */ + public Object[] getRules(ModuleRevisionId mrid, Filter filter) { + Checks.checkNotNull(mrid, "mrid"); + Checks.checkNotNull(filter, "filter"); + + List matchingRules = new ArrayList(); + for (Iterator iter = rules.keySet().iterator(); iter.hasNext();) { + MapMatcher midm = (MapMatcher) iter.next(); + if (midm.matches(mrid.getAttributes())) { + Object rule = rules.get(midm); + if (filter.accept(rule)) { + matchingRules.add(rule); + } + } + } + return matchingRules.toArray(); + } + /** * Dump the list of rules to {@link Message#debug(String)} * @@ -149,5 +220,21 @@ public class ModuleRules { } } } + + /** + * Returns an unmodifiable view of all the rules defined on this ModuleRules. + *

+ * The rules are returned in a Map where they keys are the MapMatchers matching the rules + * object, and the values are the rules object themselves. + *

+ * + * @return an unmodifiable view of all the rules defined on this ModuleRules. + */ + public Map/**/ getAllRules() { + return Collections.unmodifiableMap(rules); + } + public Object clone() { + return new ModuleRules(rules); + } } diff --git a/src/java/org/apache/ivy/plugins/matcher/MapMatcher.java b/src/java/org/apache/ivy/plugins/matcher/MapMatcher.java index 015feb39..425ac37c 100644 --- a/src/java/org/apache/ivy/plugins/matcher/MapMatcher.java +++ b/src/java/org/apache/ivy/plugins/matcher/MapMatcher.java @@ -17,6 +17,7 @@ */ package org.apache.ivy.plugins.matcher; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -55,4 +56,12 @@ public class MapMatcher { public String toString() { return attributes + " (" + pm.getName() + ")"; } + + public Map getAttributes() { + return Collections.unmodifiableMap(attributes); + } + + public PatternMatcher getPatternMatcher() { + return pm; + } } diff --git a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java index 10665161..42156f7e 100644 --- a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java +++ b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java @@ -185,8 +185,6 @@ public final class XmlModuleDescriptorParser extends AbstractModuleDescriptorPar private static final int EXTRA_INFO = 12; - private static final int HINTS = 13; - private int state = NONE; private final URL xmlURL; @@ -307,20 +305,13 @@ public final class XmlModuleDescriptorParser extends AbstractModuleDescriptorPar } state = CONFLICT; checkConfigurations(); - } else if ("hints".equals(qName)) { - state = HINTS; } else if ("artifact".equals(qName)) { artifactStarted(qName, attributes); } else if ("include".equals(qName) && state == DEP) { addIncludeRule(qName, attributes); } else if ("exclude".equals(qName) && state == DEP) { addExcludeRule(qName, attributes); - } else if ("exclude".equals(qName) && (state == DEPS || state == HINTS)) { - if (state == DEPS) { - Message.deprecated( - "using exclude directly under dependencies is deprecated: " - + "please use hints section. Ivy file URL: " + xmlURL); - } + } else if ("exclude".equals(qName) && state == DEPS) { state = EXCLUDE; parseRule(qName, attributes); getMd().addExcludeRule((ExcludeRule) confAware); @@ -331,10 +322,10 @@ public final class XmlModuleDescriptorParser extends AbstractModuleDescriptorPar } else if ("mapped".equals(qName)) { dd.addDependencyConfiguration(conf, ivy.substitute(attributes .getValue("name"))); - } else if (("conflict".equals(qName) && state == HINTS) + } else if (("conflict".equals(qName) && state == DEPS) || "manager".equals(qName) && state == CONFLICT) { managerStarted(attributes, state == CONFLICT ? "name" : "manager"); - } else if ("override".equals(qName) && state == HINTS) { + } else if ("override".equals(qName) && state == DEPS) { mediationOverrideStarted(attributes); } else if ("include".equals(qName) && state == CONF) { includeConfStarted(attributes); @@ -808,8 +799,6 @@ public final class XmlModuleDescriptorParser extends AbstractModuleDescriptorPar } } confAware = null; - state = HINTS; - } else if ("hints".equals(qName) && state == HINTS) { state = DEPS; } else if ("dependency".equals(qName) && state == DEP) { if (dd.getModuleConfigurations().length == 0) { diff --git a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java index 23e3a439..04b34dd2 100644 --- a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java +++ b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java @@ -28,14 +28,19 @@ import java.util.Map; import java.util.Map.Entry; import org.apache.ivy.Ivy; +import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.core.module.descriptor.Artifact; import org.apache.ivy.core.module.descriptor.Configuration; import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; +import org.apache.ivy.core.module.descriptor.DependencyDescriptorMediator; import org.apache.ivy.core.module.descriptor.ExcludeRule; import org.apache.ivy.core.module.descriptor.IncludeRule; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; +import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator; +import org.apache.ivy.plugins.matcher.MapMatcher; +import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.apache.ivy.util.extendable.ExtendableItem; @@ -150,23 +155,55 @@ public final class XmlModuleDescriptorWriter { out.println("\t\t"); } } - boolean hasHints = md.getAllExcludeRules().length > 0; - if (hasHints) { - out.println("\t\t"); - } printAllExcludes(md, out); - if (hasHints) { - out.println("\t\t"); - } + printAllMediators(md, out); out.println("\t"); } } + private static void printAllMediators(ModuleDescriptor md, PrintWriter out) { + Map/**/ mediators + = md.getAllDependencyDescriptorMediators().getAllRules(); + + for (Iterator iterator = mediators.entrySet().iterator(); iterator.hasNext();) { + Map.Entry mediatorRule = (Map.Entry) iterator.next(); + MapMatcher matcher = (MapMatcher) mediatorRule.getKey(); + DependencyDescriptorMediator mediator = + (DependencyDescriptorMediator) mediatorRule.getValue(); + + if (mediator instanceof OverrideDependencyDescriptorMediator) { + OverrideDependencyDescriptorMediator oddm = + (OverrideDependencyDescriptorMediator) mediator; + + out.print("\t\t"); + } else { + Message.verbose("ignoring unhandled DependencyDescriptorMediator: " + + mediator.getClass()); + } + } + } + private static void printAllExcludes(ModuleDescriptor md, PrintWriter out) { ExcludeRule[] excludes = md.getAllExcludeRules(); if (excludes.length > 0) { for (int j = 0; j < excludes.length; j++) { - out.print("\t\t\t - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/test/java/org/apache/ivy/plugins/parser/xml/test-update-withvar.xml b/test/java/org/apache/ivy/plugins/parser/xml/test-update-withvar.xml index e66517cb..569bd4c4 100644 --- a/test/java/org/apache/ivy/plugins/parser/xml/test-update-withvar.xml +++ b/test/java/org/apache/ivy/plugins/parser/xml/test-update-withvar.xml @@ -101,12 +101,10 @@ - - - - - - - + + + + + diff --git a/test/java/org/apache/ivy/plugins/parser/xml/test-update.xml b/test/java/org/apache/ivy/plugins/parser/xml/test-update.xml index 680f1883..7c86e6d0 100644 --- a/test/java/org/apache/ivy/plugins/parser/xml/test-update.xml +++ b/test/java/org/apache/ivy/plugins/parser/xml/test-update.xml @@ -101,12 +101,10 @@ - - - - - - - + + + + + diff --git a/test/java/org/apache/ivy/plugins/parser/xml/test-write-full.xml b/test/java/org/apache/ivy/plugins/parser/xml/test-write-full.xml index cb4f5cd4..be3548f3 100644 --- a/test/java/org/apache/ivy/plugins/parser/xml/test-write-full.xml +++ b/test/java/org/apache/ivy/plugins/parser/xml/test-write-full.xml @@ -64,9 +64,8 @@ - - - - + + + diff --git a/test/java/org/apache/ivy/plugins/parser/xml/test.xml b/test/java/org/apache/ivy/plugins/parser/xml/test.xml index a73b9eca..d95492fa 100644 --- a/test/java/org/apache/ivy/plugins/parser/xml/test.xml +++ b/test/java/org/apache/ivy/plugins/parser/xml/test.xml @@ -99,12 +99,10 @@ - - - - - - - + + + + + diff --git a/test/java/org/apache/ivy/plugins/parser/xml/updated.xml b/test/java/org/apache/ivy/plugins/parser/xml/updated.xml index 2c25b7d1..fe7a901e 100644 --- a/test/java/org/apache/ivy/plugins/parser/xml/updated.xml +++ b/test/java/org/apache/ivy/plugins/parser/xml/updated.xml @@ -97,12 +97,10 @@ - - - - - - - + + + + +