I have some memory of a similar thread coming up on the list before but don't remember any particular resolution.

The attached patch avoids any use of File.getCanonicalPath() within the Ant core. In current sources, any file names encountered are canonicalized quite aggressively, which on Unix means symlinks are followed.

Why do I think this is bad? Symlink farms are broken by this "feature". Consider a situation like this (which has bitten me):

common/build.xml: <ant dir="../a"/> <ant dir="../b"/> ...
a/build.xml: ...
b/build.xml: ...

Pretend a/ and b/ are both major code modules, and common/ some infrastructure to build them both. Now imagine you want to work on a CVS branch of a/ while keeping the public trunk of b/. You might try this:

mkdir ~/testing
cd ~/testing
cvs co -rtestbranch a
ln -s ~/trunksrc/b b
ln -s ~/trunksrc/common common
ant -f common/build.xml

You expect this to build stuff in ~/testing/b/ == ~/trunksrc/b/, which it does, and ~/testing/a/, which it does *not*: it uses ~/trunksrc/a/ (hopefully you notice!). Is this intuitive for anyone?

The reason is that the canonicalization of the file right away tells Ant that the build script it is starting with is /home/me/trunksrc/common/build.xml, and "../a" relative to that is /home/me/trunksrc/a/.

The patch simply disables canonicalization while continuing to use absolute paths, so that Ant will think of /home/me/testing/common/build.xml as its starting point, and never explicitly know about /home/me/trunksrc/ at all. In other words, the symlink farm you set up is honored by Ant. (It also makes the code a bit simpler.)

Surely someone will have a counterexample where they *do* want symlinks followed (I'm not quite sure why but could imagine it). Wouldn't this more safely be done at explicit user request? E.g.:

<property name="maybe-symlinked" location="../other-project"/>
<!-- Hypothetical new task: -->
<canonicalize property="other-proj-dir" location="${maybe-symlinked}"/>
<!-- Task which is not symlink-safe (caches?): -->
<dosomethingwith file="${other-proj-dir}/foo"/>

Also consider build logs in a big Unix shared-disk system:

ant -f /sources/build.xml all
[javac] Compiling 2 files to /sources/java
   (vs.)
[javac] Compiling 2 files to /mnt/dsk0013/projects/foo/sources/java

There may be value in leaving canonicalization on in Path.java as it could prevent duplicates differing only in symlink path. I have no idea if this happens commonly, or if it is really a problem when it does.

Other pluses/minuses?

-Jesse

--
Jesse Glick   <mailto:[EMAIL PROTECTED]>
NetBeans, Open APIs  <http://www.netbeans.org/>
tel (+4202) 3300-9161 Sun Micro x49161 Praha CR
Index: src/main/org/apache/tools/ant/Project.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/Project.java,v
retrieving revision 1.59
diff -u -t -r1.59 Project.java
--- src/main/org/apache/tools/ant/Project.java  2001/06/26 13:42:11     1.59
+++ src/main/org/apache/tools/ant/Project.java  2001/06/26 18:07:06
@@ -314,19 +314,15 @@
 
     // match basedir attribute in xml
     public void setBasedir(String baseD) throws BuildException {
-        try {
-            setBaseDir(new File(new File(baseD).getCanonicalPath()));
-        } catch (IOException ioe) {
-            String msg = "Can't set basedir " + baseD + " due to " +
-                ioe.getMessage();
-            throw new BuildException(msg);
-        }
+        File bd = new File(baseD);
+        if (! bd.isDirectory()) throw new BuildException("Basedir " + 
bd.getAbsolutePath() + " does not exist");
+        setBaseDir(bd);
     }
 
     public void setBaseDir(File baseDir) {
-        this.baseDir = baseDir;
-        setProperty( "basedir", baseDir.getAbsolutePath());
-        String msg = "Project base dir set to: " + baseDir;
+        this.baseDir = new File(baseDir.getAbsolutePath());
+        setProperty( "basedir", this.baseDir.getPath());
+        String msg = "Project base dir set to: " + this.baseDir;
         log(msg, MSG_VERBOSE);
     }
 
@@ -553,13 +549,7 @@
 
         // deal with absolute files
         if (fileName.startsWith(File.separator)) {
-            try {
-                return new File(new File(fileName).getCanonicalPath());
-            } catch (IOException e) {
-                log("IOException getting canonical path for " + fileName 
-                    + ": " + e.getMessage(), MSG_ERR);
-                return new File(fileName);
-            }
+            return new File(fileName);
         }
 
         // Eliminate consecutive slashes after the drive spec
@@ -608,14 +598,7 @@
             }
         }
 
-        try {
-            return new File(file.getCanonicalPath());
-        }
-        catch (IOException e) {
-            log("IOException getting canonical path for " + file + ": " +
-                e.getMessage(), MSG_ERR);
-            return new File(file.getAbsolutePath());
-        }
+        return new File(file.getAbsolutePath());
     }
 
     public File resolveFile(String fileName) {
Index: src/main/org/apache/tools/ant/ProjectHelper.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java,v
retrieving revision 1.51
diff -u -t -r1.51 ProjectHelper.java
--- src/main/org/apache/tools/ant/ProjectHelper.java    2001/06/08 10:11:27     
1.51
+++ src/main/org/apache/tools/ant/ProjectHelper.java    2001/06/26 18:07:06
@@ -326,7 +326,7 @@
                     if ((new File(baseDir)).isAbsolute()) {
                         project.setBasedir(baseDir);
                     } else {
-                        project.setBasedir((new File(buildFileParent, 
baseDir)).getAbsolutePath());
+                        project.setBaseDir(project.resolveFile(baseDir, 
buildFileParent));
                     }
                 }
             }
Index: src/main/org/apache/tools/ant/types/Path.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/types/Path.java,v
retrieving revision 1.16
diff -u -t -r1.16 Path.java
--- src/main/org/apache/tools/ant/types/Path.java       2001/05/23 16:58:15     
1.16
+++ src/main/org/apache/tools/ant/types/Path.java       2001/06/26 18:07:08
@@ -112,16 +112,7 @@
         private String[] parts;
 
         public void setLocation(File loc) {
-            try {
-                parts = new String[] {translateFile(loc.getCanonicalPath())};
-            } catch(IOException e) {
-                // XXX I'd like to log something here but if I don't
-                //     have a Project I can't
-                if (project != null) {
-                    project.log(e.getMessage(), Project.MSG_WARN);
-                }
-                parts = new String[] {translateFile(loc.getAbsolutePath())};
-            }
+            parts = new String[] {translateFile(loc.getAbsolutePath())};
         }
 
         public void setPath(String path) {
@@ -304,13 +295,8 @@
                 String[] s = ds.getIncludedFiles();
                 File dir = fs.getDir(project);
                 for (int j=0; j<s.length; j++) {
-                    String canonicalPath;
                     File f = new File(dir, s[j]);
-                    try {
-                        canonicalPath = f.getCanonicalPath();
-                    } catch(IOException e) {
-                        canonicalPath = f.getAbsolutePath();
-                    }
+                    String canonicalPath = f.getAbsolutePath();
                     addUnlessPresent(result, translateFile(canonicalPath));
                 } 
             }
@@ -447,12 +433,7 @@
     private static String resolveFile(Project project, String relativeName) {
         if (project != null) {
             File f = project.resolveFile(relativeName);
-            try {
-                return f.getCanonicalPath();
-            } catch(IOException e) {
-                project.log(e.getMessage(), Project.MSG_WARN);
-                return f.getAbsolutePath();
-            }
+            return f.getAbsolutePath();
         }
         return relativeName;
     }

Reply via email to