You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by xa...@apache.org on 2008/07/08 15:51:59 UTC

svn commit: r674824 - in /ant/ivy/core/trunk: ./ doc/configuration/ src/java/org/apache/ivy/core/resolve/ src/java/org/apache/ivy/plugins/namespace/ src/java/org/apache/ivy/plugins/resolver/ test/java/org/apache/ivy/core/resolve/ test/repositories/ tes...

Author: xavier
Date: Tue Jul  8 06:51:59 2008
New Revision: 674824

URL: http://svn.apache.org/viewvc?rev=674824&view=rev
Log:
NEW: Better support for local builds (IVY-857)

Added:
    ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml   (with props)
    ant/ivy/core/trunk/test/repositories/ivysettings-local.xml   (with props)
    ant/ivy/core/trunk/test/repositories/local/
    ant/ivy/core/trunk/test/repositories/local/mod1.2/
    ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/
    ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml   (with props)
    ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/mod1.2.jar   (with props)
    ant/ivy/core/trunk/test/repositories/local/mod2.1/
    ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/
    ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml   (with props)
    ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/mod2.1.jar   (with props)
Modified:
    ant/ivy/core/trunk/CHANGES.txt
    ant/ivy/core/trunk/doc/configuration/resolvers.html
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/IvyNode.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolvedModuleRevision.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/namespace/NameSpaceHelper.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java
    ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java
    ant/ivy/core/trunk/test/repositories/ivysettings.xml

Modified: ant/ivy/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/CHANGES.txt (original)
+++ ant/ivy/core/trunk/CHANGES.txt Tue Jul  8 06:51:59 2008
@@ -71,6 +71,7 @@
 
    trunk version
 =====================================
+- NEW: Better support for local builds (IVY-857)
 - NEW: Retain original dependency constraint rules in resolved ivy file (IVY-739)
 - NEW: Add a new resolve mode (optionally per module) to utilize dynamic constraint rule metadata (IVY-740)
 - NEW: Add transitive dependency version and branch override mechanism (IVY-784)

Modified: ant/ivy/core/trunk/doc/configuration/resolvers.html
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/doc/configuration/resolvers.html?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/doc/configuration/resolvers.html (original)
+++ ant/ivy/core/trunk/doc/configuration/resolvers.html Tue Jul  8 06:51:59 2008
@@ -74,8 +74,26 @@
 </tbody>
 </table>
 
-<h1><a name="common">Common attributes</a></h1>
-All resolvers of the same type share some common attributes detailed here:
+<h1><a name="common">Common features and attributes</a></h1>
+All resolvers of the same type share some common features and attributes detailed here.
+<h2>Features</h2>
+<h3>validation</h3>
+All standard resolvers support several options for validation.
+
+The validate attribute is used to configure if Ivy files should be checked against the Ivy file xml schema.
+
+The checkconsistency attribute allow to enable or disable consistency checking between what is expected by Ivy when it finds a module descriptor, and what the module descriptor actually contains.
+
+The descriptor attribute let one define if module descriptors are mandatory or optional.
+
+The checksums attribute is used to define the list of checksums files to use to check the content of downloaded files has not been corrupted (eg during transfer).
+<h3>force</h3>
+Any standard resolver can be used in force mode, which is used mainly to handle local development builds. In force mode, the resolver attempts to find a dependency whatever the requested revision is (internally it replace the requested revision by 'latest.integration'), and if it finds one, it forces this revision to be returned, even when used in a chain with returnFirst=false.
+
+By using such a resolver at the beginning of a chain, you can be sure that Ivy will pick up whatever module is available in this resolver (usually a private local build) instead of the real requested revision. This allows to handle use case like a developer working on modules A and C, where A -> B -> C, and pick up the local build for C without having to publish a local version of B.
+<span class="since">since 2.0</span>
+
+<h2>Attributes</h2>
 <table class="ivy-attributes">
 <thead>
     <tr><th class="ivy-att">Attribute</th><th class="ivy-att-desc">Description</th><th class="ivy-att-req">Required</th><th>Composite</th><th>Standard</th></tr>
@@ -91,6 +109,11 @@
         <td>Yes</td>
         <td>Yes</td>
     </tr>
