You are viewing a plain text version of this content. The canonical link for it is here.
Posted to easyant-commits@incubator.apache.org by hi...@apache.org on 2011/02/17 17:01:56 UTC

svn commit: r1071697 [24/42] - in /incubator/easyant: buildtypes/ buildtypes/trunk/ buildtypes/trunk/build-osgi-bundle-java/ buildtypes/trunk/build-osgi-bundle-java/src/ buildtypes/trunk/build-osgi-bundle-java/src/main/ buildtypes/trunk/build-osgi-bund...

Added: incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r766667.patch
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r766667.patch?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r766667.patch (added)
+++ incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r766667.patch Thu Feb 17 17:01:07 2011
@@ -0,0 +1,677 @@
+Index: src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
+===================================================================
+--- src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java	(révision 772962)
++++ src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java	(copie de travail)
+@@ -31,6 +31,7 @@
+ 
+ import org.apache.ivy.Ivy;
+ import org.apache.ivy.core.IvyContext;
++import org.apache.ivy.core.cache.ResolutionCacheManager;
+ import org.apache.ivy.core.module.descriptor.Configuration;
+ import org.apache.ivy.core.module.descriptor.ConfigurationAware;
+ import org.apache.ivy.core.module.descriptor.DefaultArtifact;
+@@ -40,6 +41,7 @@
+ import org.apache.ivy.core.module.descriptor.DefaultIncludeRule;
+ 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.ExcludeRule;
+ import org.apache.ivy.core.module.descriptor.IncludeRule;
+ import org.apache.ivy.core.module.descriptor.License;
+@@ -49,15 +51,23 @@
+ 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.resolve.ResolveData;
++import org.apache.ivy.core.resolve.ResolveEngine;
++import org.apache.ivy.core.resolve.ResolveOptions;
++import org.apache.ivy.core.resolve.ResolvedModuleRevision;
+ import org.apache.ivy.plugins.conflict.ConflictManager;
+ import org.apache.ivy.plugins.conflict.FixedConflictManager;
+ import org.apache.ivy.plugins.matcher.PatternMatcher;
+ import org.apache.ivy.plugins.namespace.Namespace;
+ import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParser;
+ import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
++import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
+ import org.apache.ivy.plugins.parser.ParserSettings;
+ import org.apache.ivy.plugins.repository.Resource;
+ import org.apache.ivy.plugins.repository.url.URLResource;
++import org.apache.ivy.plugins.resolver.CacheResolver;
++import org.apache.ivy.plugins.resolver.DependencyResolver;
++import org.apache.ivy.plugins.resolver.util.ResolvedResource;
+ import org.apache.ivy.util.Message;
+ import org.apache.ivy.util.XMLHelper;
+ import org.apache.ivy.util.extendable.ExtendableItemHelper;
+@@ -139,14 +149,10 @@
+                 DefaultModuleDescriptor dmd = (DefaultModuleDescriptor) md;
+                 ns = dmd.getNamespace();
+             }
+-            XmlModuleDescriptorUpdater.update(is, res, destFile, 
+-                    new UpdateOptions()
+-                        .setSettings(IvyContext.getContext().getSettings())
+-                        .setStatus(md.getStatus()) 
+-                        .setRevision(md.getResolvedModuleRevisionId().getRevision()) 
+-                        .setPubdate(md.getResolvedPublicationDate())
+-                        .setUpdateBranch(false)
+-                        .setNamespace(ns));
++            XmlModuleDescriptorUpdater.update(is, res, destFile, new UpdateOptions().setSettings(
++                IvyContext.getContext().getSettings()).setStatus(md.getStatus()).setRevision(
++                md.getResolvedModuleRevisionId().getRevision()).setPubdate(
++                md.getResolvedPublicationDate()).setUpdateBranch(false).setNamespace(ns));
+         } catch (SAXException e) {
+             ParseException ex = new ParseException("exception occured while parsing " + res, 0);
+             ex.initCause(e);
+@@ -181,37 +187,48 @@
+             public static final int EXCLUDE = 9;
+ 
+             public static final int DEPS = 10;
+-        
++
+             public static final int DESCRIPTION = 11;
+ 
+             public static final int EXTRA_INFO = 12;
+-            
++
+             private State() {
+             }
+         }
+ 
+-        protected static final List ALLOWED_VERSIONS = Arrays.asList(
+-            new String[] {"1.0", "1.1", "1.2", "1.3", "1.4", "2.0"});
++        protected static final List ALLOWED_VERSIONS = Arrays.asList(new String[] {"1.0", "1.1",
++                "1.2", "1.3", "1.4", "2.0"});
+ 
+         /* how and what do we have to parse */
+         private ParserSettings settings;
++
+         private boolean validate = true;
++
+         private URL descriptorURL;
++
+         private InputStream descriptorInput;
+ 
+-
+         /* Parsing state */
+         private int state = State.NONE;
++
+         private PatternMatcher defaultMatcher;
++
+         private DefaultDependencyDescriptor dd;
++
+         private ConfigurationAware confAware;
++
+         private MDArtifact artifact;
++
+         private String conf;
++
+         private boolean artifactsDeclared = false;
++
+         private StringBuffer buffer;
++
+         private String descriptorVersion;
++
+         private String[] publicationsDefaultConf;
+-        
++
+         public Parser(ModuleDescriptorParser parser, ParserSettings ivySettings) {
+             super(parser);
+             settings = ivySettings;
+@@ -229,8 +246,7 @@
+             this.validate = validate;
+         }
+ 
+-        public void parse() throws ParseException,
+-                IOException {
++        public void parse() throws ParseException, IOException {
+             try {
+                 URL schemaURL = validate ? getSchemaURL() : null;
+                 if (descriptorURL != null) {
+@@ -241,14 +257,15 @@
+                 checkConfigurations();
+                 replaceConfigurationWildcards();
+                 getMd().setModuleArtifact(
+-                    DefaultArtifact.newIvyArtifact(
+-                        getMd().getResolvedModuleRevisionId(), getMd().getPublicationDate()));
++                    DefaultArtifact.newIvyArtifact(getMd().getResolvedModuleRevisionId(), getMd()
++                            .getPublicationDate()));
+                 if (!artifactsDeclared) {
+                     String[] confs = getMd().getConfigurationsNames();
+                     for (int i = 0; i < confs.length; i++) {
+-                        getMd().addArtifact(confs[i], 
+-                            new MDArtifact(getMd(), getMd().getModuleRevisionId().getName(), 
+-                                "jar", "jar"));
++                        getMd().addArtifact(
++                            confs[i],
++                            new MDArtifact(getMd(), getMd().getModuleRevisionId().getName(), "jar",
++                                    "jar"));
+                     }
+                 }
+                 getMd().check();
+@@ -269,16 +286,19 @@
+                 throws SAXException {
+             try {
+                 if (state == State.DESCRIPTION) {
+-                    //make sure we don't interpret any tag while in description tag 
++                    // make sure we don't interpret any tag while in description tag
+                     buffer.append("<" + qName + ">");
+                     return;
+                 } else if ("ivy-module".equals(qName)) {
+                     ivyModuleStarted(attributes);
+                 } else if ("info".equals(qName)) {
+                     infoStarted(attributes);
++                } else if (state == State.INFO && "extends".equals(qName)) {
++                    extendsStarted(attributes);
+                 } else if (state == State.INFO && "license".equals(qName)) {
+-                    getMd().addLicense(new License(settings.substitute(attributes.getValue("name")),
+-                                        settings.substitute(attributes.getValue("url"))));
++                    getMd().addLicense(
++                        new License(settings.substitute(attributes.getValue("name")), settings
++                                .substitute(attributes.getValue("url"))));
+                 } else if (state == State.INFO && "description".equals(qName)) {
+                     getMd().setHomePage(settings.substitute(attributes.getValue("homepage")));
+                     state = State.DESCRIPTION;
+@@ -299,7 +319,8 @@
+                 } else if ("conflicts".equals(qName)) {
+                     if (!descriptorVersion.startsWith("1.")) {
+                         Message.deprecated("using conflicts section is deprecated: "
+-                            + "please use hints section instead. Ivy file URL: " + descriptorURL);
++                                + "please use hints section instead. Ivy file URL: "
++                                + descriptorURL);
+                     }
+                     state = State.CONFLICT;
+                     checkConfigurations();
+@@ -341,6 +362,185 @@
+             }
+         }
+ 
++        protected String getDefaultParentLocation() {
++            return "../ivy.xml";
++        }
++
++        protected void extendsStarted(Attributes attributes) throws ParseException {
++            String parentOrganisation = attributes.getValue("organisation");
++            String parentModule = attributes.getValue("name");
++            String parentRevision = attributes.getValue("revision");
++            String location = attributes.getValue("location") != null ? attributes
++                    .getValue("location") : getDefaultParentLocation();
++            ModuleDescriptor parent = null;
++
++            String extendType = attributes.getValue("extendType") != null ? attributes.getValue(
++                "extendType").toLowerCase() : "all";
++
++            List/* <String> */extendTypes = Arrays.asList(extendType.split(","));
++
++            try {
++                Message.debug("Trying to parse included ivy file :" + location);
++                parent = parseOtherIvyFileOnFileSystem(location);
++            } catch (ParseException e) {
++                Message.warn("Unable to parse included ivy file : " + location);
++            } catch (IOException e) {
++                Message.warn("Unable to parse included ivy file : " + location);
++            }
++
++            // if the included ivy file is not found on file system, tries to resolve using
++            // repositories
++            if (parent == null) {
++                try {
++                    Message
++                            .debug("Trying to parse included ivy file by asking repository for module :"
++                                    + parentOrganisation
++                                    + "#"
++                                    + parentModule
++                                    + ";"
++                                    + parentRevision);
++                    parent = parseOtherIvyFile(parentOrganisation, parentModule, parentRevision);
++                } catch (ParseException e) {
++                    Message.warn("Unable to parse included ivy file for " + parentOrganisation
++                            + "#" + parentModule + ";" + parentRevision);
++                }
++            }
++
++            if (parent == null) {
++                throw new ParseException("Unable to parse included ivy file for "
++                        + parentOrganisation + "#" + parentModule + ";" + parentRevision, 0);
++            }
++
++            ResolutionCacheManager cacheManager = settings.getResolutionCacheManager();
++
++            File ivyFileInCache = cacheManager.getResolvedIvyFileInCache(parent
++                    .getResolvedModuleRevisionId());
++            //Generate the parent cache file if necessary
++            if (parent.getResource() != null
++                    && !parent.getResource().getName().equals(ivyFileInCache.toURI().toString())) {
++                try {
++                    parent.toIvyFile(ivyFileInCache);
++                } catch (ParseException e) {
++                    throw new ParseException("Unable to create cache file for "
++                            + parentOrganisation + "#" + parentModule + ";" + parentRevision
++                            + " Reason:" + e.getLocalizedMessage(), 0);
++                } catch (IOException e) {
++                    throw new ParseException("Unable to create cache file for "
++                            + parentOrganisation + "#" + parentModule + ";" + parentRevision
++                            + " Reason :" + e.getLocalizedMessage(), 0);
++                }
++            }
++            mergeWithOtherModuleDescriptor(extendTypes, parent);
++        }
++
++        protected void mergeWithOtherModuleDescriptor(List/* <String> */extendTypes,
++                ModuleDescriptor parent) {
++
++            if (extendTypes.contains("all")) {
++                mergeAll(parent);
++            } else {
++                if (extendTypes.contains("configurations")) {
++                    mergeConfigurations(parent.getConfigurations());
++                }
++
++                if (extendTypes.contains("dependencies")) {
++                    mergeDependencies(parent.getDependencies());
++                }
++
++                if (extendTypes.contains("description")) {
++                    mergeDescription(parent.getDescription());
++                }
++            }
++
++        }
++
++        protected void mergeAll(ModuleDescriptor parent) {
++            mergeConfigurations(parent.getConfigurations());
++            mergeDependencies(parent.getDependencies());
++            mergeDescription(parent.getDescription());
++        }
++
++        protected void mergeConfigurations(Configuration[] configurations) {
++            for (int i = 0; i < configurations.length; i++) {
++                Configuration configuration = configurations[i];
++                Message.debug("Merging configuration with: " + configuration.getName());
++                // TODO: Here we need to merge configuration
++                getMd().addConfiguration(configuration);
++            }
++        }
++
++        protected void mergeDependencies(DependencyDescriptor[] dependencies) {
++            for (int i = 0; i < dependencies.length; i++) {
++                DependencyDescriptor dependencyDescriptor = dependencies[i];
++                Message.debug("Merging dependency with: "
++                        + dependencyDescriptor.getDependencyRevisionId().toString());
++                // TODO: Here we need to merge dependencies
++                getMd().addDependency(dependencyDescriptor);
++            }
++        }
++
++        protected void mergeDescription(String description) {
++            if (getMd().getDescription() == null)
++                getMd().setDescription(description);
++        }
++
++        protected ModuleDescriptor parseOtherIvyFileOnFileSystem(String location)
++                throws ParseException, IOException {
++            URL url = null;
++            ModuleDescriptor parent = null;
++            url = getSettings().getRelativeUrlResolver().getURL(descriptorURL, location);
++            Message.debug("Trying to load included ivy file from " + url.toString());
++            URLResource res = new URLResource(url);
++            ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance().getParser(
++                res);
++
++            parent = parser.parseDescriptor(getSettings(), url, isValidate());
++            return parent;
++        }
++
++        protected ModuleDescriptor parseOtherIvyFile(String parentOrganisation,
++                String parentModule, String parentRevision) throws ParseException {
++            ModuleId parentModuleId = new ModuleId(parentOrganisation, parentModule);
++            ModuleRevisionId parentMrid = new ModuleRevisionId(parentModuleId, parentRevision);
++
++            // try to load parent module in cache
++            File cacheFile = settings.getResolutionCacheManager().getResolvedIvyFileInCache(
++                ModuleRevisionId.newInstance(parentMrid, Ivy.getWorkingRevision()));
++            if (cacheFile.exists() && cacheFile.length() > 0) {
++                ModuleDescriptor md;
++                try {
++                    Message.debug("Trying to load included ivy file from cache");
++                    URL parentUrl = cacheFile.toURI().toURL();
++                    md = parseOtherIvyFileOnFileSystem(parentUrl.toString());
++                    return md;
++                } catch (IOException e) {
++                    // do nothing
++                    Message.error(e.getLocalizedMessage());
++                }
++            }
++
++            DependencyDescriptor dd = new DefaultDependencyDescriptor(parentMrid, true);
++            ResolveData data = IvyContext.getContext().getResolveData();
++            if (data == null) {
++                ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine();
++                ResolveOptions options = new ResolveOptions();
++                options.setDownload(false);
++                data = new ResolveData(engine, options);
++            }
++
++            DependencyResolver resolver = getSettings().getResolver(parentMrid);
++            if (resolver == null) {
++                // TODO: Throw exception here?
++                return null;
++            } else {
++                ResolvedModuleRevision otherModule = resolver.getDependency(dd, data);
++                if (otherModule == null)
++                    throw new ParseException("Unable to find " + parentMrid.toString(), 0);
++                return otherModule.getDescriptor();
++            }
++
++        }
++
+         protected void publicationsStarted(Attributes attributes) {
+             state = State.PUB;
+             artifactsDeclared = true;
+@@ -407,28 +607,27 @@
+                 addError("unknown matcher: " + matcherName);
+                 return;
+             }
+-            getMd().addDependencyDescriptorMediator(
+-                new ModuleId(org, mod), matcher, 
++            getMd().addDependencyDescriptorMediator(new ModuleId(org, mod), matcher,
+                 new OverrideDependencyDescriptorMediator(branch, rev));
+         }
+ 
+-        protected void includeConfStarted(Attributes attributes) 
+-                throws SAXException, IOException, ParserConfigurationException, ParseException {
++        protected void includeConfStarted(Attributes attributes) throws SAXException, IOException,
++                ParserConfigurationException, ParseException {
+             URL url = settings.getRelativeUrlResolver().getURL(descriptorURL,
+-                    settings.substitute(attributes.getValue("file")),
+-                    settings.substitute(attributes.getValue("url")));
+-            
++                settings.substitute(attributes.getValue("file")),
++                settings.substitute(attributes.getValue("url")));
++
+             if (url == null) {
+                 throw new SAXException("include tag must have a file or an url attribute");
+             }
+-            
++
+             // create a new temporary parser to read the configurations from
+             // the specified file.
+             Parser parser = new Parser(getModuleDescriptorParser(), settings);
+             parser.setInput(url);
+-            parser.setMd(new DefaultModuleDescriptor(getModuleDescriptorParser(),
+-                    new URLResource(url)));
+-            XMLHelper.parse(url , null, parser);
++            parser.setMd(new DefaultModuleDescriptor(getModuleDescriptorParser(), new URLResource(
++                    url)));
++            XMLHelper.parse(url, null, parser);
+ 
+             // add the configurations from this temporary parser to this module descriptor
+             Configuration[] configs = parser.getModuleDescriptor().getConfigurations();
+@@ -441,8 +640,7 @@
+                 setDefaultConfMapping(parser.getDefaultConfMapping());
+             }
+             if (parser.getMd().isMappingOverride()) {
+-                Message.debug("enabling mapping-override from imported configurations" 
+-                        + " file");
++                Message.debug("enabling mapping-override from imported configurations" + " file");
+                 getMd().setMappingOverride(true);
+             }
+         }
+@@ -454,18 +652,16 @@
+                     String visibility = settings.substitute(attributes.getValue("visibility"));
+                     String ext = settings.substitute(attributes.getValue("extends"));
+                     String transitiveValue = attributes.getValue("transitive");
+-                    boolean transitive = (transitiveValue == null) ? true : Boolean
+-                            .valueOf(attributes.getValue("transitive")).booleanValue();
++                    boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf(
++                        attributes.getValue("transitive")).booleanValue();
+                     String deprecated = attributes.getValue("deprecated");
+-                    Configuration configuration = new Configuration(conf,
+-                            Configuration.Visibility
+-                                    .getVisibility(visibility == null ? "public"
+-                                            : visibility), settings.substitute(attributes
+-                                    .getValue("description")), ext == null ? null : ext
+-                                    .split(","), transitive, deprecated);
++                    Configuration configuration = new Configuration(conf, Configuration.Visibility
++                            .getVisibility(visibility == null ? "public" : visibility), settings
++                            .substitute(attributes.getValue("description")), ext == null ? null
++                            : ext.split(","), transitive, deprecated);
+                     ExtendableItemHelper.fillExtraAttributes(settings, configuration, attributes,
+-                        new String[] {"name", "visibility", "extends", "transitive",
+-                                "description", "deprecated"});
++                        new String[] {"name", "visibility", "extends", "transitive", "description",
++                                "deprecated"});
+                     getMd().addConfiguration(configuration);
+                     break;
+                 case State.PUB:
+@@ -511,8 +707,8 @@
+             }
+             boolean force = Boolean.valueOf(settings.substitute(attributes.getValue("force")))
+                     .booleanValue();
+-            boolean changing = Boolean.valueOf(
+-                settings.substitute(attributes.getValue("changing"))).booleanValue();
++            boolean changing = Boolean
++                    .valueOf(settings.substitute(attributes.getValue("changing"))).booleanValue();
+ 
+             String transitiveValue = settings.substitute(attributes.getValue("transitive"));
+             boolean transitive = (transitiveValue == null) ? true : Boolean.valueOf(
+@@ -524,14 +720,11 @@
+             String rev = settings.substitute(attributes.getValue("rev"));
+             String revConstraint = settings.substitute(attributes.getValue("revConstraint"));
+             revConstraint = revConstraint == null ? rev : revConstraint;
+-            Map extraAttributes = ExtendableItemHelper.getExtraAttributes(
+-                settings, attributes, DEPENDENCY_REGULAR_ATTRIBUTES);
+-            dd = new DefaultDependencyDescriptor(
+-                getMd(), 
+-                ModuleRevisionId.newInstance(org, name, branch, rev, extraAttributes), 
+-                ModuleRevisionId.newInstance(
+-                    org, name, branchConstraint, revConstraint, extraAttributes), 
+-                force, changing, transitive);
++            Map extraAttributes = ExtendableItemHelper.getExtraAttributes(settings, attributes,
++                DEPENDENCY_REGULAR_ATTRIBUTES);
++            dd = new DefaultDependencyDescriptor(getMd(), ModuleRevisionId.newInstance(org, name,
++                branch, rev, extraAttributes), ModuleRevisionId.newInstance(org, name,
++                branchConstraint, revConstraint, extraAttributes), force, changing, transitive);
+             getMd().addDependency(dd);
+             String confs = settings.substitute(attributes.getValue("conf"));
+             if (confs != null && confs.length() > 0) {
+@@ -539,7 +732,7 @@
+             }
+         }
+ 
+-        protected void artifactStarted(String qName, Attributes attributes) 
++        protected void artifactStarted(String qName, Attributes attributes)
+                 throws MalformedURLException {
+             if (state == State.PUB) {
+                 // this is a published artifact
+@@ -551,8 +744,8 @@
+                 ext = ext != null ? ext : type;
+                 String url = settings.substitute(attributes.getValue("url"));
+                 artifact = new MDArtifact(getMd(), artName, type, ext, url == null ? null
+-                        : new URL(url), ExtendableItemHelper.getExtraAttributes(
+-                            settings, attributes, new String[] {"ext", "type", "name", "conf"}));
++                        : new URL(url), ExtendableItemHelper.getExtraAttributes(settings,
++                    attributes, new String[] {"ext", "type", "name", "conf"}));
+                 String confs = settings.substitute(attributes.getValue("conf"));
+                 // only add confs if they are specified. if they aren't, endElement will
+                 // handle this
+@@ -597,12 +790,10 @@
+ 
+         protected void configurationStarted(Attributes attributes) {
+             state = State.CONF;
+-            setDefaultConfMapping(settings
+-                    .substitute(attributes.getValue("defaultconfmapping")));
+-            getMd()
+-                    .setMappingOverride(Boolean.valueOf(
+-                        settings.substitute(attributes.getValue("confmappingoverride")))
+-                            .booleanValue());
++            setDefaultConfMapping(settings.substitute(attributes.getValue("defaultconfmapping")));
++            getMd().setMappingOverride(
++                Boolean.valueOf(settings.substitute(attributes.getValue("confmappingoverride")))
++                        .booleanValue());
+         }
+ 
+         protected void infoStarted(Attributes attributes) {
+@@ -611,28 +802,30 @@
+             String module = settings.substitute(attributes.getValue("module"));
+             String revision = settings.substitute(attributes.getValue("revision"));
+             String branch = settings.substitute(attributes.getValue("branch"));
+-            getMd().setModuleRevisionId(ModuleRevisionId.newInstance(org, module, branch,
+-                revision, ExtendableItemHelper.getExtraAttributes(settings, attributes, 
+-                    new String[] {
+-                        "organisation", "module", "revision", "status", "publication",
+-                        "branch", "namespace", "default", "resolver"})));
++            getMd().setModuleRevisionId(
++                ModuleRevisionId.newInstance(org, module, branch, revision, ExtendableItemHelper
++                        .getExtraAttributes(settings, attributes, new String[] {"organisation",
++                                "module", "revision", "status", "publication", "branch",
++                                "namespace", "default", "resolver"})));
+ 
+             String namespace = settings.substitute(attributes.getValue("namespace"));
+             if (namespace != null) {
+                 Namespace ns = settings.getNamespace(namespace);
+                 if (ns == null) {
+-                    Message.warn("namespace not found for " + getMd().getModuleRevisionId()
+-                            + ": " + namespace);
++                    Message.warn("namespace not found for " + getMd().getModuleRevisionId() + ": "
++                            + namespace);
+                 } else {
+                     getMd().setNamespace(ns);
+                 }
+             }
+ 
+             String status = settings.substitute(attributes.getValue("status"));
+-            getMd().setStatus(status == null ? settings.getStatusManager().getDefaultStatus()
+-                    : status);
+-            getMd().setDefault(Boolean.valueOf(settings.substitute(attributes.getValue("default")))
+-                    .booleanValue());
++            getMd().setStatus(
++                status == null ? settings.getStatusManager().getDefaultStatus() : status);
++            getMd()
++                    .setDefault(
++                        Boolean.valueOf(settings.substitute(attributes.getValue("default")))
++                                .booleanValue());
+             String pubDate = settings.substitute(attributes.getValue("publication"));
+             if (pubDate != null && pubDate.length() > 0) {
+                 try {
+@@ -662,12 +855,13 @@
+                         + " as default matcher");
+                 defaultMatcher = settings.getMatcher(PatternMatcher.EXACT_OR_REGEXP);
+             }
+-            
++
+             for (int i = 0; i < attributes.getLength(); i++) {
+                 if (attributes.getQName(i).startsWith("xmlns:")) {
+-                    getMd().addExtraAttributeNamespace(
+-                        attributes.getQName(i).substring("xmlns:".length()), 
+-                        attributes.getValue(i));
++                    getMd()
++                            .addExtraAttributeNamespace(
++                                attributes.getQName(i).substring("xmlns:".length()),
++                                attributes.getValue(i));
+                 }
+             }
+         }
+@@ -678,13 +872,13 @@
+             parseRule(tag, attributes);
+         }
+ 
+-        protected void addIncludeRule(String tag, Attributes attributes) 
++        protected void addIncludeRule(String tag, Attributes attributes)
+                 throws MalformedURLException {
+             state = State.ARTIFACT_INCLUDE;
+             parseRule(tag, attributes);
+         }
+ 
+-        protected void addExcludeRule(String tag, Attributes attributes) 
++        protected void addExcludeRule(String tag, Attributes attributes)
+                 throws MalformedURLException {
+             state = State.ARTIFACT_EXCLUDE;
+             parseRule(tag, attributes);
+@@ -707,7 +901,7 @@
+             ext = ext != null ? ext : type;
+             if (state == State.DEP_ARTIFACT) {
+                 String url = settings.substitute(attributes.getValue("url"));
+-                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, 
++                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes,
+                     new String[] {"name", "type", "ext", "url", "conf"});
+                 confAware = new DefaultDependencyArtifactDescriptor(dd, name, type, ext,
+                         url == null ? null : new URL(url), extraAtt);
+@@ -718,7 +912,7 @@
+                 String module = settings.substitute(attributes.getValue("module"));
+                 module = module == null ? PatternMatcher.ANY_EXPRESSION : module;
+                 ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext);
+-                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, 
++                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes,
+                     new String[] {"org", "module", "name", "type", "ext", "matcher", "conf"});
+                 confAware = new DefaultIncludeRule(aid, matcher, extraAtt);
+             } else { // _state == ARTIFACT_EXCLUDE || EXCLUDE
+@@ -728,7 +922,7 @@
+                 String module = settings.substitute(attributes.getValue("module"));
+                 module = module == null ? PatternMatcher.ANY_EXPRESSION : module;
+                 ArtifactId aid = new ArtifactId(new ModuleId(org, module), name, type, ext);
+-                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes, 
++                Map extraAtt = ExtendableItemHelper.getExtraAttributes(settings, attributes,
+                     new String[] {"org", "module", "name", "type", "ext", "matcher", "conf"});
+                 confAware = new DefaultExcludeRule(aid, matcher, extraAtt);
+             }
+@@ -780,20 +974,17 @@
+             return matcher;
+         }
+ 
+-        
+         public void characters(char[] ch, int start, int length) throws SAXException {
+             if (buffer != null) {
+                 buffer.append(ch, start, length);
+-            }            
++            }
+         }
+ 
+-        
+         public void endElement(String uri, String localName, String qName) throws SAXException {
+             if (state == State.PUB && "artifact".equals(qName)
+                     && artifact.getConfigurations().length == 0) {
+-                String[] confs = publicationsDefaultConf == null 
+-                    ? getMd().getConfigurationsNames()
+-                    : publicationsDefaultConf;
++                String[] confs = publicationsDefaultConf == null ? getMd().getConfigurationsNames()
++                        : publicationsDefaultConf;
+                 for (int i = 0; i < confs.length; i++) {
+                     artifact.addConfiguration(confs[i].trim());
+                     getMd().addArtifact(confs[i].trim(), artifact);
+Index: src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd
+===================================================================
+--- src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd	(révision 772962)
++++ src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd	(copie de travail)
+@@ -60,6 +60,15 @@
+   		    <xs:element name="info">
+             	<xs:complexType>
+ 			        <xs:sequence>
++					<xs:element name="extends" minOccurs="0" maxOccurs="unbounded">
++                                        	<xs:complexType>
++	                                                <xs:attribute name="organisation" type="xs:string" use="required"/>
++                                                        <xs:attribute name="name" type="xs:string" use="required"/>
++                                                        <xs:attribute name="revision" type="xs:string" use="required"/>
++                                                        <xs:attribute name="location" type="xs:string" />
++                                                        <xs:attribute name="extendType" type="xs:string" />
++                                                </xs:complexType>
++                                        </xs:element>
+ 			      		<xs:element name="license" minOccurs="0" maxOccurs="unbounded">
+ 			            	<xs:complexType>
+ 					            <xs:attribute name="name" type="xs:string" use="required"/>
+@@ -141,7 +150,7 @@
+ 				            	</xs:complexType>
+ 				      		</xs:element>
+ 				        </xs:sequence>
+-						<xs:attribute name="defaultconf" type="xs:string"/>				  
++						<xs:attribute name="defaultconf" type="xs:string"/>				  
+ 			      </xs:complexType>
+       		</xs:element>
+       		<xs:element name="dependencies" minOccurs="0">
+@@ -220,7 +229,7 @@
+ 						            <xs:attribute name="org" type="xs:string"/>
+ 						            <xs:attribute name="name" type="xs:string" use="required"/>
+ 						            <xs:attribute name="branch" type="xs:string"/>
+-						            <xs:attribute name="branchConstraint" type="xs:string"/>
++						            <xs:attribute name="branchConstraint" type="xs:string"/>
+ 						            <xs:attribute name="rev" type="xs:string" use="required"/>
+ 						            <xs:attribute name="revConstraint" type="xs:string"/>
+ 						            <xs:attribute name="force" type="xs:boolean"/>

Added: incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r886938.patch
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r886938.patch?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r886938.patch (added)
+++ incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r886938.patch Thu Feb 17 17:01:07 2011
@@ -0,0 +1,948 @@
+Index: src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
+===================================================================
+--- src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java	(revision 887799)
++++ src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java	(working copy)
+@@ -31,6 +31,7 @@
+ 
+ import org.apache.ivy.Ivy;
+ import org.apache.ivy.core.IvyContext;
++import org.apache.ivy.core.cache.ResolutionCacheManager;
+ import org.apache.ivy.core.module.descriptor.Configuration;
+ import org.apache.ivy.core.module.descriptor.ConfigurationAware;
+ import org.apache.ivy.core.module.descriptor.DefaultArtifact;
+@@ -40,6 +41,7 @@
+ import org.apache.ivy.core.module.descriptor.DefaultIncludeRule;
+ 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.ExcludeRule;
+ import org.apache.ivy.core.module.descriptor.IncludeRule;
+ import org.apache.ivy.core.module.descriptor.License;
+@@ -49,15 +51,21 @@
+ 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.resolve.ResolveData;
++import org.apache.ivy.core.resolve.ResolveEngine;
++import org.apache.ivy.core.resolve.ResolveOptions;
++import org.apache.ivy.core.resolve.ResolvedModuleRevision;
+ import org.apache.ivy.plugins.conflict.ConflictManager;
+ import org.apache.ivy.plugins.conflict.FixedConflictManager;
+ import org.apache.ivy.plugins.matcher.PatternMatcher;
+ import org.apache.ivy.plugins.namespace.Namespace;
+ import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParser;
+ import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
++import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
+ import org.apache.ivy.plugins.parser.ParserSettings;
+ import org.apache.ivy.plugins.repository.Resource;
+ import org.apache.ivy.plugins.repository.url.URLResource;
++import org.apache.ivy.plugins.resolver.DependencyResolver;
+ import org.apache.ivy.util.Message;
+ import org.apache.ivy.util.XMLHelper;
+ import org.apache.ivy.util.extendable.ExtendableItemHelper;
+@@ -269,13 +277,15 @@
+                 throws SAXException {
+             try {
+                 if (state == State.DESCRIPTION) {
+-                    //make sure we don't interpret any tag while in description tag 
++                    // make sure we don't interpret any tag while in description tag
+                     buffer.append("<" + qName + ">");
+                     return;
+                 } else if ("ivy-module".equals(qName)) {
+                     ivyModuleStarted(attributes);
+                 } else if ("info".equals(qName)) {
+                     infoStarted(attributes);
++                } else if (state == State.INFO && "extends".equals(qName)) {
++                    extendsStarted(attributes);
+                 } else if (state == State.INFO && "license".equals(qName)) {
+                     getMd().addLicense(new License(settings.substitute(attributes.getValue("name")),
+                                         settings.substitute(attributes.getValue("url"))));
+@@ -341,6 +351,200 @@
+             }
+         }
+ 
++        protected String getDefaultParentLocation() {
++            return "../ivy.xml";
++        }
++
++        protected void extendsStarted(Attributes attributes) throws ParseException {
++            String parentOrganisation = attributes.getValue("organisation");
++            String parentModule = attributes.getValue("module");
++            String parentRevision = attributes.getValue("revision");
++            String location = attributes.getValue("location") != null ? attributes
++                    .getValue("location") : getDefaultParentLocation();
++            ModuleDescriptor parent = null;
++
++            String extendType = attributes.getValue("extendType") != null ? attributes.getValue(
++                "extendType").toLowerCase() : "all";
++
++            List/* <String> */extendTypes = Arrays.asList(extendType.split(","));
++
++            try {
++                Message.debug("Trying to parse included ivy file :" + location);
++                parent = parseOtherIvyFileOnFileSystem(location);
++
++                //verify that the parsed descriptor is the correct parent module.
++                ModuleId expected = new ModuleId(parentOrganisation, parentModule);
++                ModuleId pid = parent.getModuleRevisionId().getModuleId();
++                if (!expected.equals(pid)) {
++                    Message.verbose("Ignoring parent Ivy file " + location + "; expected "
++                        + expected + " but found " + pid);
++                    parent = null;
++                }
++                
++            } catch (ParseException e) {
++                Message.warn("Unable to parse included ivy file " + location + ": " 
++                    + e.getMessage());
++            } catch (IOException e) {
++                Message.warn("Unable to parse included ivy file " + location + ": " 
++                    + e.getMessage());
++            }
++
++            // if the included ivy file is not found on file system, tries to resolve using
++            // repositories
++            if (parent == null) {
++                try {
++                    Message.debug(
++                        "Trying to parse included ivy file by asking repository for module :"
++                                    + parentOrganisation
++                                    + "#"
++                                    + parentModule
++                                    + ";"
++                                    + parentRevision);
++                    parent = parseOtherIvyFile(parentOrganisation, parentModule, parentRevision);
++                } catch (ParseException e) {
++                    Message.warn("Unable to parse included ivy file for " + parentOrganisation
++                            + "#" + parentModule + ";" + parentRevision);
++                }
++            }
++
++            if (parent == null) {
++                throw new ParseException("Unable to parse included ivy file for "
++                        + parentOrganisation + "#" + parentModule + ";" + parentRevision, 0);
++            }
++
++            ResolutionCacheManager cacheManager = settings.getResolutionCacheManager();
++
++            File ivyFileInCache = cacheManager.getResolvedIvyFileInCache(parent
++                    .getResolvedModuleRevisionId());
++            //Generate the parent cache file if necessary
++            if (parent.getResource() != null
++                    && !parent.getResource().getName().equals(ivyFileInCache.toURI().toString())) {
++                try {
++                    parent.toIvyFile(ivyFileInCache);
++                } catch (ParseException e) {
++                    throw new ParseException("Unable to create cache file for "
++                            + parentOrganisation + "#" + parentModule + ";" + parentRevision
++                            + " Reason:" + e.getLocalizedMessage(), 0);
++                } catch (IOException e) {
++                    throw new ParseException("Unable to create cache file for "
++                            + parentOrganisation + "#" + parentModule + ";" + parentRevision
++                            + " Reason :" + e.getLocalizedMessage(), 0);
++                }
++            }
++            mergeWithOtherModuleDescriptor(extendTypes, parent);
++        }
++
++        protected void mergeWithOtherModuleDescriptor(List/* <String> */extendTypes,
++                ModuleDescriptor parent) {
++
++            if (extendTypes.contains("all")) {
++                mergeAll(parent);
++            } else {
++                if (extendTypes.contains("configurations")) {
++                    mergeConfigurations(parent.getConfigurations());
++                }
++
++                if (extendTypes.contains("dependencies")) {
++                    mergeDependencies(parent.getDependencies());
++                }
++
++                if (extendTypes.contains("description")) {
++                    mergeDescription(parent.getDescription());
++                }
++            }
++
++        }
++
++        protected void mergeAll(ModuleDescriptor parent) {
++            mergeConfigurations(parent.getConfigurations());
++            mergeDependencies(parent.getDependencies());
++            mergeDescription(parent.getDescription());
++        }
++
++        protected void mergeConfigurations(Configuration[] configurations) {
++            for (int i = 0; i < configurations.length; i++) {
++                Configuration configuration = configurations[i];
++                Message.debug("Merging configuration with: " + configuration.getName());
++                // TODO: Here we need to merge configuration
++                getMd().addConfiguration(configuration);
++            }
++        }
++
++        protected void mergeDependencies(DependencyDescriptor[] dependencies) {
++            for (int i = 0; i < dependencies.length; i++) {
++                DependencyDescriptor dependencyDescriptor = dependencies[i];
++                Message.debug("Merging dependency with: "
++                        + dependencyDescriptor.getDependencyRevisionId().toString());
++                // TODO: Here we need to merge dependencies
++                getMd().addDependency(dependencyDescriptor);
++            }
++        }
++
++        protected void mergeDescription(String description) {
++            String current = getMd().getDescription();
++            if (current == null || current.trim().length() == 0) {
++                getMd().setDescription(description);
++            }
++        }
++
++        protected ModuleDescriptor parseOtherIvyFileOnFileSystem(String location)
++                throws ParseException, IOException {
++            URL url = null;
++            ModuleDescriptor parent = null;
++            url = getSettings().getRelativeUrlResolver().getURL(descriptorURL, location);
++            Message.debug("Trying to load included ivy file from " + url.toString());
++            URLResource res = new URLResource(url);
++            ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance().getParser(
++                res);
++
++            parent = parser.parseDescriptor(getSettings(), url, isValidate());
++            return parent;
++        }
++
++        protected ModuleDescriptor parseOtherIvyFile(String parentOrganisation,
++                String parentModule, String parentRevision) throws ParseException {
++            ModuleId parentModuleId = new ModuleId(parentOrganisation, parentModule);
++            ModuleRevisionId parentMrid = new ModuleRevisionId(parentModuleId, parentRevision);
++
++            // try to load parent module in cache
++            File cacheFile = settings.getResolutionCacheManager().getResolvedIvyFileInCache(
++                ModuleRevisionId.newInstance(parentMrid, Ivy.getWorkingRevision()));
++            if (cacheFile.exists() && cacheFile.length() > 0) {
++                ModuleDescriptor md;
++                try {
++                    Message.debug("Trying to load included ivy file from cache");
++                    URL parentUrl = cacheFile.toURI().toURL();
++                    md = parseOtherIvyFileOnFileSystem(parentUrl.toString());
++                    return md;
++                } catch (IOException e) {
++                    // do nothing
++                    Message.error(e.getLocalizedMessage());
++                }
++            }
++
++            DependencyDescriptor dd = new DefaultDependencyDescriptor(parentMrid, true);
++            ResolveData data = IvyContext.getContext().getResolveData();
++            if (data == null) {
++                ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine();
++                ResolveOptions options = new ResolveOptions();
++                options.setDownload(false);
++                data = new ResolveData(engine, options);
++            }
++
++            DependencyResolver resolver = getSettings().getResolver(parentMrid);
++            if (resolver == null) {
++                // TODO: Throw exception here?
++                return null;
++            } else {
++                ResolvedModuleRevision otherModule = resolver.getDependency(dd, data);
++                if (otherModule == null) {
++                    throw new ParseException("Unable to find " + parentMrid.toString(), 0);
++                }
++                return otherModule.getDescriptor();
++            }
++
++        }
++
+         protected void publicationsStarted(Attributes attributes) {
+             state = State.PUB;
+             artifactsDeclared = true;
+Index: src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd
+===================================================================
+--- src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd	(revision 887799)
++++ src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd	(working copy)
+@@ -60,6 +60,15 @@
+   		    <xs:element name="info">
+             	<xs:complexType>
+ 			        <xs:sequence>
++					<xs:element name="extends" minOccurs="0" maxOccurs="unbounded">
++                                        	<xs:complexType>
++	                                                <xs:attribute name="organisation" type="xs:string" use="required"/>
++                                                        <xs:attribute name="module" type="xs:string" use="required"/>
++                                                        <xs:attribute name="revision" type="xs:string" use="required"/>
++                                                        <xs:attribute name="location" type="xs:string" />
++                                                        <xs:attribute name="extendType" type="xs:string" />
++                                                </xs:complexType>
++                                        </xs:element>
+ 			      		<xs:element name="license" minOccurs="0" maxOccurs="unbounded">
+ 			            	<xs:complexType>
+ 					            <xs:attribute name="name" type="xs:string" use="required"/>
+Index: test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java	(revision 887799)
++++ test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java	(working copy)
+@@ -31,7 +31,6 @@
+ import org.apache.ivy.core.module.descriptor.Configuration;
+ import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
+ 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.License;
+ import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
+@@ -46,6 +45,8 @@
+ import org.apache.ivy.plugins.matcher.GlobPatternMatcher;
+ import org.apache.ivy.plugins.matcher.PatternMatcher;
+ import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParserTester;
++import org.apache.ivy.plugins.resolver.FileSystemResolver;
++import org.apache.ivy.util.FileUtil;
+ import org.apache.ivy.util.XMLHelper;
+ 
+ public class XmlModuleDescriptorParserTest extends AbstractModuleDescriptorParserTester {
+@@ -55,6 +56,8 @@
+         super.setUp();
+         
+         this.settings = new IvySettings();
++        //prevent test from polluting local cache
++        settings.setDefaultCache(new File("build/cache"));
+     }
+ 
+     public void testSimple() throws Exception {
+@@ -78,7 +81,7 @@
+         assertNotNull(md.getDependencies());
+         assertEquals(0, md.getDependencies().length);
+     }
+-
++    
+     public void testNamespaces() throws Exception {
+         ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+             getClass().getResource("test-namespaces.xml"), true);
+@@ -1018,4 +1021,333 @@
+             // expected
+         }
+     }
++    
++    public void testExtendsAll() throws Exception {
++        //default extends type is 'all' when no extendsType attribute is specified.
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-all.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //verify that the parent description was merged.
++        assertEquals("Parent module description.", md.getDescription());
++        
++        //verify that the parent and child configurations were merged together.
++        final Configuration[] expectedConfs = { new Configuration("default"), 
++                new Configuration("conf1"), new Configuration("conf2") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent and child dependencies were merged together.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(2, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule1", dep.getModuleId().getName());
++        assertEquals("1.0", dep.getRevision());
++
++        assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }), 
++            Arrays.asList(deps[1].getModuleConfigurations()));
++        dep = deps[1].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
++    
++    public void testExtendsDependencies() throws Exception {
++        //descriptor specifies that only parent dependencies should be included
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-dependencies.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //verify that the parent description was ignored.
++        assertEquals("", md.getDescription());
++        
++        //verify that the parent configurations were ignored.
++        final Configuration[] expectedConfs = { new Configuration("default") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent dependencies were merged.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(2, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule1", dep.getModuleId().getName());
++        assertEquals("1.0", dep.getRevision());
++        
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[1].getModuleConfigurations()));
++        dep = deps[1].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
++    
++    public void testExtendsConfigurations() throws Exception {
++        //descriptor specifies that only parent configurations should be included
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-configurations.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //verify that the parent description was ignored.
++        assertEquals("", md.getDescription());
++        
++        //verify that the parent and child configurations were merged together.
++        final Configuration[] expectedConfs = { new Configuration("default"), 
++                new Configuration("conf1"), new Configuration("conf2") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent dependencies were ignored.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(1, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
++    
++    public void testExtendsDescription() throws Exception {
++        //descriptor specifies that only parent description should be included
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-description.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //verify that the parent description was merged.
++        assertEquals("Parent module description.", md.getDescription());
++        
++        //verify that the parent configurations were ignored.
++        final Configuration[] expectedConfs = { new Configuration("default") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent dependencies were ignored.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(1, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
++
++    public void testExtendsDescriptionWithOverride() throws Exception {
++        //descriptor specifies that only parent description should be included
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-description-override.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //child description should always be preferred, even if extendType="description"
++        assertEquals("Child description overrides parent.", md.getDescription());
++        
++        //verify that the parent configurations were ignored.
++        final Configuration[] expectedConfs = { new Configuration("default") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent dependencies were ignored.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(1, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
++    
++    public void testExtendsMixed() throws Exception {
++        //descriptor specifies that parent configurations and dependencies should be included
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-mixed.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //verify that the parent description was ignored.
++        assertEquals("", md.getDescription());
++        
++        //verify that the parent and child configurations were merged together.
++        final Configuration[] expectedConfs = { new Configuration("default"), 
++                new Configuration("conf1"), new Configuration("conf2") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent and child dependencies were merged together.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(2, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule1", dep.getModuleId().getName());
++        assertEquals("1.0", dep.getRevision());
++
++        assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }), 
++            Arrays.asList(deps[1].getModuleConfigurations()));
++        dep = deps[1].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
++    
++    public void testExtendsCached() throws Exception {
++        //configure a resolver to serve the parent descriptor, so that parse succeeds.
++        File resolveRoot = new File("build/tmp/xmlModuleDescriptorTest");
++        assertTrue(resolveRoot.exists() || resolveRoot.mkdirs());
++        
++        FileUtil.copy(getClass().getResource("test-extends-parent.xml"), 
++            new File(resolveRoot, "myorg/myparent/ivy.xml"), null);
++        
++        FileSystemResolver resolver = new FileSystemResolver();
++        resolver.setSettings(settings);
++        resolver.setName("testExtendsCached");
++        resolver.addIvyPattern(resolveRoot.getAbsolutePath() 
++            + "/[organisation]/[module]/[artifact].[ext]");
++
++        settings.addResolver(resolver);
++        settings.setDefaultResolver("testExtendsCached");
++        
++        //descriptor extends a module without a location="..." attribute, so resolver lookup
++        //must be performed.
++        ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
++            getClass().getResource("test-extends-cached.xml"), true);
++        assertNotNull(md);
++        
++        assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
++        assertEquals("mymodule", md.getModuleRevisionId().getName());
++        assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
++        assertEquals("integration", md.getStatus());
++
++        //verify that the parent description was merged.
++        assertEquals("Parent module description.", md.getDescription());
++        
++        //verify that the parent and child configurations were merged together.
++        final Configuration[] expectedConfs = { new Configuration("default"), 
++                new Configuration("conf1"), new Configuration("conf2") };
++        assertNotNull(md.getConfigurations());
++        assertEquals(Arrays.asList(expectedConfs), Arrays
++                .asList(md.getConfigurations()));
++
++        //verify parent and child dependencies were merged together.
++        DependencyDescriptor[] deps = md.getDependencies();
++        assertNotNull(deps);
++        assertEquals(2, deps.length);
++
++        assertEquals(Arrays.asList(new String[]{ "default" }), 
++            Arrays.asList(deps[0].getModuleConfigurations()));
++        ModuleRevisionId dep = deps[0].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule1", dep.getModuleId().getName());
++        assertEquals("1.0", dep.getRevision());
++
++        assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }), 
++            Arrays.asList(deps[1].getModuleConfigurations()));
++        dep = deps[1].getDependencyRevisionId();
++        assertEquals("myorg", dep.getModuleId().getOrganisation());
++        assertEquals("mymodule2", dep.getModuleId().getName());
++        assertEquals("2.0", dep.getRevision());
++        
++        //verify only child publications are present
++        Artifact[] artifacts = md.getAllArtifacts();
++        assertNotNull(artifacts);
++        assertEquals(1, artifacts.length);
++        assertEquals("mymodule", artifacts[0].getName());
++        assertEquals("jar", artifacts[0].getType());
++    }
+ }
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-all.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-all.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-all.xml	(revision 0)
+@@ -0,0 +1,32 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision" location="test-extends-parent.xml"/>
++	</info>
++	<configurations>
++		<conf name="conf2" visibility="private"/>
++	</configurations>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="conf1,conf2"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-cached.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-cached.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-cached.xml	(revision 0)
+@@ -0,0 +1,32 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision"/>
++	</info>
++	<configurations>
++		<conf name="conf2" visibility="private"/>
++	</configurations>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="conf1,conf2"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-configurations.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-configurations.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-configurations.xml	(revision 0)
+@@ -0,0 +1,33 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision" 
++	       			location="test-extends-parent.xml" extendType="configurations"/>
++	</info>
++	<configurations>
++		<conf name="conf2" visibility="private"/>
++	</configurations>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="conf1,conf2"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-dependencies.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-dependencies.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-dependencies.xml	(revision 0)
+@@ -0,0 +1,30 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision" 
++	       			location="test-extends-parent.xml" extendType="dependencies"/>
++	</info>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="default"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-description-override.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-description-override.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-description-override.xml	(revision 0)
+@@ -0,0 +1,31 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision" 
++	       			location="test-extends-parent.xml" extendType="description"/>
++	       <description>Child description overrides parent.</description>
++	</info>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="default"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-description.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-description.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-description.xml	(revision 0)
+@@ -0,0 +1,30 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision" 
++	       			location="test-extends-parent.xml" extendType="description"/>
++	</info>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="default"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-mixed.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-mixed.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-mixed.xml	(revision 0)
+@@ -0,0 +1,33 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="mymodule"
++	       status="integration"
++	       publication="20091206000000">
++	       <extends organisation="myorg" module="myparent" revision="latest.revision" 
++	       			location="test-extends-parent.xml" extendType="configurations,dependencies"/>
++	</info>
++	<configurations>
++		<conf name="conf2" visibility="private"/>
++	</configurations>
++	<dependencies>
++		<dependency name="mymodule2" rev="2.0" conf="conf1,conf2"/>
++	</dependencies>
++</ivy-module>
+Index: test/java/org/apache/ivy/plugins/parser/xml/test-extends-parent.xml
+===================================================================
+--- test/java/org/apache/ivy/plugins/parser/xml/test-extends-parent.xml	(revision 0)
++++ test/java/org/apache/ivy/plugins/parser/xml/test-extends-parent.xml	(revision 0)
+@@ -0,0 +1,34 @@
++<!--
++   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
++
++     http://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.    
++-->
++<ivy-module version="1.0">
++	<info organisation="myorg"
++	       module="myparent"
++	       revision="myrev"
++	       status="integration"
++	       publication="20091206000000">
++	       <description>Parent module description.  </description>
++	</info>
++	<configurations>
++		<conf name="default"/>
++		<conf name="conf1" visibility="public"/>
++	</configurations>
++	<dependencies>
++		<dependency name="mymodule1" rev="1.0" conf="default"/>
++	</dependencies>
++</ivy-module>