=== build.properties
==================================================================
--- build.properties	(revision 7105)
+++ build.properties	(local)
@@ -13,6 +13,7 @@
 doc.src.dir=${basedir}/src/doc
 dxml.doc.file=${doc.src.dir}/ivy-book.xml
 raw.dxml.doc.file=${doc.src.dir}/ivy-raw-book.xml
+test.class=*Test
 
 ivy.minimum.javaversion=1.4
 debug.mode=on
=== build.xml
==================================================================
--- build.xml	(revision 7105)
+++ build.xml	(local)
@@ -147,7 +147,7 @@
          ================================================================= -->
 	<target name="init-tests-offline" if="offline">
  		    <fileset id="test.fileset" dir="${test.dir}">
- 		    	<include name="**/*Test.java"/>
+ 		    	<include name="**/${test.class}.java"/>
  		    	<contains text="junit"/>
  		    	<not><contains text="remote.test"/></not>
  		    </fileset>
@@ -155,7 +155,7 @@
 		
 	<target name="init-tests-online" unless="offline">
  		    <fileset id="test.fileset" dir="${test.dir}">
- 		    	<include name="**/*Test.java"/>
+ 		    	<include name="**/${test.class}.java"/>
  		    	<contains text="junit"/>
  		    </fileset>
 	</target>
=== ivy.xml
==================================================================
--- ivy.xml	(revision 7105)
+++ ivy.xml	(local)
@@ -20,6 +20,7 @@
 	<dependencies>
 		<dependency org="apache" name="commons-httpclient" rev="3.0" conf="default,httpclient->default"/>
 		<dependency org="apache" name="commons-cli" rev="1.0" conf="default,standalone->default"/>
+		<dependency org="apache" name="commons-io" rev="1.2" conf="default,standalone->default"/>
 		<dependency org="apache" name="oro" rev="2.0.8" conf="default,oro->default"/>
 		<dependency org="apache" name="commons-vfs" rev="20060920" conf="vfs->default;default,webdav->webdav" />
 		<dependency org="jcraft" name="jsch" rev="0.1.25" conf="default,sftp->default" />