+    <tr><td>force</td><td>Indicates if this resolver should be used in force mode (see above). <span class="since">since 2.0</span></td>
+        <td>No, defaults to false</td>
+        <td>No</td>
+        <td>Yes</td>
+    </tr>
     <tr><td>checkmodified</td><td>Indicates if this resolver should check lastmodified date to know if an ivy file is up to date.</td>
         <td>No, defaults to ${ivy.resolver.default.check.modified}</td>
         <td>No</td>
@@ -121,8 +144,8 @@
         <td>No</td>
         <td>Yes</td>
     </tr>
-    <tr><td>descriptor</td><td>optional if a module descriptor (usually an ivy file) is optional for this resolver, required to refuse modules without module descriptor <span class="since">since 2.0</span></td>
-        <td>No, defaults to optional</td>
+    <tr><td>descriptor</td><td>'optional' if a module descriptor (usually an ivy file) is optional for this resolver, 'required' to refuse modules without module descriptor <span class="since">since 2.0</span></td>
+        <td>No, defaults to 'optional'</td>
         <td>No (except dual)</td>
         <td>Yes</td>
     </tr>

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/IvyNode.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/IvyNode.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/IvyNode.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/IvyNode.java Tue Jul  8 06:51:59 2008
@@ -186,19 +186,20 @@
                                     + module.getResolver().getName());
                         }
 
-                        if (settings.getVersionMatcher().isDynamic(getId())) {
-                            // IVY-56: check if revision has actually been resolved
-                            if (settings.getVersionMatcher().isDynamic(module.getId())) {
-                                Message.error("impossible to resolve dynamic revision for "
-                                    + getId() + ": check your configuration and "
-                                    + "make sure revision is part of your pattern");
-                                problem = new RuntimeException(
-                                        "impossible to resolve dynamic revision");
-                                return false;
-                            }
+                        // IVY-56: check if revision has actually been resolved
+                        if (settings.getVersionMatcher().isDynamic(getId()) 
+                                && settings.getVersionMatcher().isDynamic(module.getId())) {
+                            Message.error("impossible to resolve dynamic revision for "
+                                + getId() + ": check your configuration and "
+                                + "make sure revision is part of your pattern");
+                            problem = new RuntimeException(
+                            "impossible to resolve dynamic revision");
+                            return false;
+                        }
+                        if (!getId().equals(module.getId())) {
                             IvyNode resolved = data.getNode(module.getId());
                             if (resolved != null) {
-                                // exact revision has already been resolved
+                                // found revision has already been resolved
                                 // => update it and discard this node
                                 md = module.getDescriptor(); // needed for handleConfiguration
                                 if (!handleConfiguration(loaded, rootModuleConf, parent,
@@ -211,37 +212,35 @@
 
                                 return true;
                             }
+                            String log = "\t[" + module.getId().getRevision() + "] " + getId();
+                            if (!settings.getVersionMatcher().isDynamic(getId())) {
+                                log += " (forced)";
+                            }
+                            if (settings.logResolvedRevision()) {
+                                Message.info(log);
+                            } else {
+                                Message.verbose(log);
+                            }
                         }
                         downloaded = module.getReport().isDownloaded();
                         searched = module.getReport().isSearched();
+                        loaded = true;
+                        
+                        md = module.getDescriptor();
+                        confsToFetch.remove("*");
+                        updateConfsToFetch(Arrays.asList(resolveSpecialConfigurations(
+                            getRequiredConfigurations(parent, parentConf), this)));
                     } else {
                         Message.warn("\tmodule not found: " + getId());
                         resolver.reportFailure();
                         problem = new RuntimeException("not found");
+                        return false;
                     }
                 } catch (ResolveProcessException e) {
                     throw e;
                 } catch (Exception e) {
-                    e.printStackTrace();
                     problem = e;
-                }
-
-                // still not resolved, report error
-                if (module == null) {
                     return false;
-                } else {
-                    loaded = true;
-                    if (settings.getVersionMatcher().isDynamic(getId())) {
-                        if (settings.logResolvedRevision()) {
-                            Message.info("\t[" + module.getId().getRevision() + "] " + getId());
-                        } else {
-                            Message.verbose("\t[" + module.getId().getRevision() + "] " + getId());
-                        }
-                    }
-                    md = module.getDescriptor();
-                    confsToFetch.remove("*");
-                    updateConfsToFetch(Arrays.asList(resolveSpecialConfigurations(
-                        getRequiredConfigurations(parent, parentConf), this)));
                 }
             } else {
                 loaded = true;

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolvedModuleRevision.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolvedModuleRevision.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolvedModuleRevision.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolvedModuleRevision.java Tue Jul  8 06:51:59 2008
@@ -36,6 +36,8 @@
     private ModuleDescriptor descriptor;
 
     private MetadataArtifactDownloadReport report;
+    
+    private boolean force = false;
 
     public ResolvedModuleRevision(DependencyResolver resolver, DependencyResolver artifactResolver,
             ModuleDescriptor descriptor, MetadataArtifactDownloadReport report) {
@@ -45,6 +47,15 @@
         this.report = report;
     }
 
+    public ResolvedModuleRevision(DependencyResolver resolver, DependencyResolver artifactResolver,
+            ModuleDescriptor descriptor, MetadataArtifactDownloadReport report, boolean force) {
+        this.resolver = resolver;
+        this.artifactResolver = artifactResolver;
+        this.descriptor = descriptor;
+        this.report = report;
+        this.force = force;
+    }
+
     /**
      * Returns the identifier of the resolved module.
      * 
@@ -102,7 +113,21 @@
     public MetadataArtifactDownloadReport getReport() {
         return report;
     }
-
+    
+    /**
+     * Returns <code>true</code> if this resolved module revision should be forced as the one
+     * being returned.
+     * <p>
+     * This is used as an indication for CompositeResolver, to know if they should continue to look
+     * for a better ResolvedModuleRevision if possible, or stop with this instance.
+     * </p>
+     * 
+     * @return <code>true</code> if this resolved module revision should be forced as the one
+     *         being returned.
+     */
+    public boolean isForce() {
+        return force;
+    }
 
     public boolean equals(Object obj) {
         if (!(obj instanceof ResolvedModuleRevision)) {

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/namespace/NameSpaceHelper.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/namespace/NameSpaceHelper.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/namespace/NameSpaceHelper.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/namespace/NameSpaceHelper.java Tue Jul  8 06:51:59 2008
@@ -56,7 +56,8 @@
         }
         return new ResolvedModuleRevision(
             rmr.getResolver(), rmr.getArtifactResolver(), md, 
-            transform(rmr.getReport(), ns.getToSystemTransformer()));
+            transform(rmr.getReport(), ns.getToSystemTransformer()),
+            rmr.isForce());
     }
 
     public static Artifact transform(Artifact artifact, NamespaceTransformer t) {

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java Tue Jul  8 06:51:59 2008
@@ -135,6 +135,8 @@
 
     private boolean allownomd = true;
 
+    private boolean force = false;
+
     private String checksums = null;
 
     private URLRepository extartifactrep = new URLRepository(); // used only to download
@@ -161,11 +163,15 @@
         this.envDependent = envDependent;
     }
 
