Repository: ant-ivy
Updated Branches:
  refs/heads/master c07d659cf -> 545536e34


IVY-1475 Throw an error if a common base directory cannot be determined for 
cachefileset task


Project: http://git-wip-us.apache.org/repos/asf/ant-ivy/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant-ivy/commit/7f293a06
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/7f293a06
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/7f293a06

Branch: refs/heads/master
Commit: 7f293a06a0b7ec9b554d51f150991efa9b7dd54e
Parents: c07d659
Author: Jaikiran Pai <jaikiran....@gmail.com>
Authored: Fri Jun 2 16:57:36 2017 +0530
Committer: Jaikiran Pai <jaikiran....@gmail.com>
Committed: Tue Jun 13 15:17:51 2017 +0530

----------------------------------------------------------------------
 doc/use/cachefileset.html                       |   8 +-
 .../org/apache/ivy/ant/IvyCacheFileset.java     | 120 ++++++++++++-------
 .../org/apache/ivy/ant/IvyCacheFilesetTest.java |  37 +++++-
 3 files changed, 120 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/7f293a06/doc/use/cachefileset.html
----------------------------------------------------------------------
diff --git a/doc/use/cachefileset.html b/doc/use/cachefileset.html
index aeba54f..747db0d 100644
--- a/doc/use/cachefileset.html
+++ b/doc/use/cachefileset.html
@@ -32,7 +32,13 @@ Please prefer the use of retrieve + standard ant path 
creation, which make your
 more independent from ivy (once artifacts are properly retrieved, ivy is not 
required any more).<br/><br/>
 Built fileset is registered in ant with a given id, and can thus be used like 
any other ant fileset using
 refid.
-  
+
+<h2>Limitation</h2>
+A fileset, in Ant, requires a base directory from within which the files are 
included/excluded. The cachefileset task, in Ivy, internally tries to determine 
a common base directory across all the resolved artifacts' files that have been 
downloaded in the Ivy repository cache(s). Given that Ivy can be configured to 
consist multiple repository caches and each one can potentially be on a 
different filesystem root, there are times, when cachefileset cannot determine 
a common base directory for these resolved artifacts. The cachefileset throws 
an exception in such cases.
+
+<h2>Alternative task</h2>
+If cachefileset doesn't fit the need of your use case (maybe due to the 
limitations noted above), the [[use/resources]] task could be an alternative 
task to use in certain cases.
+
 <table class="ant">
 <thead>
     <tr><th class="ant-att">Attribute</th><th 