=== src/java/fr/jayasoft/ivy/Ivy.java
==================================================================
--- src/java/fr/jayasoft/ivy/Ivy.java	(revision 7105)
+++ src/java/fr/jayasoft/ivy/Ivy.java	(local)
@@ -1914,6 +1914,9 @@
     	return retrieve(moduleId, confs, cache, destFilePattern, destIvyPattern, artifactFilter, false, false);
     }
     public int retrieve(ModuleId moduleId, String[] confs, final File cache, String destFilePattern, String destIvyPattern, Filter artifactFilter, boolean sync, boolean useOrigin) {
+    	return retrieve(moduleId, confs, cache, destFilePattern, destIvyPattern, artifactFilter, sync, useOrigin, false);
+    }
+    public int retrieve(ModuleId moduleId, String[] confs, final File cache, String destFilePattern, String destIvyPattern, Filter artifactFilter, boolean sync, boolean useOrigin, boolean makeSymlinks) {
     	if (artifactFilter == null) {
     		artifactFilter = FilterHelper.NO_FILTER;
     	}
@@ -1956,7 +1959,11 @@
                     File destFile = new File((String)it2.next());
                     if (!_checkUpToDate || !upToDate(archive, destFile)) {
                         Message.verbose("\t\tto "+destFile);
-                        FileUtil.copy(archive, destFile, null);
+                        if (makeSymlinks) {
+                            FileUtil.symlink(archive, destFile, null, false);
+                        } else {
+                            FileUtil.copy(archive, destFile, null);
+                        }
                         targetsCopied++;
                     } else {
                         Message.verbose("\t\tto "+destFile+" [NOT REQUIRED]");
=== src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java
==================================================================
--- src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java	(revision 7105)
+++ src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java	(local)
@@ -19,6 +19,7 @@
     private String _pattern;
     private String _ivypattern = null;
     private boolean _sync = false;
+    private boolean _symlink = false;
     
     public String getPattern() {
         return _pattern;
@@ -33,7 +34,7 @@
         _pattern = getProperty(_pattern, getIvyInstance(), "ivy.retrieve.pattern");
         try {
         	Filter artifactFilter = getArtifactFilter();
-            int targetsCopied = getIvyInstance().retrieve(getResolvedModuleId(), splitConfs(getConf()), getCache(), _pattern, _ivypattern, artifactFilter, _sync, isUseOrigin());
+            int targetsCopied = getIvyInstance().retrieve(getResolvedModuleId(), splitConfs(getConf()), getCache(), _pattern, _ivypattern, artifactFilter, _sync, isUseOrigin(), _symlink);
             boolean haveTargetsBeenCopied = targetsCopied > 0;
             getProject().setProperty("ivy.nb.targets.copied", String.valueOf(targetsCopied));
             getProject().setProperty("ivy.targets.copied", String.valueOf(haveTargetsBeenCopied));
@@ -53,5 +54,11 @@
 	public void setSync(boolean sync) {
 		_sync = sync;
 	}
-    
+
+    /**
+     * Option to create symlinks instead of copying.
+     */
+    public void setSymlink(boolean symlink) {
+        _symlink = symlink;
+    }
 }
=== src/java/fr/jayasoft/ivy/util/FileUtil.java
==================================================================
--- src/java/fr/jayasoft/ivy/util/FileUtil.java	(revision 7105)
+++ src/java/fr/jayasoft/ivy/util/FileUtil.java	(local)
@@ -11,6 +11,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.io.OutputStream;
 import java.net.URL;
 import java.util.ArrayList;
@@ -18,8 +20,11 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.commons.io.IOUtils;
+
 import fr.jayasoft.ivy.url.URLHandlerRegistry;
 
+
 /**
  * @author x.hanin
  *
@@ -27,7 +32,45 @@
 public class FileUtil {
     // tried some other values with empty files... seems to be the best one (512 * 1024 is very bad)
     // 8 * 1024 is also the size used by ant in its FileUtils... maybe they've done more study about it ;-)
-    private static final int BUFFER_SIZE = 8 * 1024; 
+    private static final int BUFFER_SIZE = 8 * 1024;
+
+    public static void symlink(File src, File dest, CopyProgressListener l, boolean overwrite) throws IOException {
+        try {
+            if (dest.exists()) {
+        	if (!dest.isFile()) {
+                    throw new IOException("impossible to copy: destination is not a file: "+dest);
+        	}
+        	if (!overwrite) {
+                    Message.verbose(dest+" already exists, nothing done");
+                    return;
+        	}
+            }
+            if (dest.getParentFile() != null) {
+                dest.getParentFile().mkdirs();
+            }
+            Process proc = new ProcessBuilder(new String[] {
+                    "/bin/ln", "-s", "-f",
+                    src.getAbsolutePath(),
+                    dest.getPath() })
+                .redirectErrorStream(true)
+                .start();
+            String error = IOUtils.toString(proc.getInputStream());
+            if (proc.waitFor() != 0) {
+                throw new IOException("error symlinking " + src + " to " + dest + ":\n" + error);
+            }
+        }
+        catch (IOException x) {
+            Message.verbose("symlink failed; falling back to copy");
+            StringWriter buffer = new StringWriter();
+            x.printStackTrace(new PrintWriter(buffer));
+            Message.debug(buffer.toString());
+            copy(src, dest, l, overwrite);
+        }
+        catch (InterruptedException x) {
+            Thread.currentThread().interrupt();
+        }
+    }
+  
     public static void copy(File src, File dest, CopyProgressListener l) throws IOException {
         copy(src, dest, l, false);
     }
=== test/java/fr/jayasoft/ivy/RetrieveTest.java
==================================================================
--- test/java/fr/jayasoft/ivy/RetrieveTest.java	(revision 7105)
+++ test/java/fr/jayasoft/ivy/RetrieveTest.java	(local)
@@ -7,9 +7,12 @@
 
 import java.io.File;
 
+import org.apache.commons.io.IOUtils;
+
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.taskdefs.Delete;
 
+import fr.jayasoft.ivy.filter.FilterHelper;
 import fr.jayasoft.ivy.report.ResolveReport;
 import fr.jayasoft.ivy.util.IvyPatternHelper;
 
@@ -65,6 +68,54 @@
         assertTrue(new File(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar", "default")).exists());
     }
 
+    public void testRetrieveWithSymlinks() throws Exception {
+        // mod1.1 depends on mod1.2
+        ResolveReport report = _ivy.resolve(new File("test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURL(),
+                null, new String[] {"*"}, _cache, null, true);
+        assertNotNull(report);
+        ModuleDescriptor md = report.getModuleDescriptor();
+        assertNotNull(md);
+        
+        String pattern = "build/test/retrieve/[module]/[conf]/[artifact]-[revision].[ext]";
+        _ivy.retrieve(md.getModuleRevisionId().getModuleId(), md.getConfigurationsNames(), _cache, pattern, null, FilterHelper.NO_FILTER, false, false, true);
+        assertLink(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().getModuleId(), md.getConfigurationsNames(), _cache, pattern, null, FilterHelper.NO_FILTER, false, false, true);
+        assertLink(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar", "default"));
+    }
+
+    private void assertLink(String filename) {
+        int code = -1;
+        try {
+            Process proc = new ProcessBuilder(new String[] {
+                    "/usr/bin/test", "-L", filename
+                })
+                .redirectErrorStream(true)
+                .start();
+            IOUtils.copy(proc.getInputStream(), System.out);
+            code = proc.waitFor();
+        }
+        catch (Throwable x) {
+            final String os = System.getProperty("os.name");
+            if (os.equals("Linux") ||
+                os.equals("Solaris") ||
+                os.equals("FreeBSD")) {
+                // Report the error if the OS is known to support
+                // symlinks.
+                x.printStackTrace();
+            }
+            else {
+                // If there is an exception, it probably means the
+                // system doesn't support symlinks; the file should at
+                // least have been copied.
+                assertTrue("file does not exists: " + filename,
+                           new File(filename).exists());
+            }
+        }
+        assertEquals("not a symlink: " + filename, 0, code);
+    }
+
     public void testRetrieveWithVariable() throws Exception {
         // mod1.1 depends on mod1.2
         _ivy.setVariable("retrieve.dir", "retrieve");