-    public ResolvedModuleRevision getDependency(DependencyDescriptor dde, ResolveData data)
+    public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data)
             throws ParseException {
         IvyContext context = IvyContext.pushNewCopyContext();
-        DependencyDescriptor systemDd = dde;
-        DependencyDescriptor nsDd = fromSystem(dde);
+        if (isForce()) {
+            dd = dd.clone(ModuleRevisionId.newInstance(
+                dd.getDependencyRevisionId(), "latest.integration"));
+        }
+        DependencyDescriptor systemDd = dd;
+        DependencyDescriptor nsDd = fromSystem(dd);
         context.setDependencyDescriptor(systemDd);
         context.setResolveData(data);
         try {
@@ -187,9 +193,14 @@
                         + systemMrid
                         + " (resolved by " + rmr.getResolver().getName()
                         + "): but it's a default one, maybe we can find a better one");
+                } else if (isForce() && rmr.getResolver() != this) {
+                    Message.verbose("\t" + getName() + ": found revision in cache: " 
+                        + systemMrid
+                        + " (resolved by " + rmr.getResolver().getName()
+                        + "): but we are in force mode, let's try to find one ourself");
                 } else {
                     Message.verbose("\t" + getName() + ": revision in cache: " + systemMrid);
-                    return rmr;
+                    return checkForcedResolvedModuleRevision(rmr);
                 }
             }
             
@@ -229,7 +240,7 @@
                         new MetadataArtifactDownloadReport(systemMd.getMetadataArtifact());
                     madr.setDownloadStatus(DownloadStatus.NO);
                     madr.setSearched(true);
