Author: hibou
Date: Sat Nov 20 10:07:31 2010
New Revision: 1037152

URL: http://svn.apache.org/viewvc?rev=1037152&view=rev
Log:
IVY-1248: Module inheritance sometimes fails to locate parent descriptor in 
deliver process (thanks to Jean-Louis Boudart)

Modified:
    ant/ivy/core/trunk/CHANGES.txt
    
ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
    ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java

Modified: ant/ivy/core/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=1037152&r1=1037151&r2=1037152&view=diff
==============================================================================
--- ant/ivy/core/trunk/CHANGES.txt (original)
+++ ant/ivy/core/trunk/CHANGES.txt Sat Nov 20 10:07:31 2010
@@ -124,6 +124,7 @@ for detailed view of each issue, please 
 - FIX: UseCacheOnly doesn't respect the cache configuration in the ivysettings 
(IVY-1227)
 - FIX: UseCacheOnly is influenced by the TTL on cached metadata (IVY-1243)
 - FIX: ConcurrentModificationException on ivy settings loading (IVY-1250)
+- FIX: Module inheritance sometimes fails to locate parent descriptor in 
deliver process (IVY-1248) (thanks to Jean-Louis Boudart)
 
    2.2.0
 =====================================

Modified: 
ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
URL: 
http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java?rev=1037152&r1=1037151&r2=1037152&view=diff
==============================================================================
--- 
ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
 (original)
+++ 
ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
 Sat Nov 20 10:07:31 2010
@@ -362,14 +362,30 @@ public class XmlModuleDescriptorParser e
             }
         }
 
+        /**
+         * Default parent location to check (for dev ONLY) 
+         * @return a relative path to a parent module descriptor
+         */
         protected String getDefaultParentLocation() {
             return "../ivy.xml";
         }
 
+        /**
+         * Handle extends elements.
+         * It checks :
+         *  <ul>
+         *      <li>filesystem based on location attribute, if no one is 
specified it will check the default parent location</li>
+         *      <li>cache to find a resolved parent descriptor</li>
+         *      <li>ask repositories to retrieve the parent module 
descriptor</li>
+         *  </ul>
+         * @param attributes 
+         * @throws ParseException 
+         */
         protected void extendsStarted(Attributes attributes) throws 
ParseException {
             String parentOrganisation = attributes.getValue("organisation");
             String parentModule = attributes.getValue("module");
-            String parentRevision = attributes.getValue("revision");
+            String parentRevision = attributes.getValue("revision") != null ? 
attributes
+                    .getValue("revision") : Ivy.getWorkingRevision();
             String location = attributes.getValue("location") != null ? 
attributes
                     .getValue("location") : getDefaultParentLocation();
             ModuleDescriptor parent = null;
@@ -378,17 +394,19 @@ public class XmlModuleDescriptorParser e
                 "extendType").toLowerCase() : "all";
 
             List/* <String> */extendTypes = 
Arrays.asList(extendType.split(","));
+            ModuleId parentMid = new ModuleId(parentOrganisation, 
parentModule);
+            ModuleRevisionId parentMrid = new ModuleRevisionId(parentMid, 
parentRevision);
 
+
+            //check on filesystem based on location attribute (for dev ONLY)
             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)) {
+                if (!parentMid.equals(pid)) {
                     Message.verbose("Ignoring parent Ivy file " + location + 
"; expected "
-                        + expected + " but found " + pid);
+                        + parentMrid + " but found " + pid);
                     parent = null;
                 }
                 
@@ -399,32 +417,28 @@ public class XmlModuleDescriptorParser e
                 Message.warn("Unable to parse included ivy file " + location + 
": " 
                     + e.getMessage());
             }
+            
+            // if not found on file system, check in the cache
+            if (parent ==null) {
+                parent = parseOtherIvyFileInCache(parentMrid);
+            }
 
-            // if the included ivy file is not found on file system, tries to 
resolve using
-            // repositories
+            // if not found, 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);
+                    parent = parseOtherIvyFile(parentMrid);
                 } catch (ParseException e) {
-                    Message.warn("Unable to parse included ivy file for " + 
parentOrganisation
-                            + "#" + parentModule + ";" + parentRevision);
+                    Message.warn("Unable to parse included ivy file for " + 
parentMrid.toString());
                 }
             }
-
+            
+            // if still not found throw an exception
             if (parent == null) {
                 throw new ParseException("Unable to parse included ivy file 
for "
-                        + parentOrganisation + "#" + parentModule + ";" + 
parentRevision, 0);
+                        + parentMrid.toString(), 0);
             }
 
             ResolutionCacheManager cacheManager = 
