Repository: ant-ivy
Updated Branches:
  refs/heads/master 080e96a6c -> 366fb741f


Use Java standard API for symlink handling and deprecate symlinkinmass option 
on retrieve 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/366fb741
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/366fb741
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/366fb741

Branch: refs/heads/master
Commit: 366fb741f0772c8309f9dfe963f6032b091d7b89
Parents: 080e96a
Author: Jaikiran Pai <jaiki...@apache.org>
Authored: Thu Jul 27 11:53:25 2017 +0530
Committer: Jaikiran Pai <jaiki...@apache.org>
Committed: Thu Jul 27 19:31:57 2017 +0530

----------------------------------------------------------------------
 asciidoc/release-notes.adoc                     |   2 +
 asciidoc/use/retrieve.adoc                      |  13 +-
 src/java/org/apache/ivy/ant/IvyRetrieve.java    |  26 ++--
 .../ivy/core/retrieve/RetrieveEngine.java       |  44 +++----
 .../ivy/core/retrieve/RetrieveOptions.java      |  23 +++-
 src/java/org/apache/ivy/util/FileUtil.java      | 124 +++----------------
 .../apache/ivy/core/retrieve/RetrieveTest.java  |  82 +++++++++---
 7 files changed, 135 insertions(+), 179 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/asciidoc/release-notes.adoc
----------------------------------------------------------------------
diff --git a/asciidoc/release-notes.adoc b/asciidoc/release-notes.adoc
index 6623217..5f541c6 100644
--- a/asciidoc/release-notes.adoc
+++ b/asciidoc/release-notes.adoc
@@ -73,6 +73,8 @@ For details about the following changes, check our JIRA 
install at link:https://
 - IMPROVEMENT: Throw an IllegalStateException when retrieving the 
resolutionCacheRoot on the DefaultResolutionCacheManager if the basedir (or 
IvySettings) is not set (jira:IVY-1482[])
 - IMPROVEMENT: Optimization: limit the revision numbers scanned if revision 