-                    rmr = new ResolvedModuleRevision(this, this, systemMd, madr);
+                    rmr = new ResolvedModuleRevision(this, this, systemMd, madr, isForce());
                 }
             } else {
                 if (ivyRef instanceof MDResolvedResource) {
@@ -243,13 +254,13 @@
                 }
                 if (!rmr.getReport().isDownloaded() 
                         && rmr.getReport().getLocalFile() != null) {
-                    return toSystem(rmr);
+                    return checkForcedResolvedModuleRevision(toSystem(rmr));
                 } else {
                     nsMd = rmr.getDescriptor();
 
                     // check descriptor data is in sync with resource revision and names
                     systemMd = toSystem(nsMd);
-                    if (checkconsistency) {
+                    if (isCheckconsistency()) {
                         checkDescriptorConsistency(systemMrid, systemMd, ivyRef);
                         checkDescriptorConsistency(nsMrid, nsMd, ivyRef);
                     } else {
@@ -266,7 +277,7 @@
                         }
                     }
                     rmr = new ResolvedModuleRevision(
-                        this, this, systemMd, toSystem(rmr.getReport()));
+                        this, this, systemMd, toSystem(rmr.getReport()), isForce());
                 }
             }
 
@@ -276,7 +287,7 @@
 
             cacheModuleDescriptor(systemMd, systemMrid, ivyRef, rmr);            
             
-            return rmr;
+            return checkForcedResolvedModuleRevision(rmr);
         } catch (UnresolvedDependencyException ex) {
             if (ex.getMessage().length() > 0) {
                 if (ex.isError()) {
@@ -291,6 +302,18 @@
         }
     }
 
+    private ResolvedModuleRevision checkForcedResolvedModuleRevision(ResolvedModuleRevision rmr) {
+        if (rmr == null) {
+            return null;
+        }
+        if (!isForce() || rmr.isForce()) {
+            return rmr;
+        }
+        return new ResolvedModuleRevision(
+            rmr.getResolver(), rmr.getArtifactResolver(), 
+            rmr.getDescriptor(), rmr.getReport(), true);
+    }
+
     private void cacheModuleDescriptor(ModuleDescriptor systemMd, ModuleRevisionId systemMrid,
             ResolvedResource ivyRef, ResolvedModuleRevision rmr) {
         RepositoryCacheManager cacheManager = getRepositoryCacheManager();
@@ -516,7 +539,7 @@
                 madr.setDownloadStatus(DownloadStatus.NO);
                 madr.setSearched(true);
                 return new MDResolvedResource(resource, rev, new ResolvedModuleRevision(
-                        BasicResolver.this, BasicResolver.this, md, madr));
+                        BasicResolver.this, BasicResolver.this, md, madr, isForce()));
             }
         };
     }
@@ -823,6 +846,14 @@
     public void setCheckconsistency(boolean checkConsitency) {
         checkconsistency = checkConsitency;
     }
+    
+    public void setForce(boolean force) {
+        this.force = force;
+    }
+    
+    public boolean isForce() {
+        return force;
+    }
 
     public boolean isAllownomd() {
         return allownomd;

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java Tue Jul  8 06:51:59 2008
@@ -108,14 +108,6 @@
 
         ModuleRevisionId mrid = dd.getDependencyRevisionId();
 
-
-        Message.verbose(getName() + ": Checking cache for: " + dd);
-        mr = findModuleInCache(dd, data, true);
-        if (mr != null) {
-            Message.verbose(getName() + ": module revision found in cache: " + mr.getId());
-            return resolvedRevision(mr);
-        }
-
         boolean isDynamic = getSettings().getVersionMatcher().isDynamic(mrid);
         for (Iterator iter = chain.iterator(); iter.hasNext();) {
             DependencyResolver resolver = (DependencyResolver) iter.next();
@@ -136,6 +128,7 @@
                 boolean shouldReturn = returnFirst;
                 shouldReturn |= !isDynamic
                         && ret != null && !ret.getDescriptor().isDefault();
+                shouldReturn |= mr.isForce();
                 if (!shouldReturn) {
                     // check if latest is asked and compare to return the most recent
                     String mrDesc = mr.getId()
@@ -192,7 +185,7 @@
     private ResolvedModuleRevision resolvedRevision(ResolvedModuleRevision mr) {
         if (isDual() && mr != null) {
             return new ResolvedModuleRevision(
-                mr.getResolver(), this, mr.getDescriptor(), mr.getReport());
+                mr.getResolver(), this, mr.getDescriptor(), mr.getReport(), mr.isForce());
         } else {
             return mr;
         }

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/DualResolver.java Tue Jul  8 06:51:59 2008
@@ -78,7 +78,7 @@
             }
         } else {
             return new ResolvedModuleRevision(
-                mr.getResolver(), this, mr.getDescriptor(), mr.getReport());
+                mr.getResolver(), this, mr.getDescriptor(), mr.getReport(), mr.isForce());
         }
     }
 

Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java (original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java Tue Jul  8 06:51:59 2008
@@ -768,6 +768,102 @@
             cacheMgr2.getArchiveFileInCache(depArtifact));
     }
 