settings.getResolutionCacheManager();
-
             File ivyFileInCache = cacheManager.getResolvedIvyFileInCache(parent
                     .getResolvedModuleRevisionId());
             //Generate the parent cache file if necessary
@@ -434,11 +448,11 @@ public class XmlModuleDescriptorParser e
                     parent.toIvyFile(ivyFileInCache);
                 } catch (ParseException e) {
                     throw new ParseException("Unable to create cache file for "
-                            + parentOrganisation + "#" + parentModule + ";" + 
parentRevision
+                            + parentMrid.toString()
                             + " Reason:" + e.getLocalizedMessage(), 0);
                 } catch (IOException e) {
                     throw new ParseException("Unable to create cache file for "
-                            + parentOrganisation + "#" + parentModule + ";" + 
parentRevision
+                            + parentMrid.toString()
                             + " Reason :" + e.getLocalizedMessage(), 0);
                 }
             }
@@ -453,6 +467,11 @@ public class XmlModuleDescriptorParser e
             mergeWithOtherModuleDescriptor(extendTypes, parent);
         }
 
+        /**
+         * Merge current module with a given module descriptor and specify 
what should be inherited through extendTypes argument
+         * @param extendTypes specify what should be inherited
+         * @param parent a given parent module descriptor
+         */
         protected void mergeWithOtherModuleDescriptor(List/* <String> 
*/extendTypes,
                 ModuleDescriptor parent) {
 
@@ -478,6 +497,10 @@ public class XmlModuleDescriptorParser e
 
         }
 
+        /**
+         * Merge everything from a given parent
+         * @param parent a given parent module desciptor
+         */
         protected void mergeAll(ModuleDescriptor parent) {
             ModuleRevisionId sourceMrid = parent.getModuleRevisionId();
             mergeInfo(parent);
@@ -485,7 +508,11 @@ public class XmlModuleDescriptorParser e
             mergeDependencies(parent.getDependencies());
             mergeDescription(parent.getDescription());
         }
-        
+
+        /**
+         * Explain how to inherit metadatas related to info element
+         * @param parent a given parent module decriptor
+         */
         protected void mergeInfo(ModuleDescriptor parent) {
             ModuleRevisionId parentMrid = parent.getModuleRevisionId();
 
@@ -522,6 +549,11 @@ public class XmlModuleDescriptorParser e
             return dup;
         }
 
+        /**
+         * Describes how to merge configurations elements
+         * @param sourceMrid the source module revision id
+         * @param configurations array of configurations to be inherited 
+         */
         protected void mergeConfigurations(ModuleRevisionId sourceMrid, 
Configuration[] configurations) {
             DefaultModuleDescriptor md = getMd();
             for (int i = 0; i < configurations.length; i++) {
@@ -532,6 +564,10 @@ public class XmlModuleDescriptorParser e
             }
         }
 
+        /**
+         * Describes how dependencies should be inherited
+         * @param dependencies array of dependencies to inherit
+         */
         protected void mergeDependencies(DependencyDescriptor[] dependencies) {
             DefaultModuleDescriptor md = getMd();
             for (int i = 0; i < dependencies.length; i++) {
@@ -542,6 +578,10 @@ public class XmlModuleDescriptorParser e
             }
         }
 
+        /**
+         * Describes how to merge description
+         * @param description description going to be inherited
+         */
         protected void mergeDescription(String description) {
             String current = getMd().getDescription();
             if (current == null || current.trim().length() == 0) {
@@ -549,12 +589,20 @@ public class XmlModuleDescriptorParser e
             }
         }
 
+        /**
+         * Describes how to parse another ivy file on filesystem 
+         * @param location a given location
+         * @return a {...@link ModuleDescriptor} if found. Return null if no 
{...@link ModuleDescriptor} was found
+         * @throws ParseException
+         * @throws IOException
+         */
         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());
+            Message.debug("Trying to load included ivy file from " + 
url.toString() + " location was " + location);
+
             URLResource res = new URLResource(url);
             ModuleDescriptorParser parser = 
ModuleDescriptorParserRegistry.getInstance().getParser(
                 res);
@@ -563,27 +611,16 @@ public class XmlModuleDescriptorParser e
             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());