prefix is specified (Thanks to Ernestas Vaiciukevi&#269;ius)
 - IMPROVEMENT: Update bouncycastle to 1.52 (jira:IVY-1521[]) (Thanks to Michal 
Srb)
+- IMPROVEMENT: `symlinkmass` option of retrieve task has been deprecated in 
this release and will no longer be supported since, starting this version of 
Ivy, Ivy uses Java standard API(s) for symlink management and as such doesn't 
spawn a process to execute symlink creation shell commands, like it used to do 
eariler. The `symlinkmass` option was previously there to launch just one 
single process instead of multiple processes for symlink creation. Now with the 
usage of the Java standard API(s), this option no longer is relevant.
+
 
 - NEW: Lets ssh-based resolvers use an ~/.ssh/config file to find 
username/hostname/keyfile options (Thanks to Colin Stanfill)
 - NEW: Add ivy.maven.lookup.sources and ivy.maven.lookup.javadoc variables to 
control the lookup of the additional artifacts. Defaults to true, for backward 
compatibility (jira:IVY-1529[])

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/asciidoc/use/retrieve.adoc
----------------------------------------------------------------------
diff --git a/asciidoc/use/retrieve.adoc b/asciidoc/use/retrieve.adoc
index 8aaf9ee..6b1bde2 100644
--- a/asciidoc/use/retrieve.adoc
+++ b/asciidoc/use/retrieve.adoc
@@ -49,15 +49,12 @@ Possible values are: +
 * `never`: never overwrite the destination file +
 |No. Defaults to `newer`.
 |symlink|`true` to create symbolic links, `false` to copy the artifacts.
-    The destination of the symbolic links depends on the value of the 
`useOrigin` attribute.
-    (requires `ln` to be a valid command, and to support the options `-s` and 
`-f` (works on UNIX/Linux, on other systems you may need to script `ln`)
+    The destination of the symbolic links depends on the value of the 
`useOrigin` attribute. +
+    The implementation of this task relies on Java standard 
`Files.createSymbolicLink` API and depending on whether or not the underlying
+    filesystem supports symbolic links, creation of such symbolic links may or 
may not work. +
+    If this option is set to `true` and symbolic link creation fails, then the 
retrieve task will attempt to do a regular copy of the artifact which failed 
symlink creation.
     *__(since 2.0)__*|No. Defaults to `false`
-|symlinkmass|`true` to create symbolic links in mass, `false` to copy the 
artifacts. +
-`symlinkmass` overrides `symlink` if both are set to `true`. +
-`symlinkmass` will create the same symbolic links `symlink` does, but with a 
single process call to `sh` with batched `ln` commands passed in as standard 
input (works on UNIX/Linux, on other systems you may need to script it). For 
large lists of resolved jars, this can be dramatically faster. +
-The destination of the symbolic links depends on the value of the `useOrigin` 
attribute. +
-The events `StartRetrieveArtifactEvent` and `EndRetrieveEvent` are __NOT__ 
fired by this activity, because it is not clear when they should be called.
-    *__(since 2.4)__*|No. Defaults to `false`
+|symlinkmass| *__Deprecated since 2.5__* This option is no longer supported or 
relevant starting 2.5 version of Ivy|No. Defaults to `false`
 |settingsRef|A reference to the ivy settings that must be used by this task 
*__(since 2.0)__*|No, defaults ot `ivy.instance`.
 |log|the log setting to use during the resolve and retrieve process. *__(since 
2.0)__*
 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/src/java/org/apache/ivy/ant/IvyRetrieve.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/ant/IvyRetrieve.java 
b/src/java/org/apache/ivy/ant/IvyRetrieve.java
index f90403a..3930617 100644
--- a/src/java/org/apache/ivy/ant/IvyRetrieve.java
+++ b/src/java/org/apache/ivy/ant/IvyRetrieve.java
@@ -95,17 +95,19 @@ public class IvyRetrieve extends IvyPostResolveTask {
 
         pattern = getProperty(pattern, getSettings(), "ivy.retrieve.pattern");
         try {
-            Filter<Artifact> artifactFilter = getArtifactFilter();
-            RetrieveReport report = getIvyInstance().retrieve(
-                getResolvedMrid(),
-                ((RetrieveOptions) new RetrieveOptions().setLog(getLog()))
-                        
.setConfs(splitConfs(getConf())).setDestArtifactPattern(pattern)
-                        
.setDestIvyPattern(ivypattern).setArtifactFilter(artifactFilter)
-                        .setSync(sync).setOverwriteMode(getOverwriteMode())
-                        .setUseOrigin(isUseOrigin()).setMakeSymlinks(symlink)
-                        
.setMakeSymlinksInMass(symlinkmass).setResolveId(getResolveId())
-                        .setMapper(mapper == null ? null : new 
MapperAdapter(mapper)));
-
+            final Filter<Artifact> artifactFilter = getArtifactFilter();
+            final RetrieveOptions retrieveOptions = (RetrieveOptions) new 
RetrieveOptions().setLog(getLog());
+            
retrieveOptions.setConfs(splitConfs(getConf())).setDestArtifactPattern(pattern)
+                    
.setDestIvyPattern(ivypattern).setArtifactFilter(artifactFilter)
+                    .setSync(sync).setOverwriteMode(getOverwriteMode())
+                    .setUseOrigin(isUseOrigin()).setMakeSymlinks(symlink)
+                    .setResolveId(getResolveId())
+                    .setMapper(mapper == null ? null : new 
MapperAdapter(mapper));
+            // only set this if the user has explicitly enabled this 
deprecated option
+            if (symlinkmass) {
+                retrieveOptions.setMakeSymlinksInMass(symlinkmass);
+            }
+            final RetrieveReport report = 
getIvyInstance().retrieve(getResolvedMrid(), retrieveOptions);
             int targetsCopied = report.getNbrArtifactsCopied();
             boolean haveTargetsBeenCopied = targetsCopied > 0;
             getProject().setProperty("ivy.nb.targets.copied", 
String.valueOf(targetsCopied));
@@ -171,7 +173,9 @@ public class IvyRetrieve extends IvyPostResolveTask {
      * Option to create symlinks in one mass action, instead of separately.
      *
      * @param symlinkmass boolean
+     * @deprecated Starting 2.5, symlinking in mass isn't supported
      */
+    @Deprecated
     public void setSymlinkmass(boolean symlinkmass) {
         this.symlinkmass = symlinkmass;
     }

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java 
b/src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java
index 9fcf80a..e3d16a7 100644
--- a/src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java
+++ b/src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java
@@ -120,7 +120,6 @@ public class RetrieveEngine {
         }
 
         try {
-            Map<File, File> destToSrcMap = null;
             Map<ArtifactDownloadReport, Set<String>> artifactsToCopy = 
determineArtifactsToCopy(
                 mrid, destFilePattern, options);
             File fileRetrieveRoot = settings.resolveFile(IvyPatternHelper
@@ -133,12 +132,6 @@ public class RetrieveEngine {
             // for sync)
             Collection<File> targetIvysStructure = new HashSet<>(); // same 
for ivy files
 
-            if (options.isMakeSymlinksInMass()) {
-                // The HashMap is of "destToSrc" because src could go two 
places, but dest can only
-                // come from one
-                destToSrcMap = new HashMap<>();
-            }
-
             // do retrieve
             long totalCopiedSize = 0;
             for (Entry<ArtifactDownloadReport, Set<String>> artifactAndPaths : 
artifactsToCopy
@@ -160,29 +153,27 @@ public class RetrieveEngine {
                     if (!settings.isCheckUpToDate() || !upToDate(archive, 
destFile, options)) {
                         Message.verbose("\t\tto " + destFile);
                         if (this.eventManager != null) {
-                            // There is no unitary event for the mass sym 
linking.
-                            // skip the event declaration.
-                            if (!options.isMakeSymlinksInMass()) {
-                                this.eventManager.fireIvyEvent(new 
StartRetrieveArtifactEvent(
-                                        artifact, destFile));
-                            }
+                            this.eventManager.fireIvyEvent(new 
StartRetrieveArtifactEvent(artifact, destFile));
                         }
-                        if (options.isMakeSymlinksInMass()) {
-                            if (FileUtil.prepareCopy(archive, destFile, true)) 
{
-                                destToSrcMap.put(destFile, archive);
+                        if (options.isMakeSymlinks()) {
+                            boolean symlinkCreated;
+                            try {
+                                symlinkCreated = FileUtil.symlink(archive, 
destFile,  true);
+                            } catch (IOException ioe) {
+                                symlinkCreated = false;
+                                // warn about the inability to create a symlink
+                                Message.warn("symlink creation failed at path 
" + destFile, ioe);
+                            }
+                            if (!symlinkCreated) {
+                                // since symlink creation failed, let's 
attempt to an actual copy instead
+                                Message.info("Attempting a copy operation 
(since symlink creation failed) at path " + destFile);
+                                FileUtil.copy(archive, destFile, null, true);
                             }
-                        } else if (options.isMakeSymlinks()) {
-                            FileUtil.symlink(archive, destFile, null, true);
                         } else {
                             FileUtil.copy(archive, destFile, null, true);
                         }
                         if (this.eventManager != null) {
-                            // There is no unitary event for the mass sym 
linking.
-                            // skip the event declaration.
-                            if (!options.isMakeSymlinksInMass()) {
-                                this.eventManager.fireIvyEvent(new 
EndRetrieveArtifactEvent(
-                                        artifact, destFile));
-                            }
+                            this.eventManager.fireIvyEvent(new 
EndRetrieveArtifactEvent(artifact, destFile));
                         }
                         totalCopiedSize += FileUtil.getFileLength(destFile);
                         report.addCopiedFile(destFile, artifact);
@@ -205,11 +196,6 @@ public class RetrieveEngine {
                 }
             }
 
-            if (options.isMakeSymlinksInMass()) {
-                Message.verbose("\tMass symlinking " + destToSrcMap.size() + " 
files");
-                FileUtil.symlinkInMass(destToSrcMap, true);
-            }
-
             if (options.isSync()) {
                 Message.verbose("\tsyncing...");
 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/src/java/org/apache/ivy/core/retrieve/RetrieveOptions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/core/retrieve/RetrieveOptions.java 
b/src/java/org/apache/ivy/core/retrieve/RetrieveOptions.java
index 6fa2399..8dba4d9 100644
--- a/src/java/org/apache/ivy/core/retrieve/RetrieveOptions.java
+++ b/src/java/org/apache/ivy/core/retrieve/RetrieveOptions.java
@@ -19,6 +19,7 @@ package org.apache.ivy.core.retrieve;
 
 import org.apache.ivy.core.LogOptions;
 import org.apache.ivy.core.module.descriptor.Artifact;
+import org.apache.ivy.util.Message;
 import org.apache.ivy.util.filter.Filter;
 import org.apache.ivy.util.filter.FilterHelper;
 
@@ -78,10 +79,7 @@ public class RetrieveOptions extends LogOptions {
      */
     private boolean makeSymlinks = false;
 
-    /**
-     * True if symbolic links should be created all at once, instead of one at 
a time. Works only on
-     * OS supporting with both "sh" (a shell) and "ln" (the link command).
-     */
+    @Deprecated
     private boolean makeSymlinksInMass = false;
 
     /**
@@ -155,11 +153,18 @@ public class RetrieveOptions extends LogOptions {
     }
 
     public boolean isMakeSymlinks() {
-        return makeSymlinks;
+        // we also do a check on makeSymlinkInMass just to allow backward 
compatibility for a version
+        // or so, to allow users time to move away from symlinkinmass option
+        return makeSymlinks || makeSymlinksInMass;
     }
 
+    @Deprecated
+    /**
+     * @deprecated Starting 2.5, creating symlinks in mass is no longer 
supported and this
+     * method will always return false
+     */
     public boolean isMakeSymlinksInMass() {
-        return makeSymlinksInMass;
+        return false;
     }
 
     public RetrieveOptions setMakeSymlinks(boolean makeSymlinks) {
@@ -167,8 +172,14 @@ public class RetrieveOptions extends LogOptions {
         return this;
     }
 
+    @Deprecated
+    /**
+     * @deprecated Starting 2.5, creating symlinks in mass is no longer 
supported and this
+     * method plays no role in creation of symlinks. Use {@link 
#setMakeSymlinks(boolean)} instead
+     */
     public RetrieveOptions setMakeSymlinksInMass(boolean makeSymlinksInMass) {
         this.makeSymlinksInMass = makeSymlinksInMass;
+        Message.warn("symlinkmass option has been deprecated and will no 
longer be supported");
         return this;
     }
 

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/src/java/org/apache/ivy/util/FileUtil.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/util/FileUtil.java 
b/src/java/org/apache/ivy/util/FileUtil.java
index 0ff62fa..138a9ce 100644
--- a/src/java/org/apache/ivy/util/FileUtil.java
+++ b/src/java/org/apache/ivy/util/FileUtil.java
@@ -29,7 +29,6 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.net.URL;
 import java.nio.file.Files;
@@ -38,14 +37,11 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Stack;
 import java.util.StringTokenizer;
 import java.util.jar.JarOutputStream;
 import java.util.jar.Pack200;
 import java.util.jar.Pack200.Unpacker;
-import java.util.regex.Pattern;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.ZipInputStream;
 
@@ -64,111 +60,25 @@ public final class FileUtil {
 
     private static final byte[] EMPTY_BUFFER = new byte[0];
 
-    private static final Pattern ALLOWED_PATH_PATTERN = 
Pattern.compile("[\\w-./\\\\:~ %\\(\\)]+");
-
-    public static void symlinkInMass(Map<File, File> destToSrcMap, boolean 
overwrite)
-            throws IOException {
-        // This pattern could be more forgiving if somebody wanted it to be... 
but this should
-        // satisfy 99+% of all needs, without letting unsafe operations be 
done.
-        // If a path is not allowed, then skip this mass option.
-        // NOTE: A space inside the path is allowed (I can't control other 
programmers who like them
-        // in their working directory names)... but trailing spaces on file 
names will be checked
-        // otherwise and refused.
-        try {
-            StringBuilder sb = new StringBuilder();
-
-            for (Entry<File, File> entry : destToSrcMap.entrySet()) {
-                if (sb.length() > 0) {
-                    sb.append("\n");
-                }
-                File destFile = entry.getKey();
-                File srcFile = entry.getValue();
-                if 
(!ALLOWED_PATH_PATTERN.matcher(srcFile.getAbsolutePath()).matches()) {
-                    throw new IOException("Unsafe file to 'mass' symlink: '"
-                            + srcFile.getAbsolutePath() + "'");
-                }
-                if 
(!ALLOWED_PATH_PATTERN.matcher(destFile.getAbsolutePath()).matches()) {
-                    throw new IOException("Unsafe file to 'mass' symlink to: '"
-                            + destFile.getAbsolutePath() + "'");
-                }
-
-                // Add to our buffer of commands
-                sb.append(String.format("ln -s -f \"%s\"  \"%s\";",
-                        srcFile.getAbsolutePath(), 
destFile.getAbsolutePath()));
-            }
-
-            String commands = sb.toString();
-            // Run the buffer of commands we have built.
-            Runtime runtime = Runtime.getRuntime();
-            Message.verbose("executing \"sh\" of:\n\t" + 
commands.replaceAll("\n", "\n\t"));
-            Process process = runtime.exec("sh");
-            OutputStream os = process.getOutputStream();
-            os.write(commands.getBytes("UTF-8"));
-            os.flush();
-            os.close();
-
-            if (process.waitFor() != 0) {
-                InputStream errorStream = process.getErrorStream();
-                InputStreamReader isr = new InputStreamReader(errorStream);
-                BufferedReader br = new BufferedReader(isr);
-
-                StringBuilder error = new StringBuilder();
-                String line;
-                while ((line = br.readLine()) != null) {
-                    error.append(line);
-                    error.append('\n');
-                }
-
-                throw new IOException("error running ln commands with 'sh':\n" 
+ error);
-            }
-        } catch (InterruptedException x) {
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    public static void symlink(File src, File dest, CopyProgressListener l, 
boolean overwrite)
+    /**
+     * Creates a symbolic link at {@code link} whose target will be the {@code 
target}. Depending on the underlying
+     * filesystem, this method may not always be able to create a symbolic 
link, in which case this method returns
+     * {@code false}.
+     *
+     * @param target    The {@link File} which will be the target of the 
symlink being created
+     * @param link      The path to the symlink that needs to be created
+     * @param overwrite {@code true} if any existing file at {@code link} has 
to be overwritten. False otherwise
+     * @return Returns true if the symlink was successfully created. Returns 
false if the symlink creation couldn't
+     * be done
+     * @throws IOException
+     */
+    public static boolean symlink(final File target, final File link, final 
boolean overwrite)
             throws IOException {
-        if (!prepareCopy(src, dest, overwrite)) {
-            return;
-        }
-        try {
-            Runtime runtime = Runtime.getRuntime();
-            Message.verbose("executing 'ln -s -f " + src.getAbsolutePath() + " 
" + dest.getPath()
-                    + "'");
-            Process process = runtime.exec(new String[] {"ln", "-s", "-f", 
src.getAbsolutePath(),
-                    dest.getPath()});
-
-            if (process.waitFor() != 0) {
-                InputStream errorStream = process.getErrorStream();
-                InputStreamReader isr = new InputStreamReader(errorStream);
-                BufferedReader br = new BufferedReader(isr);
-
-                StringBuilder error = new StringBuilder();
-                String line;
-                while ((line = br.readLine()) != null) {
-                    error.append(line);
-                    error.append('\n');
-                }
-
-                throw new IOException("error symlinking " + src + " to " + 
dest + ":\n" + error);
-            }
-
-            // check if the creation of the symbolic link was successful
-            if (!dest.exists()) {
-                throw new IOException("error symlinking: " + dest + " doesn't 
exists");
-            }
-
-            // check if the result is a true symbolic link
-            if (dest.getAbsolutePath().equals(dest.getCanonicalPath())) {
-                dest.delete(); // just make sure we do delete the invalid 
symlink!
-                throw new IOException("error symlinking: " + dest + " isn't a 
symlink");
-            }
-        } catch (IOException e) {
-            Message.verbose("symlink failed; falling back to copy", e);
-            copy(src, dest, l, overwrite);
-        } catch (InterruptedException x) {
-            Thread.currentThread().interrupt();
+        if (!prepareCopy(target, link, overwrite)) {
+            return false;
         }
+        Files.createSymbolicLink(link.toPath(), 
target.getAbsoluteFile().toPath());
+        return true;
     }
 
     public static boolean copy(File src, File dest, CopyProgressListener l) 
throws IOException {

http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/366fb741/test/java/org/apache/ivy/core/retrieve/RetrieveTest.java
----------------------------------------------------------------------
diff --git a/test/java/org/apache/ivy/core/retrieve/RetrieveTest.java 
b/test/java/org/apache/ivy/core/retrieve/RetrieveTest.java
index 921ad0b..ffac56f 100644
--- a/test/java/org/apache/ivy/core/retrieve/RetrieveTest.java
+++ b/test/java/org/apache/ivy/core/retrieve/RetrieveTest.java
@@ -38,12 +38,14 @@ import org.apache.tools.ant.Project;
 import org.apache.tools.ant.taskdefs.Delete;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.nio.file.Files;
+import java.nio.file.LinkOption;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -62,6 +64,36 @@ public class RetrieveTest {
 
     private Ivy ivy;
 
+    private static boolean systemHasSymlinkAbility;
+
+    @BeforeClass
+    public static void beforeClass() {
+        final List<File> tmpFilesCreated = new ArrayList<>();
+        // create a dummy symlink and see if it works fine
+        try {
+            final File tmpDir = Files.createTempDirectory(null).toFile();
+            tmpFilesCreated.add(tmpDir);
+
+            final Path tmpFile = Files.createTempFile(tmpDir.toPath(), null, 
null);
+            tmpFilesCreated.add(tmpFile.toFile());
+
+            final File symlinkedFile = new File(tmpDir, "symlinked-test-file");
+            tmpFilesCreated.add(symlinkedFile);
+
+            // attempt to create the symlink
+            Files.createSymbolicLink(symlinkedFile.toPath(), tmpFile);
+            systemHasSymlinkAbility = true;
+        } catch (IOException ioe) {
+            Message.info("Current system is considered as not having symlink 
ability due to failure to create a test symlink", ioe);
+            systemHasSymlinkAbility = false;
+        }
+        // delete on exit, the tmp files we created
+        for (final File file : tmpFilesCreated) {
+            file.deleteOnExit();
+        }
+    }
+
+
     @Before
     public void setUp() throws Exception {
         ivy = Ivy.newInstance();
@@ -216,22 +248,24 @@ public class RetrieveTest {
         String pattern = 
"build/test/retrieve/[module]/[conf]/[artifact]-[revision].[ext]";
         ivy.retrieve(md.getModuleRevisionId(),
             
getRetrieveOptions().setMakeSymlinks(true).setDestArtifactPattern(pattern));
-        assertLink(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", 
"2.0", "mod1.2", "jar",
+        assertLinkOrExists(IvyPatternHelper.substitute(pattern, "org1", 
"mod1.2", "2.0", "mod1.2", "jar",
             "jar", "default"));
 
         pattern = 
"build/test/retrieve/[module]/[conf]/[type]s/[artifact]-[revision].[ext]";
         ivy.retrieve(md.getModuleRevisionId(),
             
getRetrieveOptions().setMakeSymlinks(true).setDestArtifactPattern(pattern));
-        assertLink(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", 
"2.0", "mod1.2", "jar",
+        assertLinkOrExists(IvyPatternHelper.substitute(pattern, "org1", 
"mod1.2", "2.0", "mod1.2", "jar",
             "jar", "default"));
     }
 
+    /**
+     * This test is here to just test the deprecated {@code symlinkmass} 
option for retrieve task.
+     * A version or two down the line, after 2.5 release, we can remove this 
test and the option altogether
+     *
+     * @throws Exception
+     */
     @Test
     public void testRetrieveWithSymlinksMass() throws Exception {
-        if (System.getProperty("os.name").startsWith("Windows")) {
-            return;
-        }
-
         // mod1.1 depends on mod1.2
         ResolveReport report = ivy.resolve(new File(
                 
"test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURI().toURL(),
@@ -243,18 +277,31 @@ public class RetrieveTest {
         String pattern = 
"build/test/retrieve/[module]/[conf]/[artifact]-[revision].[ext]";
         ivy.retrieve(md.getModuleRevisionId(),
             
getRetrieveOptions().setMakeSymlinksInMass(true).setDestArtifactPattern(pattern));
-        assertLink(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", 
"2.0", "mod1.2", "jar",
+        assertLinkOrExists(IvyPatternHelper.substitute(pattern, "org1", 
"mod1.2", "2.0", "mod1.2", "jar",
             "jar", "default"));
 
         pattern = 
"build/test/retrieve/[module]/[conf]/[type]s/[artifact]-[revision].[ext]";
         ivy.retrieve(md.getModuleRevisionId(),
             
getRetrieveOptions().setMakeSymlinksInMass(true).setDestArtifactPattern(pattern));
-        assertLink(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", 
"2.0", "mod1.2", "jar",
+        assertLinkOrExists(IvyPatternHelper.substitute(pattern, "org1", 
"mod1.2", "2.0", "mod1.2", "jar",
             "jar", "default"));
     }
 
-    private void assertLink(final String filename) throws IOException {
-        assertTrue(filename + " was expected to be a symlink", 
Files.isSymbolicLink(Paths.get(filename)));
+    /**
+     * If the system {@link #systemHasSymlinkAbility has symlink ability} then 
asserts that the passed {@code filePath}
+     * is a {@link Files#isSymbolicLink(Path) symbolic link}. Else asserts 
that the {@code filePath}
+     * {@link Files#exists(Path, LinkOption...) exists}
+     *
+     * @param filePath
+     * @throws IOException
+     */
+    private void assertLinkOrExists(final String filePath) throws IOException {
+        if (systemHasSymlinkAbility) {
+            assertTrue(filePath + " was expected to be a symlink", 
Files.isSymbolicLink(Paths.get(filePath)));
+            return;
+        }
+        Message.info("System doesn't have symlink ability so checking if path 
" + filePath + " exists instead of checking for it to be a symlink");
+        assertTrue("Missing " + filePath, Files.exists(Paths.get(filePath)));
     }
 
     @Test
@@ -452,14 +499,12 @@ public class RetrieveTest {
                 
getRetrieveOptions().setMakeSymlinks(true).setOverwriteMode(RetrieveOptions.OVERWRITEMODE_ALWAYS)
                         .setDestArtifactPattern(retrievePattern));
         // we expect org:foo-bar:1.2.3 to have been retrieved
-        final Path retrievedArtifactSymlinkPath = 
Paths.get(IvyPatternHelper.substitute(retrievePattern, "org", "foo-bar",
-                "1.2.3", "foo-bar", "jar", "jar", "default"));
-        assertTrue("Artifact wasn't retrieved to " + 
retrievedArtifactSymlinkPath, Files.exists(retrievedArtifactSymlinkPath));
-        assertTrue("Artifact retrieved at " + retrievedArtifactSymlinkPath + " 
was expected to be a " +
-                "symlink", Files.isSymbolicLink(retrievedArtifactSymlinkPath));
+        final String retrievedArtifactSymlinkPath = 
IvyPatternHelper.substitute(retrievePattern, "org", "foo-bar",
+                "1.2.3", "foo-bar", "jar", "jar", "default");
+        assertLinkOrExists(retrievedArtifactSymlinkPath);
 
         // get hold of the contents of the retrieved artifact
-        final byte[] retrievedArtifactContent = 
Files.readAllBytes(retrievedArtifactSymlinkPath);
+        final byte[] retrievedArtifactContent = 
Files.readAllBytes(Paths.get(retrievedArtifactSymlinkPath));
         // compare it to the contents of org:foo-bar:1.2.3 artifact in repo 
cache. Should be the same
         assertTrue("Unexpected content in the retrieved artifact at " + 
retrievedArtifactSymlinkPath,
                 Arrays.equals(fooBar123ArtifactContentsInCache, 
retrievedArtifactContent));
@@ -489,9 +534,10 @@ public class RetrieveTest {
                 
getRetrieveOptions().setMakeSymlinks(false).setDestArtifactPattern(retrievePattern)
                         
.setOverwriteMode(RetrieveOptions.OVERWRITEMODE_ALWAYS));
         // we expect org:foo-bar:2.3.4 to have been retrieved
-        final Path secondRetrieveArtifactPath = 
Paths.get(IvyPatternHelper.substitute(retrievePattern, "org", "foo-bar",
-                "2.3.4", "foo-bar", "jar", "jar", "default"));
+        final Path secondRetrieveArtifactPath = new 
File(IvyPatternHelper.substitute(retrievePattern, "org", "foo-bar",
+                "2.3.4", "foo-bar", "jar", "jar", "default")).toPath();
         assertTrue("Artifact wasn't retrieved to " + 
secondRetrieveArtifactPath, Files.exists(secondRetrieveArtifactPath));
+        // expected to be a regular file and not a symlink
         assertFalse("Artifact retrieved at " + secondRetrieveArtifactPath + " 
wasn't expected to be a " +
                 "symlink", Files.isSymbolicLink(secondRetrieveArtifactPath));
 

Reply via email to