+    public void testForceLocal() throws Exception {
+        // mod2.1 depends on mod1.1 which depends on mod1.2
+        // a local build for mod1.2 is available
+        Ivy ivy = new Ivy();
+        ivy.configure(new File("test/repositories/ivysettings-local.xml"));
+        ResolveReport report = ivy.resolve(new File(
+                "test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+
+        // dependencies
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.1", "1.0")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.1", "1.0", "mod1.1", "jar", "jar").exists());
+
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.2", "local-20080708091023")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.2", "local-20080708091023", 
+                                         "mod1.2", "jar", "jar").exists());
+
+        assertTrue(getArchiveFileInCache("org1", "mod1.3", "3.0", "mod1.3-A", "jar", "jar")
+            .exists());
+
+        assertFalse(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists());
+        assertFalse(getArchiveFileInCache("org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists());
+    }
+
+    public void testForceLocal2() throws Exception {
+        // mod2.3 -> mod2.1;[0.0,0.4] -> mod1.1 -> mod1.2
+        // a local build for mod2.1 and mod1.2 is available
+        Ivy ivy = new Ivy();
+        ivy.configure(new File("test/repositories/ivysettings-local.xml"));
+        ResolveReport report = ivy.resolve(new File(
+                "test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+
+        // dependencies
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org2", "mod2.1", "0.3-local-20050213110000")).exists());
+        assertTrue(getArchiveFileInCache("org2", "mod2.1", "0.3-local-20050213110000", 
+                                         "mod2.1", "jar", "jar").exists());
+
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.1", "1.1")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.1", "1.1", "mod1.1", "jar", "jar").exists());
+
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.2", "local-20080708091023")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.2", "local-20080708091023", 
+                                         "mod1.2", "jar", "jar").exists());
+
+        assertTrue(getArchiveFileInCache("org1", "mod1.3", "3.0", "mod1.3-A", "jar", "jar")
+            .exists());
+
+        assertFalse(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org2", "mod2.1", "0.4")).exists());
+        assertFalse(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists());
+        assertFalse(getArchiveFileInCache("org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists());
+    }
+
+    public void testForceLocal3() throws Exception {
+        // mod2.1 depends on mod1.1 which depends on mod1.2
+        // a local build for mod1.2 is available
+        // we do a first resolve without local build so that cache contains mod1.2;2.0 module
+        ivy.resolve(new File(
+                "test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists());
+        
+        Ivy ivy = new Ivy();
+        ivy.configure(new File("test/repositories/ivysettings-local.xml"));
+        ResolveReport report = ivy.resolve(new File(
+                "test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+
+        // dependencies
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.1", "1.0")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.1", "1.0", "mod1.1", "jar", "jar").exists());
+
+        assertTrue(getIvyFileInCache(
+            ModuleRevisionId.newInstance("org1", "mod1.2", "local-20080708091023")).exists());
+        assertTrue(getArchiveFileInCache("org1", "mod1.2", "local-20080708091023", 
+                                         "mod1.2", "jar", "jar").exists());
+
+        assertTrue(getArchiveFileInCache("org1", "mod1.3", "3.0", "mod1.3-A", "jar", "jar")
+            .exists());
+    }
+
     public void testResolveExtends() throws Exception {
         // mod6.1 depends on mod1.2 2.0 in conf default, and conf extension extends default
         ResolveReport report = ivy.resolve(new File(

Added: ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml?rev=674824&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml (added)
+++ ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml Tue Jul  8 06:51:59 2008
@@ -0,0 +1,28 @@
+<!--
+   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="org2"
+	       module="mod2.3"
+	       revision="0.8"
+	       status="integration"
+	/>
+	<dependencies>
+		<dependency name="mod2.1" rev="[0.0,0.4]"/>
+	</dependencies>
+</ivy-module>

Propchange: ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ant/ivy/core/trunk/test/repositories/1/org2/mod2.3/ivys/ivy-0.8.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/test/repositories/ivysettings-local.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/ivysettings-local.xml?rev=674824&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/repositories/ivysettings-local.xml (added)
+++ ant/ivy/core/trunk/test/repositories/ivysettings-local.xml Tue Jul  8 06:51:59 2008
@@ -0,0 +1,44 @@
+<!--
+   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.    
+-->
+<ivysettings>
+	<properties file="${ivy.settings.dir}/ivysettings.properties" />
+	<settings defaultResolver="test"/>
+	<caches defaultCacheDir="${cache.dir}" />
+	<resolvers>
+		<chain name="test">
+			<filesystem name="local" force="true">
+				<ivy pattern="${ivy.settings.dir}/local/[module]/[revision]/ivy.xml"/>
+				<artifact pattern="${ivy.settings.dir}/local/[module]/[revision]/[artifact].[ext]"/>
+			</filesystem>
+			<filesystem name="1">
+				<ivy pattern="${ivy.settings.dir}/1/[organisation]/[module]/ivys/ivy-[revision].xml"/>
+				<artifact pattern="${ivy.settings.dir}/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"/>
+			</filesystem>
+			<dual name="2">
+				<filesystem name="2-ivy">
+					<ivy pattern="${ivy.settings.dir}/2/[module]/ivy-[revision].xml"/>
+				</filesystem>
+				<filesystem name="2-artifact">
+					<artifact pattern="${ivy.settings.dir}/2/[module]/[artifact]-[revision].[ext]"/>
+					<artifact pattern="${ivy.settings.dir}/2/[module]/[artifact].[ext]"/>
+				</filesystem>
+			</dual>
+		</chain>
+	</resolvers>
+</ivysettings>

Propchange: ant/ivy/core/trunk/test/repositories/ivysettings-local.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ant/ivy/core/trunk/test/repositories/ivysettings-local.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ant/ivy/core/trunk/test/repositories/ivysettings.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/ivysettings.xml?rev=674824&r1=674823&r2=674824&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/repositories/ivysettings.xml (original)
+++ ant/ivy/core/trunk/test/repositories/ivysettings.xml Tue Jul  8 06:51:59 2008
@@ -18,7 +18,8 @@
 -->
 <ivysettings>
 	<properties file="${ivy.settings.dir}/ivysettings.properties" />
-	<settings defaultCache="${cache.dir}" defaultResolver="test"/>
+	<settings defaultResolver="test"/>
+	<caches defaultCacheDir="${cache.dir}" />
 	<resolvers>
 		<chain name="test">
 			<filesystem name="1">

Added: ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml?rev=674824&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml (added)
+++ ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml Tue Jul  8 06:51:59 2008
@@ -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="org1"
+	       module="mod1.2"
+	       revision="local-20080708091023"
+	       status="integration"
+	       publication="20080708091023"
+	/>
+	<dependencies>
+		<dependency name="mod1.3" rev="3.0">
+			<artifact name="mod1.3-A" type="jar" />
+		</dependency>
+	</dependencies>
+</ivy-module>

Propchange: ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/ivy.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/mod1.2.jar
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/mod1.2.jar?rev=674824&view=auto
==============================================================================
Binary file - no diff available.

Propchange: ant/ivy/core/trunk/test/repositories/local/mod1.2/local-20080708091023/mod1.2.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml?rev=674824&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml (added)
+++ ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml Tue Jul  8 06:51:59 2008
@@ -0,0 +1,29 @@
+<!--
+   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="org2"
+	       module="mod2.1"
+	       revision="0.3-local-20050213110000"
+	       status="integration"
+	       publication="20050213110000"
+	/>
+	<dependencies>
+		<dependency org="org1" name="mod1.1" rev="1.1"/>
+	</dependencies>
+</ivy-module>

Propchange: ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/ivy.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/mod2.1.jar
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/mod2.1.jar?rev=674824&view=auto
==============================================================================
Binary file - no diff available.

Propchange: ant/ivy/core/trunk/test/repositories/local/mod2.1/0.3-local-20050213110000/mod2.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream