delete task and symlinks
Alan Snyder <alan <at> cbfiddle.com>
2014-11-10 21:24:28 GMT
I realize that I am late to the party and that there is an open RFE
<https://issues.apache.org/bugzilla/show_bug.cgi?id=56700> on this issue, but considering how
long this problem has been in existence, I want to make some comments (and maybe rant a bit, too).
First, I cannot tell you how surprised I was when I decided to add a symlink to a build product and suddenly my
build script tried to delete my installation of the JDK! Fortunately, it did not have permission to do so…
Then I checked the documentation. Sure enough, that is how delete works. I investigated alternatives, and
could not find a better one than exec rm. Sad, but true.
OK, so I solved my problem, but for the benefit of those who have not yet encountered this problem, I have to
say that having a delete operation that follows symlinks may be the most surprising and dumb and dangerous
thing I have ever encountered in software, and it is very hard to understand why after all these years it is
still that way. Is there anyone who actually wants this behavior? In other words, does it really need to be
an option or should it just be fixed to never follow symlinks? Even Unix rm does not have a follow-symlinks
option, and Unix was made for power users.
I’ve seen some supposed explanations for this behavior, but they sound lame to me. Some say that Ant
cannot avoid following symlinks because Java doesn’t support them. Well, that’s not true any more.
But regardless, would it not be sufficient to call File.delete() first and only if it fails call
File.isDirectory() to see if iteration is required?
Other comments suggest the problem has to do with file sets and such. I guess I don’t see this. Deleting a
directory (or a symlink that happens to point at a directory) is not a matter of enumerating all the files in
the directory tree and then deleting them. From the point of view of Ant tasks, it should be an atomic
(meaning not composite) operation: call File.delete(), if that fails, check File.isDirectory() and if
true, iterate and recurse. If I tell Ant to delete a bunch of files, that operation should be applied to each
one. If I tell Ant to delete one directory, that operation should be applied to that one directory (or
symlink). If someone wants more control over what gets deleted in a directory, let them specify the set of
files to be deleted.