-                }
-            }
-
+        /**
+         * Describe how to parse a {...@link ModuleDescriptor} by asking 
repositories
+         * @param parentMrid a given {...@link ModuleRevisionId} to find
+         * @return a {...@link ModuleDescriptor} if found. Return null if no 
{...@link ModuleDescriptor} was found
+         * @throws ParseException
+         */
+        protected ModuleDescriptor parseOtherIvyFile(ModuleRevisionId 
parentMrid) throws ParseException {
+            Message.debug(
+                "Trying to parse included ivy file by asking repository for 
module :"
+                            + parentMrid.toString());
             DependencyDescriptor dd = new 
DefaultDependencyDescriptor(parentMrid, true);
             ResolveData data = IvyContext.getContext().getResolveData();
             if (data == null) {
@@ -608,6 +645,30 @@ public class XmlModuleDescriptorParser e
 
         }
 
+        /**
+         * Describes how to parse ivy file from cache
+         * @param parentMrid a given {...@link ModuleRevisionId} to find
+         * @return a {...@link ModuleDescriptor} if found. Return null if no 
{...@link ModuleDescriptor} was found
+         * @throws ParseException
+         */
+        protected ModuleDescriptor parseOtherIvyFileInCache(ModuleRevisionId 
parentMrid) throws ParseException {
+            // try to load parent module in cache
+            File cacheFile = 
settings.getResolutionCacheManager().getResolvedIvyFileInCache(parentMrid);
+            if (cacheFile.exists() && cacheFile.length() > 0) {
+                ModuleDescriptor md;
+                try {
+                    Message.debug("Trying to load included ivy file from cache 
" + cacheFile.getAbsolutePath());
+                    URL parentUrl = cacheFile.toURI().toURL();
+                    md = parseOtherIvyFileOnFileSystem(parentUrl.toString());
+                    return md;
+                } catch (IOException e) {
+                    // do nothing
+                    Message.error(e.getLocalizedMessage());
+                }
+            }
+            return null;
+        }
+
         protected void publicationsStarted(Attributes attributes) {
             state = State.PUB;
             artifactsDeclared = true;

Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java
URL: 
http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java?rev=1037152&r1=1037151&r2=1037152&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java 
(original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java Sat Nov 
20 10:07:31 2010
@@ -146,6 +146,55 @@ public class IvyPublishTest extends Test
         }
     }
     
+    public void testMergeParentWithoutPublishingParent() throws IOException, 
ParseException {
+        //here we directly publish a module extending ivy-multiconf.xml, 
+        //the module parent is not published not yet in cache
+        //See : IVY-1248
+        
+        //update=true implies merge=true
+        project.setProperty("ivy.dep.file", 
"test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml");
+        publish.setResolver("1");
+        publish.setUpdate(true);
+        publish.setOrganisation("apache");
+        publish.setModule("resolve-extends");
+        publish.setRevision("1.0");
+        publish.setPubrevision("1.2");
+        publish.setStatus("release");
+        
publish.addArtifactspattern("test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml");
+        publish.execute();
+
+        // should have published the files with "1" resolver
+        File published = new 
File("test/repositories/1/apache/resolve-extends/ivys/ivy-1.2.xml");
+        assertTrue(published.exists());
+
+        // do a text compare, since we want to test comments as well as 
structure.
+        // we could do a better job of this with xmlunit
+
+        int lineNo = 1;
+
+        BufferedReader merged = new BufferedReader(new FileReader(published));
+        BufferedReader expected = new BufferedReader(new 
InputStreamReader(getClass()
+            .getResourceAsStream("ivy-extends-merged.xml")));
+        for (String mergeLine = merged.readLine(),
+                    expectedLine = expected.readLine(); 
+            mergeLine != null && expectedLine != null; 
+            mergeLine = merged.readLine(),
+            expectedLine = expected.readLine()) {
+
+            //strip timestamps for the comparison
+            if (mergeLine.indexOf("<info") >= 0) {
+                mergeLine = mergeLine.replaceFirst("\\s?publication=\"\\d+\"", 
"");
+            }
+            //discard whitespace-only lines
+            if (!(mergeLine.trim().equals("") && 
expectedLine.trim().equals(""))) {
+                assertEquals("published descriptor matches at line[" + lineNo 
+ "]", expectedLine, mergeLine);
+            }
+
+            ++lineNo;
+        }
+    }
+
+    
     public void testMinimalMerge() throws IOException, ParseException {
         //publish the parent descriptor first, so that it can be found while
         //we are reading the child descriptor.


Reply via email to