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č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));