diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Delete.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Delete.java | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Delete.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Delete.java new file mode 100644 index 00000000..6c34ccf2 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Delete.java @@ -0,0 +1,836 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant.taskdefs; + +import java.io.File; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.PatternSet; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.resources.FileProvider; +import org.apache.tools.ant.types.resources.FileResourceIterator; +import org.apache.tools.ant.types.resources.Resources; +import org.apache.tools.ant.types.resources.Restrict; +import org.apache.tools.ant.types.resources.Sort; +import org.apache.tools.ant.types.resources.comparators.FileSystem; +import org.apache.tools.ant.types.resources.comparators.ResourceComparator; +import org.apache.tools.ant.types.resources.comparators.Reverse; +import org.apache.tools.ant.types.resources.selectors.Exists; +import org.apache.tools.ant.types.resources.selectors.ResourceSelector; +import org.apache.tools.ant.types.selectors.AndSelector; +import org.apache.tools.ant.types.selectors.ContainsRegexpSelector; +import org.apache.tools.ant.types.selectors.ContainsSelector; +import org.apache.tools.ant.types.selectors.DateSelector; +import org.apache.tools.ant.types.selectors.DependSelector; +import org.apache.tools.ant.types.selectors.DepthSelector; +import org.apache.tools.ant.types.selectors.ExtendSelector; +import org.apache.tools.ant.types.selectors.FileSelector; +import org.apache.tools.ant.types.selectors.FilenameSelector; +import org.apache.tools.ant.types.selectors.MajoritySelector; +import org.apache.tools.ant.types.selectors.NoneSelector; +import org.apache.tools.ant.types.selectors.NotSelector; +import org.apache.tools.ant.types.selectors.OrSelector; +import org.apache.tools.ant.types.selectors.PresentSelector; +import org.apache.tools.ant.types.selectors.SelectSelector; +import org.apache.tools.ant.types.selectors.SizeSelector; +import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.SymbolicLinkUtils; + +/** + * Deletes a file or directory, or set of files defined by a fileset. + * The original delete task would delete a file, or a set of files + * using the include/exclude syntax. The deltree task would delete a + * directory tree. This task combines the functionality of these two + * originally distinct tasks. + * <p>Currently Delete extends MatchingTask. This is intended <i>only</i> + * to provide backwards compatibility for a release. The future position + * is to use nested filesets exclusively.</p> + * + * @since Ant 1.2 + * + * @ant.task category="filesystem" + */ +public class Delete extends MatchingTask { + private static final ResourceComparator REVERSE_FILESYSTEM = new Reverse(new FileSystem()); + private static final ResourceSelector EXISTS = new Exists(); + + private static class ReverseDirs implements ResourceCollection { + static final Comparator<Comparable<?>> REVERSE = new Comparator<Comparable<?>>() { + public int compare(Comparable<?> foo, Comparable<?> bar) { + return ((Comparable) foo).compareTo(bar) * -1; + } + }; + private Project project; + private File basedir; + private String[] dirs; + ReverseDirs(Project project, File basedir, String[] dirs) { + this.project = project; + this.basedir = basedir; + this.dirs = dirs; + Arrays.sort(this.dirs, REVERSE); + } + public Iterator<Resource> iterator() { + return new FileResourceIterator(project, basedir, dirs); + } + public boolean isFilesystemOnly() { return true; } + public int size() { return dirs.length; } + } + + // CheckStyle:VisibilityModifier OFF - bc + protected File file = null; + protected File dir = null; + protected Vector<FileSet> filesets = new Vector<FileSet>(); + protected boolean usedMatchingTask = false; + // by default, remove matching empty dirs + protected boolean includeEmpty = false; + // CheckStyle:VisibilityModifier ON + + private int verbosity = Project.MSG_VERBOSE; + private boolean quiet = false; + private boolean failonerror = true; + private boolean deleteOnExit = false; + private boolean removeNotFollowedSymlinks = false; + private Resources rcs = null; + private static FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private static SymbolicLinkUtils SYMLINK_UTILS = + SymbolicLinkUtils.getSymbolicLinkUtils(); + private boolean performGc = Os.isFamily("windows"); + + /** + * Set the name of a single file to be removed. + * + * @param file the file to be deleted + */ + public void setFile(File file) { + this.file = file; + } + + /** + * Set the directory from which files are to be deleted + * + * @param dir the directory path. + */ + public void setDir(File dir) { + this.dir = dir; + getImplicitFileSet().setDir(dir); + } + + /** + * If true, list all names of deleted files. + * + * @param verbose "true" or "on" + */ + public void setVerbose(boolean verbose) { + if (verbose) { + this.verbosity = Project.MSG_INFO; + } else { + this.verbosity = Project.MSG_VERBOSE; + } + } + + /** + * If true and the file does not exist, do not display a diagnostic + * message or modify the exit status to reflect an error. + * This means that if a file or directory cannot be deleted, + * then no error is reported. This setting emulates the + * -f option to the Unix "rm" command. + * Default is false meaning things are "noisy" + * @param quiet "true" or "on" + */ + public void setQuiet(boolean quiet) { + this.quiet = quiet; + if (quiet) { + this.failonerror = false; + } + } + + /** + * If false, note errors but continue. + * + * @param failonerror true or false + */ + public void setFailOnError(boolean failonerror) { + this.failonerror = failonerror; + } + + /** + * If true, on failure to delete, note the error and set + * the deleteonexit flag, and continue + * + * @param deleteOnExit true or false + */ + public void setDeleteOnExit(boolean deleteOnExit) { + this.deleteOnExit = deleteOnExit; + } + + + /** + * If true, delete empty directories. + * @param includeEmpty if true delete empty directories (only + * for filesets). Default is false. + */ + public void setIncludeEmptyDirs(boolean includeEmpty) { + this.includeEmpty = includeEmpty; + } + + /** + * Whether to perform a garbage collection before retrying a failed delete. + * + * <p>This may be required on Windows (where it is set to true by + * default) but also on other operating systems, for example when + * deleting directories from an NFS share.</p> + * + * @since Ant 1.8.3 + */ + public void setPerformGcOnFailedDelete(boolean b) { + performGc = b; + } + + /** + * Adds a set of files to be deleted. + * @param set the set of files to be deleted + */ + public void addFileset(FileSet set) { + filesets.addElement(set); + } + + /** + * Add an arbitrary ResourceCollection to be deleted. + * @param rc the filesystem-only ResourceCollection. + */ + public void add(ResourceCollection rc) { + if (rc == null) { + return; + } + if (rcs == null) { + rcs = new Resources(); + rcs.setCache(true); + } + rcs.add(rc); + } + + /** + * add a name entry on the include list + * @return a NameEntry object to be configured + */ + public PatternSet.NameEntry createInclude() { + usedMatchingTask = true; + return super.createInclude(); + } + + /** + * add a name entry on the include files list + * @return an NameEntry object to be configured + */ + public PatternSet.NameEntry createIncludesFile() { + usedMatchingTask = true; + return super.createIncludesFile(); + } + + /** + * add a name entry on the exclude list + * @return an NameEntry object to be configured + */ + public PatternSet.NameEntry createExclude() { + usedMatchingTask = true; + return super.createExclude(); + } + + /** + * add a name entry on the include files list + * @return an NameEntry object to be configured + */ + public PatternSet.NameEntry createExcludesFile() { + usedMatchingTask = true; + return super.createExcludesFile(); + } + + /** + * add a set of patterns + * @return PatternSet object to be configured + */ + public PatternSet createPatternSet() { + usedMatchingTask = true; + return super.createPatternSet(); + } + + /** + * Sets the set of include patterns. Patterns may be separated by a comma + * or a space. + * + * @param includes the string containing the include patterns + */ + public void setIncludes(String includes) { + usedMatchingTask = true; + super.setIncludes(includes); + } + + /** + * Sets the set of exclude patterns. Patterns may be separated by a comma + * or a space. + * + * @param excludes the string containing the exclude patterns + */ + public void setExcludes(String excludes) { + usedMatchingTask = true; + super.setExcludes(excludes); + } + + /** + * Sets whether default exclusions should be used or not. + * + * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions + * should be used, "false"|"off"|"no" when they + * shouldn't be used. + */ + public void setDefaultexcludes(boolean useDefaultExcludes) { + usedMatchingTask = true; + super.setDefaultexcludes(useDefaultExcludes); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param includesfile A string containing the filename to fetch + * the include patterns from. + */ + public void setIncludesfile(File includesfile) { + usedMatchingTask = true; + super.setIncludesfile(includesfile); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param excludesfile A string containing the filename to fetch + * the include patterns from. + */ + public void setExcludesfile(File excludesfile) { + usedMatchingTask = true; + super.setExcludesfile(excludesfile); + } + + /** + * Sets case sensitivity of the file system + * + * @param isCaseSensitive "true"|"on"|"yes" if file system is case + * sensitive, "false"|"off"|"no" when not. + */ + public void setCaseSensitive(boolean isCaseSensitive) { + usedMatchingTask = true; + super.setCaseSensitive(isCaseSensitive); + } + + /** + * Sets whether or not symbolic links should be followed. + * + * @param followSymlinks whether or not symbolic links should be followed + */ + public void setFollowSymlinks(boolean followSymlinks) { + usedMatchingTask = true; + super.setFollowSymlinks(followSymlinks); + } + + /** + * Sets whether the symbolic links that have not been followed + * shall be removed (the links, not the locations they point at). + * + * @since Ant 1.8.0 + */ + public void setRemoveNotFollowedSymlinks(boolean b) { + removeNotFollowedSymlinks = b; + } + + /** + * add a "Select" selector entry on the selector list + * @param selector the selector to be added + */ + public void addSelector(SelectSelector selector) { + usedMatchingTask = true; + super.addSelector(selector); + } + + /** + * add an "And" selector entry on the selector list + * @param selector the selector to be added + */ + public void addAnd(AndSelector selector) { + usedMatchingTask = true; + super.addAnd(selector); + } + + /** + * add an "Or" selector entry on the selector list + * @param selector the selector to be added + */ + public void addOr(OrSelector selector) { + usedMatchingTask = true; + super.addOr(selector); + } + + /** + * add a "Not" selector entry on the selector list + * @param selector the selector to be added + */ + public void addNot(NotSelector selector) { + usedMatchingTask = true; + super.addNot(selector); + } + + /** + * add a "None" selector entry on the selector list + * @param selector the selector to be added + */ + public void addNone(NoneSelector selector) { + usedMatchingTask = true; + super.addNone(selector); + } + + /** + * add a majority selector entry on the selector list + * @param selector the selector to be added + */ + public void addMajority(MajoritySelector selector) { + usedMatchingTask = true; + super.addMajority(selector); + } + + /** + * add a selector date entry on the selector list + * @param selector the selector to be added + */ + public void addDate(DateSelector selector) { + usedMatchingTask = true; + super.addDate(selector); + } + + /** + * add a selector size entry on the selector list + * @param selector the selector to be added + */ + public void addSize(SizeSelector selector) { + usedMatchingTask = true; + super.addSize(selector); + } + + /** + * add a selector filename entry on the selector list + * @param selector the selector to be added + */ + public void addFilename(FilenameSelector selector) { + usedMatchingTask = true; + super.addFilename(selector); + } + + /** + * add an extended selector entry on the selector list + * @param selector the selector to be added + */ + public void addCustom(ExtendSelector selector) { + usedMatchingTask = true; + super.addCustom(selector); + } + + /** + * add a contains selector entry on the selector list + * @param selector the selector to be added + */ + public void addContains(ContainsSelector selector) { + usedMatchingTask = true; + super.addContains(selector); + } + + /** + * add a present selector entry on the selector list + * @param selector the selector to be added + */ + public void addPresent(PresentSelector selector) { + usedMatchingTask = true; + super.addPresent(selector); + } + + /** + * add a depth selector entry on the selector list + * @param selector the selector to be added + */ + public void addDepth(DepthSelector selector) { + usedMatchingTask = true; + super.addDepth(selector); + } + + /** + * add a depends selector entry on the selector list + * @param selector the selector to be added + */ + public void addDepend(DependSelector selector) { + usedMatchingTask = true; + super.addDepend(selector); + } + + /** + * add a regular expression selector entry on the selector list + * @param selector the selector to be added + */ + public void addContainsRegexp(ContainsRegexpSelector selector) { + usedMatchingTask = true; + super.addContainsRegexp(selector); + } + + /** + * add the modified selector + * @param selector the selector to add + * @since ant 1.6 + */ + public void addModified(ModifiedSelector selector) { + usedMatchingTask = true; + super.addModified(selector); + } + + /** + * add an arbitrary selector + * @param selector the selector to be added + * @since Ant 1.6 + */ + public void add(FileSelector selector) { + usedMatchingTask = true; + super.add(selector); + } + + /** + * Delete the file(s). + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + if (usedMatchingTask) { + log("DEPRECATED - Use of the implicit FileSet is deprecated. " + + "Use a nested fileset element instead.", quiet ? Project.MSG_VERBOSE : verbosity); + } + + if (file == null && dir == null && filesets.size() == 0 && rcs == null) { + throw new BuildException("At least one of the file or dir " + + "attributes, or a nested resource collection, " + + "must be set."); + } + + if (quiet && failonerror) { + throw new BuildException("quiet and failonerror cannot both be " + + "set to true", getLocation()); + } + + // delete the single file + if (file != null) { + if (file.exists()) { + if (file.isDirectory()) { + log("Directory " + file.getAbsolutePath() + + " cannot be removed using the file attribute. " + + "Use dir instead.", quiet ? Project.MSG_VERBOSE : verbosity); + } else { + log("Deleting: " + file.getAbsolutePath()); + + if (!delete(file)) { + 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); + } + } + + // delete the directory + 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 + case, we want to print one message about deleting the + top of the directory tree. Otherwise, the removeDir + method will handle messages for _all_ directories. + */ + if (verbosity == Project.MSG_VERBOSE) { + 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()); + resourcesToDelete.setCache(true); + Resources filesetDirs = new Resources(); + filesetDirs.setProject(getProject()); + filesetDirs.setCache(true); + FileSet implicit = null; + if (usedMatchingTask && dir != null && dir.isDirectory()) { + //add the files from the default fileset: + implicit = getImplicitFileSet(); + implicit.setProject(getProject()); + filesets.add(implicit); + } + + final int size = filesets.size(); + for (int i = 0; i < size; i++) { + FileSet fs = (FileSet) filesets.get(i); + if (fs.getProject() == null) { + log("Deleting fileset with no project specified;" + + " assuming executing project", Project.MSG_VERBOSE); + fs = (FileSet) fs.clone(); + fs.setProject(getProject()); + } + final File fsDir = fs.getDir(); + if (!fs.getErrorOnMissingDir() && + (fsDir == null || !fsDir.exists())) { + continue; + } + if (fsDir == null) { + throw new BuildException( + "File or Resource without directory or file specified"); + } else if (!fsDir.isDirectory()) { + handle("Directory does not exist: " + fsDir); + } else { + DirectoryScanner ds = fs.getDirectoryScanner(); + // the previous line has already scanned the + // filesystem, in order to avoid a rescan when later + // iterating, capture the results now and store them + final String[] files = ds.getIncludedFiles(); + resourcesToDelete.add(new ResourceCollection() { + public boolean isFilesystemOnly() { + return true; + } + public int size() { + return files.length; + } + public Iterator<Resource> iterator() { + return new FileResourceIterator(getProject(), + fsDir, files); + } + }); + if (includeEmpty) { + filesetDirs.add(new ReverseDirs(getProject(), fsDir, + ds + .getIncludedDirectories())); + } + + if (removeNotFollowedSymlinks) { + String[] n = ds.getNotFollowedSymlinks(); + if (n.length > 0) { + String[] links = new String[n.length]; + System.arraycopy(n, 0, links, 0, n.length); + Arrays.sort(links, ReverseDirs.REVERSE); + for (int l = 0; l < links.length; l++) { + try { + SYMLINK_UTILS + .deleteSymbolicLink(new File(links[l]), + this); + } catch (java.io.IOException ex) { + handle(ex); + } + } + } + } + } + } + resourcesToDelete.add(filesetDirs); + if (rcs != null) { + // sort first to files, then dirs + Restrict exists = new Restrict(); + exists.add(EXISTS); + exists.add(rcs); + Sort s = new Sort(); + s.add(REVERSE_FILESYSTEM); + s.add(exists); + resourcesToDelete.add(s); + } + try { + if (resourcesToDelete.isFilesystemOnly()) { + for (Resource r : resourcesToDelete) { + // nonexistent resources could only occur if we already + // deleted something from a fileset: + File f = r.as(FileProvider.class) + .getFile(); + if (!f.exists()) { + continue; + } + if (!(f.isDirectory()) || f.list().length == 0) { + log("Deleting " + f, verbosity); + if (!delete(f) && failonerror) { + handle("Unable to delete " + + (f.isDirectory() ? "directory " : "file ") + f); + } + } + } + } else { + handle(getTaskName() + " handles only filesystem resources"); + } + } catch (Exception e) { + handle(e); + } finally { + if (implicit != null) { + filesets.remove(implicit); + } + } + } + +//************************************************************************ +// protected and private methods +//************************************************************************ + + private void handle(String msg) { + handle(new BuildException(msg)); + } + + private void handle(Exception e) { + if (failonerror) { + throw (e instanceof BuildException) + ? (BuildException) e : new BuildException(e); + } + log(e, quiet ? Project.MSG_VERBOSE : verbosity); + } + + /** + * Accommodate Windows bug encountered in both Sun and IBM JDKs. + * Others possible. If the delete does not work, call System.gc(), + * wait a little and try again. + */ + private boolean delete(File f) { + if (!FILE_UTILS.tryHardToDelete(f, performGc)) { + if (deleteOnExit) { + int level = quiet ? Project.MSG_VERBOSE : Project.MSG_INFO; + log("Failed to delete " + f + ", calling deleteOnExit." + + " This attempts to delete the file when the Ant jvm" + + " has exited and might not succeed.", level); + f.deleteOnExit(); + return true; + } + return false; + } + return true; + } + + /** + * Delete a directory + * + * @param d the directory to delete + */ + protected void removeDir(File d) { + String[] list = d.list(); + if (list == null) { + list = new String[0]; + } + for (int i = 0; i < list.length; i++) { + String s = list[i]; + File f = new File(d, s); + if (f.isDirectory()) { + removeDir(f); + } else { + log("Deleting " + f.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity); + if (!delete(f)) { + handle("Unable to delete file " + f.getAbsolutePath()); + } + } + } + log("Deleting directory " + d.getAbsolutePath(), verbosity); + if (!delete(d)) { + handle("Unable to delete directory " + d.getAbsolutePath()); + } + } + + /** + * remove an array of files in a directory, and a list of subdirectories + * which will only be deleted if 'includeEmpty' is true + * @param d directory to work from + * @param files array of files to delete; can be of zero length + * @param dirs array of directories to delete; can of zero length + */ + protected void removeFiles(File d, String[] files, String[] dirs) { + if (files.length > 0) { + log("Deleting " + files.length + " files from " + + d.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity); + for (int j = 0; j < files.length; j++) { + File f = new File(d, files[j]); + log("Deleting " + f.getAbsolutePath(), + quiet ? Project.MSG_VERBOSE : verbosity); + if (!delete(f)) { + handle("Unable to delete file " + f.getAbsolutePath()); + } + } + } + + if (dirs.length > 0 && includeEmpty) { + int dirCount = 0; + for (int j = dirs.length - 1; j >= 0; j--) { + File currDir = new File(d, dirs[j]); + String[] dirFiles = currDir.list(); + if (dirFiles == null || dirFiles.length == 0) { + log("Deleting " + currDir.getAbsolutePath(), + quiet ? Project.MSG_VERBOSE : verbosity); + if (!delete(currDir)) { + handle("Unable to delete directory " + + currDir.getAbsolutePath()); + } else { + dirCount++; + } + } + } + + if (dirCount > 0) { + log("Deleted " + + dirCount + + " director" + (dirCount == 1 ? "y" : "ies") + + " form " + d.getAbsolutePath(), + quiet ? Project.MSG_VERBOSE : verbosity); + } + } + } + + private boolean isDanglingSymlink(File f) { + try { + return SYMLINK_UTILS.isDanglingSymbolicLink(f); + } 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; + } + } +} |