Index: ivy-2.3.x/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java =================================================================== --- ivy-2.3.x/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java (revision 1379683) +++ ivy-2.3.x/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java (working copy) @@ -65,6 +65,7 @@ import org.apache.ivy.plugins.resolver.ChainResolver.ResolvedModuleRevisionArtifactInfo; import org.apache.ivy.plugins.resolver.util.HasLatestStrategy; import org.apache.ivy.plugins.resolver.util.ResolvedResource; +import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Checks; import org.apache.ivy.util.Message; @@ -581,6 +582,10 @@ return AbstractResolver.this.getSettings().getMatcher(matcherName); } + public VersionMatcher getVersionMatcher() { + return AbstractResolver.this.getSettings().getVersionMatcher(); + } + public Namespace getNamespace(String namespace) { return AbstractResolver.this.getSettings().getNamespace(namespace); } Index: ivy-2.3.x/src/java/org/apache/ivy/plugins/parser/ParserSettings.java =================================================================== --- ivy-2.3.x/src/java/org/apache/ivy/plugins/parser/ParserSettings.java (revision 1379683) +++ ivy-2.3.x/src/java/org/apache/ivy/plugins/parser/ParserSettings.java (working copy) @@ -29,6 +29,7 @@ import org.apache.ivy.plugins.matcher.PatternMatcher; import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.resolver.DependencyResolver; +import org.apache.ivy.plugins.version.VersionMatcher; public interface ParserSettings { @@ -42,6 +43,8 @@ PatternMatcher getMatcher(String matcherName); + VersionMatcher getVersionMatcher(); + Namespace getNamespace(String namespace); StatusManager getStatusManager(); Index: ivy-2.3.x/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java =================================================================== --- ivy-2.3.x/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java (revision 1379683) +++ ivy-2.3.x/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java (working copy) @@ -26,6 +26,7 @@ import java.net.URL; import java.text.ParseException; import java.util.Arrays; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; @@ -71,13 +72,15 @@ import org.apache.ivy.plugins.repository.url.URLResource; import org.apache.ivy.plugins.resolver.DependencyResolver; import org.apache.ivy.plugins.resolver.FileSystemResolver; -import org.apache.ivy.util.FileUtil; +import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.DateUtil; +import org.apache.ivy.util.FileUtil; import org.apache.ivy.util.Message; import org.apache.ivy.util.XMLHelper; import org.apache.ivy.util.extendable.ExtendableItemHelper; import org.xml.sax.Attributes; import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; /** * Parses an xml ivy file and output a ModuleDescriptor. For dependency and performance reasons, it @@ -175,6 +178,66 @@ } } + private static class MinimalParentParser extends DefaultHandler { + private ModuleRevisionId mrid; + + /* how and what do we have to parse */ + private ParserSettings settings; + + private URL descriptorURL; + + private MinimalParentParser(ParserSettings ivySettings) { + settings = ivySettings; + } + + private void parse() throws ParseException, IOException { + try { + XMLHelper.parse(descriptorURL, null, this); + } catch (ParserConfigurationException ex) { + IllegalStateException ise = new IllegalStateException(ex.getMessage() + " in " + + descriptorURL); + ise.initCause(ex); + throw ise; + } catch (Exception ex) { + ParseException pe = new ParseException(ex.getMessage() + " in " + descriptorURL, 0); + pe.initCause(ex); + throw pe; + } + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + try { + if ("info".equals(qName)) { + infoStarted(attributes); + } + } catch (Exception ex) { + if (ex instanceof SAXException) { + throw (SAXException) ex; + } + SAXException sax = new SAXException("Problem occurred while parsing ivy file: " + + ex.getMessage(), ex); + sax.initCause(ex); + throw sax; + } + } + + private void infoStarted(Attributes attributes) { + String org = settings.substitute(attributes.getValue("organisation")); + String module = settings.substitute(attributes.getValue("module")); + String revision = settings.substitute(attributes.getValue("revision")); + mrid = ModuleRevisionId.newInstance(org, module, revision); + } + + private ModuleRevisionId getModuleRevisionId() { + return mrid; + } + + private void setInput(URL descriptorURL) { + this.descriptorURL = descriptorURL; + } + } + public static class Parser extends AbstractParser { public static final class State { public static final int NONE = 0; @@ -618,14 +681,57 @@ Message.verbose("Parent module doesn't exist on the filesystem: " + file.getAbsolutePath()); return null; } - + + if (!isExpectedParentInLocation(parentMrid, file)) { + return null; + } + // else FileSystemResolver parentModuleResolver = new FileSystemResolver(); parentModuleResolver.setName(getModuleInheritanceRepositoryParentResolverName(parentMrid)); parentModuleResolver.addIvyPattern(file.getAbsolutePath()); parentModuleResolver.setSettings(IvyContext.getContext().getSettings()); + IvyContext.getContext().getSettings().addResolver(parentModuleResolver); return parentModuleResolver; } + private boolean isExpectedParentInLocation(ModuleRevisionId expectedParentMrid, File file) { + try { + ModuleRevisionId actualParentMrid = parseModuleRevisionIdFromDescriptor(settings, + file.toURL()); + if (expectedParentMrid.getModuleId().equals(actualParentMrid.getModuleId())) { + VersionMatcher versionMatcher = settings.getVersionMatcher(); + if (versionMatcher.accept(expectedParentMrid, actualParentMrid)) { + return true; + } + } + // else + Object[] args = new Object[] {file.getAbsolutePath(), expectedParentMrid, + actualParentMrid}; + String message = String + .format( + "Unexpected ModuleRevisionId found for parent module at source location %1$s. Expected: %2$s. Actual: %3$s. Not attempting to parse the parent using the path specified by the extends@location attribute. Instead only locating the published parent through a regular resolver.", + args); + Message.info(message); + return false; + } catch (Throwable t) { + Object[] args = new Object[] {file.getAbsolutePath(), expectedParentMrid, t}; + String message = String + .format( + "Exception caught while trying to parse parent module at source location %1$s. Not attempting to parse the parent using the path specified by the extends@location attribute. Instead only locating the published parent through a regular resolver. Expected ModuleRevisionId: %2$s. Exception: %3$s.", + args); + Message.info(message); + return false; + } + } + + private ModuleRevisionId parseModuleRevisionIdFromDescriptor(ParserSettings ivySettings, + URL xmlURL) throws ParseException, IOException { + MinimalParentParser parser = new MinimalParentParser(ivySettings); + parser.setInput(xmlURL); + parser.parse(); + return parser.getModuleRevisionId(); + } + /** * Describe how to parse a {@link ModuleDescriptor} by asking repositories * @param parentMrid a given {@link ModuleRevisionId} to find Index: ivy-2.3.x/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java =================================================================== --- ivy-2.3.x/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java (revision 1379683) +++ ivy-2.3.x/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java (working copy) @@ -33,6 +33,7 @@ import org.apache.ivy.plugins.namespace.Namespace; import org.apache.ivy.plugins.parser.ParserSettings; import org.apache.ivy.plugins.resolver.DependencyResolver; +import org.apache.ivy.plugins.version.VersionMatcher; import org.apache.ivy.util.Message; /** @@ -122,6 +123,10 @@ public StatusManager getStatusManager() { return delegatedSettings.getStatusManager(); } + + public VersionMatcher getVersionMatcher() { + return delegatedSettings.getVersionMatcher(); + } public File resolveFile(String filename) { return delegatedSettings.resolveFile(filename);