class="ant-desc">Description</th><th class="ant-req">Required</th></tr>

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/7f293a06/src/java/org/apache/ivy/ant/IvyCacheFileset.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/ant/IvyCacheFileset.java 
b/src/java/org/apache/ivy/ant/IvyCacheFileset.java
index 9a60f2e..bc85eaf 100644
--- a/src/java/org/apache/ivy/ant/IvyCacheFileset.java
+++ b/src/java/org/apache/ivy/ant/IvyCacheFileset.java
@@ -60,35 +60,68 @@ public class IvyCacheFileset extends IvyCacheTask {
             throw new BuildException("setid is required in ivy cachefileset");
         }
         try {
-            List paths = getArtifactReports();
-            File base = null;
-            for (Iterator iter = paths.iterator(); iter.hasNext();) {
-                ArtifactDownloadReport a = (ArtifactDownloadReport) 
iter.next();
-                if (a.getLocalFile() != null) {
-                    base = getBaseDir(base, a.getLocalFile());
+            final List<ArtifactDownloadReport> artifactDownloadReports = 
getArtifactReports();
+            if (artifactDownloadReports.isEmpty()) {
+                // generate an empty fileset
+                final FileSet emptyFileSet = new EmptyFileSet();
+                emptyFileSet.setProject(getProject());
+                getProject().addReference(setid, emptyFileSet);
+                return;
+            }
+            // find a common base dir of the resolved artifacts
+            final File baseDir = 
this.requireCommonBaseDir(artifactDownloadReports);
+            final FileSet fileset = new FileSet();
+            fileset.setDir(baseDir);
+            fileset.setProject(getProject());
+            // enroll each of the artifact files into the fileset
+            for (final ArtifactDownloadReport artifactDownloadReport : 
artifactDownloadReports) {
+                if (artifactDownloadReport.getLocalFile() == null) {
+                    continue;
                 }
+                final NameEntry ne = fileset.createInclude();
+                ne.setName(getPath(baseDir, 
artifactDownloadReport.getLocalFile()));
             }
+            getProject().addReference(setid, fileset);
+        } catch (Exception ex) {
+            throw new BuildException("impossible to build ivy cache fileset: " 
+ ex, ex);
+        }
+    }
 
-            FileSet fileset;
+    /**
+     * Returns a common base directory, determined from the {@link 
ArtifactDownloadReport#getLocalFile() local files} of the
+     * passed <code>artifactDownloadReports</code>. If no common base 
directory can be determined, this method throws a
+     * {@link BuildException}
+     *
+     * @param artifactDownloadReports The artifact download reports for which 
the common base directory of the artifacts
+     *                                has to be determined
+     * @return
+     */
+    private File requireCommonBaseDir(final List<ArtifactDownloadReport> 
artifactDownloadReports) {
+        File base = null;
+        for (final ArtifactDownloadReport artifactDownloadReport : 
artifactDownloadReports) {
+            if (artifactDownloadReport.getLocalFile() == null) {
+                continue;
+            }
             if (base == null) {
-                fileset = new EmptyFileSet();
+                // use the parent dir of the artifact as the base
+                base = 
artifactDownloadReport.getLocalFile().getParentFile().getAbsoluteFile();
             } else {
-                fileset = new FileSet();
-                fileset.setDir(base);
-                for (Iterator iter = paths.iterator(); iter.hasNext();) {
-                    ArtifactDownloadReport a = (ArtifactDownloadReport) 
iter.next();
-                    if (a.getLocalFile() != null) {
-                        NameEntry ne = fileset.createInclude();
-                        ne.setName(getPath(base, a.getLocalFile()));
-                    }
+                // try and find a common base directory between the current 
base
+                // directory and the artifact's file
+                base = getBaseDir(base, artifactDownloadReport.getLocalFile());
+                if (base == null) {
+                    // fail fast - we couldn't determine a common base 
directory, throw an error
+                    throw new BuildException("Cannot find a common base 
directory, from resolved artifacts, " +
+                            "for generating a cache fileset");
                 }
             }
-
-            fileset.setProject(getProject());
-            getProject().addReference(setid, fileset);
-        } catch (Exception ex) {
-            throw new BuildException("impossible to build ivy cache fileset: " 
+ ex, ex);
         }
+        if (base == null) {
+            // finally, we couldn't determine a common base directory, throw 
an error
+            throw new BuildException("Cannot find a common base directory, 
from resolved artifacts, for generating " +
+                    "a cache fileset");
+        }
+        return base;
     }
 
     /**
@@ -115,34 +148,35 @@ public class IvyCacheFileset extends IvyCacheTask {
     }
 
     /**
-     * Returns the common base directory between a current base directory and 
a given file.
+     * Returns the common base directory between the passed <code>file1</code> 
and <code>file2</code>.
      * <p>
-     * The returned base directory must be a parent of both the current base 
and the given file.
+     * The returned base directory must be a parent of both the 
<code>file1</code> and <code>file2</code>.
      * </p>
      *
-     * @param base
-     *            the current base directory, may be null.
-     * @param file
-     *            the file for which the new base directory should be returned.
-     * @return the common base directory between a current base directory and 
a given file.
+     * @param file1
+     *            One of the files, for which the common base directory is 
being sought, may be null.
+     * @param file2
+     *            The other file for which the common base directory should be 
returned.
+     * @return the common base directory between a <code>file1</code> and 
<code>file2</code>. Returns null
+     *          if no common base directory could be determined or if either 
<code>file1</code> or <code>file2</code>
+     *          is null
      */
-    File getBaseDir(File base, File file) {
-        if (base == null) {
-            return file.getParentFile().getAbsoluteFile();
-        } else {
-            Iterator bases = getParents(base).iterator();
-            Iterator fileParents = 
getParents(file.getAbsoluteFile()).iterator();
-            File result = null;
-            while (bases.hasNext() && fileParents.hasNext()) {
-                File next = (File) bases.next();
-                if (next.equals(fileParents.next())) {
-                    result = next;
-                } else {
-                    break;
-                }
+    File getBaseDir(final File file1, final File file2) {
+        if (file1 == null || file2 == null) {
+            return null;
+        }
+        final Iterator bases = getParents(file1).iterator();
+        final Iterator fileParents = 
getParents(file2.getAbsoluteFile()).iterator();
+        File result = null;
+        while (bases.hasNext() && fileParents.hasNext()) {
+            File next = (File) bases.next();
+            if (next.equals(fileParents.next())) {
+                result = next;
+            } else {
+                break;
             }
-            return result;
         }
+        return result;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/7f293a06/test/java/org/apache/ivy/ant/IvyCacheFilesetTest.java
----------------------------------------------------------------------
diff --git a/test/java/org/apache/ivy/ant/IvyCacheFilesetTest.java 
b/test/java/org/apache/ivy/ant/IvyCacheFilesetTest.java
index fb01916..dbb98f7 100644
--- a/test/java/org/apache/ivy/ant/IvyCacheFilesetTest.java
+++ b/test/java/org/apache/ivy/ant/IvyCacheFilesetTest.java
@@ -173,12 +173,47 @@ public class IvyCacheFilesetTest {
     public void testGetBaseDir() {
         File base = null;
         base = fileset.getBaseDir(base, new File("x/aa/b/c"));
-        assertEquals(new File("x/aa/b").getAbsoluteFile(), base);
+        assertNull("Base directory was expected to be null", base);
+
+        base = new File("x/aa/b/c").getParentFile().getAbsoluteFile();
 
         base = fileset.getBaseDir(base, new File("x/aa/b/d/e"));
         assertEquals(new File("x/aa/b").getAbsoluteFile(), base);
 
         base = fileset.getBaseDir(base, new File("x/ab/b/d"));
         assertEquals(new File("x").getAbsoluteFile(), base);
+
+        final File[] filesytemRoots = File.listRoots();
+        final File root1 = filesytemRoots[0];
+        final File file1 = new File(root1, "abcd/xyz");
+        final File file2 = new File(root1, "pqrs/xyz");
+        final File commonBase = fileset.getBaseDir(file1, file2);
+        assertEquals("Unexpected common base dir between '" + file1 + "' and 
'" + file2 + "'", root1.getAbsoluteFile(), commonBase.getAbsoluteFile());
+
+    }
+
+    /**
+     * Tests that the {@link IvyCacheFileset} fails with an exception if it 
can't determine a common base directory
+     * while dealing with cached artifacts
+     *
+     * @see <a 
href="https://issues.apache.org/jira/browse/IVY-1475";>IVY-1475</a> for more 
details
+     */
+    @Test
+    public void testNoCommonBaseDir() {
+        final File[] fileSystemRoots = File.listRoots();
+        if (fileSystemRoots.length == 1) {
+            // single file system root isn't what we are interested in, in 
this test method
+            return;
+        }
+        // we expect a BuildException when we try to find a (non-existent) 
common base dir
+        // across file system roots
+        expExc.expect(BuildException.class);
+
+        final File root1 = fileSystemRoots[0];
+        final File root2 = fileSystemRoots[1];
+        final File fileOnRoot1 = new File(root1, "abc/file1");
+        final File fileOnRoot2 = new File(root2, "abc/file2");
+        fileset.getBaseDir(fileOnRoot1, fileOnRoot2);
+        fail("A BuildException was expected when trying to find a common base 
dir between '" + fileOnRoot1 + "' and '" + fileOnRoot2 + "'");
     }
 }

Reply via email to