Author: bodewig
Date: Mon Sep 8 05:23:54 2008
New Revision: 693071
URL: http://svn.apache.org/viewvc?rev=693071&view=rev
Log:
delete broken symbolic links. PR 41285
Modified:
ant/core/trunk/WHATSNEW
ant/core/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml
ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java
ant/core/trunk/src/main/org/apache/tools/ant/util/FileUtils.java
ant/core/trunk/src/tests/antunit/taskdefs/delete-test.xml
ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java
Modified: ant/core/trunk/WHATSNEW
URL:
http://svn.apache.org/viewvc/ant/core/trunk/WHATSNEW?rev=693071&r1=693070&r2=693071&view=diff
==============================================================================
--- ant/core/trunk/WHATSNEW (original)
+++ ant/core/trunk/WHATSNEW Mon Sep 8 05:23:54 2008
@@ -204,6 +204,9 @@
the link's target.
Bugzilla Report 41525.
+ * <delete file="..."> failed to delete broken symbolic links.
+ Bugzilla Report 41285.
+
Other changes:
--------------
Modified: ant/core/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml?rev=693071&r1=693070&r2=693071&view=diff
==============================================================================
--- ant/core/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml
(original)
+++ ant/core/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml Mon Sep
8 05:23:54 2008
@@ -54,8 +54,8 @@
</target>
<target name="all"
- depends="setup, test-single, test-delete, test-record,
test-recreate, teardown"/>
-
+ depends="setup, test-single, test-delete, test-record,
test-recreate, teardown"/>
+
<!-- test for action = single -->
<!--
Creates:
@@ -334,6 +334,22 @@
</target>
+ <!-- actually tests the symlink methods in FileUtils, but this
+ testfixture already has all the necessary envirnment in place
+ -->
+ <target name="test-fileutils" depends="setup">
+ <mkdir dir="${tdir}/dir1"/>
+ <mkdir dir="${tdir}/dir2"/>
+ <touch file="${tdir}/file1"/>
+ <touch file="${tdir}/file2"/>
+ <symlink link="${tdir}/dir.there" resource="${tdir}/dir1"/>
+ <symlink link="${tdir}/dir.notthere" resource="${tdir}/dir2"/>
+ <symlink link="${tdir}/file.there" resource="${tdir}/file1"/>
+ <symlink link="${tdir}/file.notthere" resource="${tdir}/file2"/>
+ <delete dir="${tdir}/dir2"/>
+ <delete file="${tdir}/file2"/>
+ </target>
+
<!-- CALL THIS to clean things up afterwards -->
<target name="teardown">
Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java?rev=693071&r1=693070&r2=693071&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java Mon Sep
8 05:23:54 2008
@@ -57,6 +57,7 @@
import org.apache.tools.ant.types.selectors.MajoritySelector;
import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+import org.apache.tools.ant.util.FileUtils;
/**
* Deletes a file or directory, or set of files defined by a fileset.
@@ -112,6 +113,7 @@
private boolean failonerror = true;
private boolean deleteOnExit = false;
private Resources rcs = null;
+ private static FileUtils FILE_UTILS = FileUtils.getFileUtils();
// CheckStyle:VisibilityModifier ON
/**
@@ -523,6 +525,13 @@
handle("Unable to delete file " +
file.getAbsolutePath());
}
}
+ } else if (isDanglingSymlink(file)) {
+ log("Trying to delete file " + file.getAbsolutePath()
+ + " which looks like a broken symlink.",
+ quiet ? Project.MSG_VERBOSE : verbosity);
+ if (!delete(file)) {
+ handle("Unable to delete file " + file.getAbsolutePath());
+ }
} else {
log("Could not find file " + file.getAbsolutePath()
+ " to delete.", quiet ? Project.MSG_VERBOSE : verbosity);
@@ -530,8 +539,9 @@
}
// delete the directory
- if (dir != null && dir.exists() && dir.isDirectory()
+ if (dir != null
&& !usedMatchingTask) {
+ if (dir.exists() && dir.isDirectory()) {
/*
If verbosity is MSG_VERBOSE, that mean we are doing
regular logging (backwards as that sounds). In that
@@ -543,6 +553,15 @@
log("Deleting directory " + dir.getAbsolutePath());
}
removeDir(dir);
+ } else if (isDanglingSymlink(dir)) {
+ log("Trying to delete directory " + dir.getAbsolutePath()
+ + " which looks like a broken symlink.",
+ quiet ? Project.MSG_VERBOSE : verbosity);
+ if (!delete(dir)) {
+ handle("Unable to delete directory "
+ + dir.getAbsolutePath());
+ }
+ }
}
Resources resourcesToDelete = new Resources();
resourcesToDelete.setProject(getProject());
@@ -739,4 +758,16 @@
}
}
}
+
+ private boolean isDanglingSymlink(File f) {
+ try {
+ return FILE_UTILS.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName());
+ } catch (java.io.IOException e) {
+ log("Error while trying to detect " + f.getAbsolutePath()
+ + " as broken symbolic link. " + e.getMessage(),
+ quiet ? Project.MSG_VERBOSE : verbosity);
+ return false;
+ }
+ }
}
Modified: ant/core/trunk/src/main/org/apache/tools/ant/util/FileUtils.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/util/FileUtils.java?rev=693071&r1=693070&r2=693071&view=diff
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/util/FileUtils.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/util/FileUtils.java Mon Sep 8
05:23:54 2008
@@ -1052,6 +1052,47 @@
}
/**
+ * Checks whether a given file is a broken symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether Java
+ * reports that the File doesn't exist but its parent's child list
+ * contains it--this may lead to false positives on some
+ * platforms.</p>
+ *
+ * <p>Note that #isSymbolicLink returns false if this method
+ * returns true since Java won't produce a canonical name
+ * different from the abolute one if the link is broken.</p>
+ *
+ * @param parent the parent directory of the file to test
+ * @param name the name of the file to test.
+ *
+ * @return true if the file is a broken symbolic link.
+ * @throws IOException on error.
+ * @since Ant 1.8.0
+ */
+ public boolean isDanglingSymbolicLink(File parent, String name)
+ throws IOException {
+ File f = null;
+ if (parent == null) {
+ f = new File(name);
+ parent = f.getParentFile();
+ name = f.getName();
+ } else {
+ f = new File(parent, name);
+ }
+ if (!f.exists()) {
+ final String localName = f.getName();
+ String[] c = parent.list(new FilenameFilter() {
+ public boolean accept(File d, String n) {
+ return localName.equals(n);
+ }
+ });
+ return c != null && c.length > 0;
+ }
+ return false;
+ }
+
+ /**
* Removes a leading path from a second path.
*
* @param leading The leading path, must not be null, must be absolute.
Modified: ant/core/trunk/src/tests/antunit/taskdefs/delete-test.xml
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/tests/antunit/taskdefs/delete-test.xml?rev=693071&r1=693070&r2=693071&view=diff
==============================================================================
--- ant/core/trunk/src/tests/antunit/taskdefs/delete-test.xml (original)
+++ ant/core/trunk/src/tests/antunit/taskdefs/delete-test.xml Mon Sep 8
05:23:54 2008
@@ -67,4 +67,31 @@
</target>
+ <target name="checkOs">
+ <condition property="unix">
+ <os family="unix" />
+ </condition>
+ </target>
+
+ <target name="testDanglingSymlinkInDir" if="unix" depends="checkOs,init">
+ <touch file="${output}/foo"/>
+ <symlink link="${existing.dir}/link"
+ resource="${output}/foo"/>
+ <delete file="${output}/foo"/>
+ <delete dir="${existing.dir}"/>
+ <au:assertFileDoesntExist file="${existing.dir}" />
+ </target>
+
+ <target name="testDanglingSymlink" if="unix" depends="checkOs,init">
+ <touch file="${output}/foo"/>
+ <symlink link="${output}/link"
+ resource="${output}/foo"/>
+ <delete file="${output}/foo"/>
+ <delete file="${output}/link"/>
+
+ <!-- since File.exists returns false for dangling links, recreate
+ the file so that assertFileDoesntExist can actually work -->
+ <touch file="${output}/foo"/>
+ <au:assertFileDoesntExist file="${output}/link" />
+ </target>
</project>
Modified:
ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java
URL:
http://svn.apache.org/viewvc/ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java?rev=693071&r1=693070&r2=693071&view=diff
==============================================================================
---
ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java
(original)
+++
ant/core/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java
Mon Sep 8 05:23:54 2008
@@ -33,6 +33,7 @@
import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
/**
* Test cases for the Symlink task. Link creation, link deletion, recording
@@ -181,6 +182,103 @@
}
}
+ public void testFileUtilsMethods() throws Exception {
+ if (supportsSymlinks) {
+ executeTarget("test-fileutils");
+ FileUtils fu = FileUtils.getFileUtils();
+
+ java.io.File f = getProject().resolveFile("test-working/file1");
+ assertTrue(f.exists());
+ assertFalse(f.isDirectory());
+ assertTrue(f.isFile());
+ assertFalse(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertFalse(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ f = getProject().resolveFile("test-working/dir1");
+ assertTrue(f.exists());
+ assertTrue(f.isDirectory());
+ assertFalse(f.isFile());
+ assertFalse(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertFalse(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ f = getProject().resolveFile("test-working/file2");
+ assertFalse(f.exists());
+ assertFalse(f.isDirectory());
+ assertFalse(f.isFile());
+ assertFalse(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertFalse(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ f = getProject().resolveFile("test-working/dir2");
+ assertFalse(f.exists());
+ assertFalse(f.isDirectory());
+ assertFalse(f.isFile());
+ assertFalse(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertFalse(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+
+ f = getProject().resolveFile("test-working/file.there");
+ assertTrue(f.exists());
+ assertFalse(f.isDirectory());
+ assertTrue(f.isFile());
+ assertTrue(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertTrue(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertFalse(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ f = getProject().resolveFile("test-working/dir.there");
+ assertTrue(f.exists());
+ assertTrue(f.isDirectory());
+ assertFalse(f.isFile());
+ assertTrue(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertTrue(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertFalse(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ f = getProject().resolveFile("test-working/file.notthere");
+ assertFalse(f.exists());
+ assertFalse(f.isDirectory());
+ assertFalse(f.isFile());
+ assertFalse(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertTrue(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertTrue(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ f = getProject().resolveFile("test-working/dir.notthere");
+ assertFalse(f.exists());
+ assertFalse(f.isDirectory());
+ assertFalse(f.isFile());
+ assertFalse(fu.isSymbolicLink(null, f.getAbsolutePath()));
+ assertFalse(fu.isSymbolicLink(f.getParentFile(),
+ f.getName()));
+ assertTrue(fu.isDanglingSymbolicLink(null, f.getAbsolutePath()));
+ assertTrue(fu.isDanglingSymbolicLink(f.getParentFile(),
+ f.getName()));
+
+ }
+ }
+
public void tearDown() {
if (supportsSymlinks) {
executeTarget("teardown");