summaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Move.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Move.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Move.java382
1 files changed, 382 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Move.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Move.java
new file mode 100644
index 00000000..7f5d9680
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Move.java
@@ -0,0 +1,382 @@
+/*
+ * 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.io.IOException;
+import java.util.Iterator;
+
+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.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+
+/**
+ * Moves a file or directory to a new file or directory.
+ * By default, the
+ * destination file is overwritten if it already exists.
+ * When <i>overwrite</i> is
+ * turned off, then files are only moved if the source file is
+ * newer than the destination file, or when the destination file does
+ * not exist.
+ *
+ * <p>Source files and directories are only deleted when the file or
+ * directory has been copied to the destination successfully. Filtering
+ * also works.</p>
+ *
+ * <p>This implementation is based on Arnout Kuiper's initial design
+ * document, the following mailing list discussions, and the
+ * copyfile/copydir tasks.</p>
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="filesystem"
+ */
+public class Move extends Copy {
+
+ private boolean performGc = Os.isFamily("windows");
+
+ /**
+ * Constructor of object.
+ * This sets the forceOverwrite attribute of the Copy parent class
+ * to true.
+ *
+ */
+ public Move() {
+ super();
+ setOverwrite(true);
+ }
+
+ /**
+ * 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;
+ }
+
+ /** {@inheritDoc}. */
+ protected void validateAttributes() throws BuildException {
+ if (file != null && file.isDirectory()) {
+ if ((destFile != null && destDir != null)
+ || (destFile == null && destDir == null)) {
+ throw new BuildException("One and only one of tofile and todir must be set.");
+ }
+ destFile = destFile == null ? new File(destDir, file.getName()) : destFile;
+ destDir = destDir == null ? destFile.getParentFile() : destDir;
+
+ completeDirMap.put(file, destFile);
+ file = null;
+ } else {
+ super.validateAttributes();
+ }
+ }
+
+//************************************************************************
+// protected and private methods
+//************************************************************************
+
+ /**
+ * Override copy's doFileOperations to move the files instead of copying them.
+ */
+ protected void doFileOperations() {
+ //Attempt complete directory renames, if any, first.
+ if (completeDirMap.size() > 0) {
+ for (Iterator fromDirs = completeDirMap.keySet().iterator(); fromDirs.hasNext();) {
+ File fromDir = (File) fromDirs.next();
+ File toDir = (File) completeDirMap.get(fromDir);
+ boolean renamed = false;
+ try {
+ log("Attempting to rename dir: " + fromDir + " to " + toDir, verbosity);
+ renamed = renameFile(fromDir, toDir, filtering, forceOverwrite);
+ } catch (IOException ioe) {
+ String msg = "Failed to rename dir " + fromDir
+ + " to " + toDir + " due to " + ioe.getMessage();
+ throw new BuildException(msg, ioe, getLocation());
+ }
+ if (!renamed) {
+ FileSet fs = new FileSet();
+ fs.setProject(getProject());
+ fs.setDir(fromDir);
+ addFileset(fs);
+ DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+ String[] files = ds.getIncludedFiles();
+ String[] dirs = ds.getIncludedDirectories();
+ scan(fromDir, toDir, files, dirs);
+ }
+ }
+ }
+ int moveCount = fileCopyMap.size();
+ if (moveCount > 0) { // files to move
+ log("Moving " + moveCount + " file" + ((moveCount == 1) ? "" : "s")
+ + " to " + destDir.getAbsolutePath());
+
+ for (Iterator fromFiles = fileCopyMap.keySet().iterator(); fromFiles.hasNext();) {
+ String fromFile = (String) fromFiles.next();
+ File f = new File(fromFile);
+ boolean selfMove = false;
+ if (f.exists()) { //Is this file still available to be moved?
+ String[] toFiles = (String[]) fileCopyMap.get(fromFile);
+ for (int i = 0; i < toFiles.length; i++) {
+ String toFile = (String) toFiles[i];
+
+ if (fromFile.equals(toFile)) {
+ log("Skipping self-move of " + fromFile, verbosity);
+ selfMove = true;
+
+ // if this is the last time through the loop then
+ // move will not occur, but that's what we want
+ continue;
+ }
+ File d = new File(toFile);
+ if ((i + 1) == toFiles.length && !selfMove) {
+ // Only try to move if this is the last mapped file
+ // and one of the mappings isn't to itself
+ moveFile(f, d, filtering, forceOverwrite);
+ } else {
+ copyFile(f, d, filtering, forceOverwrite);
+ }
+ }
+ }
+ }
+ }
+
+ if (includeEmpty) {
+ int createCount = 0;
+ for (Iterator fromDirNames = dirCopyMap.keySet().iterator(); fromDirNames.hasNext();) {
+ String fromDirName = (String) fromDirNames.next();
+ String[] toDirNames = (String[]) dirCopyMap.get(fromDirName);
+ boolean selfMove = false;
+ for (int i = 0; i < toDirNames.length; i++) {
+ if (fromDirName.equals(toDirNames[i])) {
+ log("Skipping self-move of " + fromDirName, verbosity);
+ selfMove = true;
+ continue;
+ }
+ File d = new File(toDirNames[i]);
+ if (!d.exists()) {
+ if (!(d.mkdirs() || d.exists())) {
+ log("Unable to create directory "
+ + d.getAbsolutePath(), Project.MSG_ERR);
+ } else {
+ createCount++;
+ }
+ }
+ }
+ File fromDir = new File(fromDirName);
+ if (!selfMove && okToDelete(fromDir)) {
+ deleteDir(fromDir);
+ }
+ }
+ if (createCount > 0) {
+ log("Moved " + dirCopyMap.size()
+ + " empty director"
+ + (dirCopyMap.size() == 1 ? "y" : "ies")
+ + " to " + createCount
+ + " empty director"
+ + (createCount == 1 ? "y" : "ies") + " under "
+ + destDir.getAbsolutePath());
+ }
+ }
+ }
+
+ /**
+ * Try to move the file via a rename, but if this fails or filtering
+ * is enabled, copy the file then delete the sourceFile.
+ */
+ private void moveFile(File fromFile, File toFile, boolean filtering, boolean overwrite) {
+ boolean moved = false;
+ try {
+ log("Attempting to rename: " + fromFile + " to " + toFile, verbosity);
+ moved = renameFile(fromFile, toFile, filtering, forceOverwrite);
+ } catch (IOException ioe) {
+ String msg = "Failed to rename " + fromFile
+ + " to " + toFile + " due to " + ioe.getMessage();
+ throw new BuildException(msg, ioe, getLocation());
+ }
+
+ if (!moved) {
+ copyFile(fromFile, toFile, filtering, overwrite);
+ if (!getFileUtils().tryHardToDelete(fromFile, performGc)) {
+ throw new BuildException("Unable to delete " + "file "
+ + fromFile.getAbsolutePath());
+ }
+ }
+ }
+
+ /**
+ * Copy fromFile to toFile.
+ * @param fromFile
+ * @param toFile
+ * @param filtering
+ * @param overwrite
+ */
+ private void copyFile(File fromFile, File toFile, boolean filtering, boolean overwrite) {
+ try {
+ log("Copying " + fromFile + " to " + toFile, verbosity);
+
+ FilterSetCollection executionFilters = new FilterSetCollection();
+ if (filtering) {
+ executionFilters.addFilterSet(getProject().getGlobalFilterSet());
+ }
+ for (Iterator filterIter = getFilterSets().iterator(); filterIter.hasNext();) {
+ executionFilters.addFilterSet((FilterSet) filterIter.next());
+ }
+ getFileUtils().copyFile(fromFile, toFile, executionFilters,
+ getFilterChains(),
+ forceOverwrite,
+ getPreserveLastModified(),
+ /* append: */ false,
+ getEncoding(),
+ getOutputEncoding(),
+ getProject(), getForce());
+ } catch (IOException ioe) {
+ String msg = "Failed to copy " + fromFile
+ + " to " + toFile + " due to " + ioe.getMessage();
+ throw new BuildException(msg, ioe, getLocation());
+ }
+ }
+
+ /**
+ * Its only ok to delete a directory tree if there are no files in it.
+ * @param d the directory to check
+ * @return true if a deletion can go ahead
+ */
+ protected boolean okToDelete(File d) {
+ String[] list = d.list();
+ if (list == null) {
+ return false;
+ } // maybe io error?
+
+ for (int i = 0; i < list.length; i++) {
+ String s = list[i];
+ File f = new File(d, s);
+ if (f.isDirectory()) {
+ if (!okToDelete(f)) {
+ return false;
+ }
+ } else {
+ return false; // found a file
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Go and delete the directory tree.
+ * @param d the directory to delete
+ */
+ protected void deleteDir(File d) {
+ deleteDir(d, false);
+ }
+
+ /**
+ * Go and delete the directory tree.
+ * @param d the directory to delete
+ * @param deleteFiles whether to delete files
+ */
+ protected void deleteDir(File d, boolean deleteFiles) {
+ String[] list = d.list();
+ if (list == null) {
+ return;
+ } // on an io error list() can return null
+
+ for (int i = 0; i < list.length; i++) {
+ String s = list[i];
+ File f = new File(d, s);
+ if (f.isDirectory()) {
+ deleteDir(f);
+ } else if (deleteFiles && !getFileUtils().tryHardToDelete(f,
+ performGc)) {
+ throw new BuildException("Unable to delete file " + f.getAbsolutePath());
+ } else {
+ throw new BuildException("UNEXPECTED ERROR - The file "
+ + f.getAbsolutePath() + " should not exist!");
+ }
+ }
+ log("Deleting directory " + d.getAbsolutePath(), verbosity);
+ if (!getFileUtils().tryHardToDelete(d, performGc)) {
+ throw new BuildException("Unable to delete directory " + d.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Attempts to rename a file from a source to a destination.
+ * If overwrite is set to true, this method overwrites existing file
+ * even if the destination file is newer. Otherwise, the source file is
+ * renamed only if the destination file is older than it.
+ * Method then checks if token filtering is used. If it is, this method
+ * returns false assuming it is the responsibility to the copyFile method.
+ *
+ * @param sourceFile the file to rename
+ * @param destFile the destination file
+ * @param filtering if true, filtering is in operation, file will
+ * be copied/deleted instead of renamed
+ * @param overwrite if true force overwrite even if destination file
+ * is newer than source file
+ * @return true if the file was renamed
+ * @exception IOException if an error occurs
+ * @exception BuildException if an error occurs
+ */
+ protected boolean renameFile(File sourceFile, File destFile, boolean filtering,
+ boolean overwrite) throws IOException, BuildException {
+ if (destFile.isDirectory() || filtering || getFilterSets().size() > 0
+ || getFilterChains().size() > 0) {
+ return false;
+ }
+
+ // identical logic lives in ResourceUtils.copyResource():
+ if (destFile.isFile() && !destFile.canWrite()) {
+ if (!getForce()) {
+ throw new IOException("can't replace read-only destination "
+ + "file " + destFile);
+ } else if (!getFileUtils().tryHardToDelete(destFile)) {
+ throw new IOException("failed to delete read-only "
+ + "destination file " + destFile);
+ }
+ }
+
+ // identical logic lives in FileUtils.rename():
+ File parent = destFile.getParentFile();
+ if (parent != null && !parent.exists()) {
+ parent.mkdirs();
+ } else if (destFile.isFile()) {
+ sourceFile = getFileUtils().normalize(sourceFile.getAbsolutePath()).getCanonicalFile();
+ destFile = getFileUtils().normalize(destFile.getAbsolutePath());
+ if (destFile.getAbsolutePath().equals(sourceFile.getAbsolutePath())) {
+ //no point in renaming a file to its own canonical version...
+ log("Rename of " + sourceFile + " to " + destFile
+ + " is a no-op.", Project.MSG_VERBOSE);
+ return true;
+ }
+ if (!(getFileUtils().areSame(sourceFile, destFile)
+ || getFileUtils().tryHardToDelete(destFile, performGc))) {
+ throw new BuildException("Unable to remove existing file " + destFile);
+ }
+ }
+ return sourceFile.renameTo(destFile);
+ }
+}