into existing directories. PR: 31031 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276925 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -59,38 +59,129 @@ | |||
| </move> | |||
| </target> | |||
| <target name="testCompleteDirectoryMoveFileToFile"> | |||
| <mkdir dir="A"/> | |||
| <touch file="A/1"/> | |||
| <move file="A" tofile="E" /> | |||
| <fail message="E/1 not available"> | |||
| <target name="testMoveFileAndFileset"> | |||
| <mkdir dir="A" /> | |||
| <touch> | |||
| <filelist dir="A" files="1,2,3" /> | |||
| </touch> | |||
| <move todir="E" file="A/1"> | |||
| <fileset dir="A" includes="2,3" /> | |||
| </move> | |||
| <fail message="A unavailable"> | |||
| <condition> | |||
| <not> | |||
| <available file="E/1" type="file" /> | |||
| <available file="A" type="dir" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| <fail message="A remains"> | |||
| <fail message="A/1 not moved"> | |||
| <condition> | |||
| <or> | |||
| <available file="A/1" type="file" /> | |||
| <not> | |||
| <available file="E/1" type="file" /> | |||
| </not> | |||
| </or> | |||
| </condition> | |||
| </fail> | |||
| <fail message="A/2 not moved"> | |||
| <condition> | |||
| <or> | |||
| <available file="A/2" type="file" /> | |||
| <not> | |||
| <available file="E/2" type="file" /> | |||
| </not> | |||
| </or> | |||
| </condition> | |||
| </fail> | |||
| <fail message="A/3 not moved"> | |||
| <condition> | |||
| <or> | |||
| <available file="A/3" type="file" /> | |||
| <not> | |||
| <available file="E/3" type="file" /> | |||
| </not> | |||
| </or> | |||
| </condition> | |||
| </fail> | |||
| </target> | |||
| <macrodef name="verifymove"> | |||
| <attribute name="newfile" /> | |||
| <attribute name="olddir" /> | |||
| <sequential> | |||
| <fail message="@{newfile} not available"> | |||
| <condition> | |||
| <not> | |||
| <available file="@{newfile}" type="file" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| <fail message="@{olddir} remains"> | |||
| <condition> | |||
| <available file="@{olddir}" type="dir" /> | |||
| </condition> | |||
| </fail> | |||
| </sequential> | |||
| </macrodef> | |||
| <target name="testCompleteDirectoryMoveToExistingDir"> | |||
| <mkdir dir="A" /> | |||
| <touch file="A/1" /> | |||
| <mkdir dir="E" /> | |||
| <touch file="E/2" /> | |||
| <move todir="E"> | |||
| <fileset dir="A" /> | |||
| </move> | |||
| <verifymove newfile="E/1" olddir="A" /> | |||
| <fail message="E/2 unavailable"> | |||
| <condition> | |||
| <available file="A" type="dir" /> | |||
| <not> | |||
| <available file="E/2" type="file" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| </target> | |||
| <target name="testCompleteDirectoryMoveFileToFile"> | |||
| <mkdir dir="A"/> | |||
| <touch file="A/1"/> | |||
| <move file="A" tofile="E" /> | |||
| <verifymove newfile="E/1" olddir="A" /> | |||
| </target> | |||
| <target name="testCompleteDirectoryMoveFileToDir"> | |||
| <mkdir dir="A"/> | |||
| <touch file="A/1"/> | |||
| <move file="A" todir="E" /> | |||
| <fail message="E/A/1 not available"> | |||
| <verifymove newfile="E/A/1" olddir="A" /> | |||
| </target> | |||
| <target name="testCompleteDirectoryMoveFileAndFileset"> | |||
| <mkdir dir="A/1" /> | |||
| <touch file="A/2" /> | |||
| <move file="A/1" todir="E"> | |||
| <fileset dir="A" includes="2" /> | |||
| </move> | |||
| <fail message="A unavailable"> | |||
| <condition> | |||
| <not> | |||
| <available file="E/A/1" type="file" /> | |||
| <available file="A" type="dir" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| <fail message="A remains"> | |||
| <fail message="E/1 unavailable"> | |||
| <condition> | |||
| <available file="A" type="dir" /> | |||
| <not> | |||
| <available file="E/1" type="dir" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| <fail message="E/2 unavailable"> | |||
| <condition> | |||
| <not> | |||
| <available file="E/2" type="file" /> | |||
| </not> | |||
| </condition> | |||
| </fail> | |||
| </target> | |||
| @@ -98,8 +189,8 @@ | |||
| <target name="testCompleteDirectoryMoveFileToExistingFile"> | |||
| <mkdir dir="A"/> | |||
| <touch file="A/1"/> | |||
| <touch file="B"/> | |||
| <move file="A" tofile="B" /> | |||
| <touch file="E"/> | |||
| <move file="A" tofile="E" /> | |||
| </target> | |||
| <target name="testCompleteDirectoryMoveFileToExistingDir"> | |||
| @@ -107,6 +198,7 @@ | |||
| <touch file="A/1"/> | |||
| <mkdir dir="E"/> | |||
| <move file="A" tofile="E" /> | |||
| <verifymove newfile="E/1" olddir="A" /> | |||
| </target> | |||
| <target name="testCompleteDirectoryMoveFileToDirWithExistingFile"> | |||
| @@ -123,6 +215,7 @@ | |||
| <mkdir dir="E"/> | |||
| <mkdir dir="E/A"/> | |||
| <move file="A" todir="E" /> | |||
| <verifymove newfile="E/A/1" olddir="A" /> | |||
| </target> | |||
| <target name="cleanup"> | |||
| @@ -73,9 +73,9 @@ public class Copy extends Task { | |||
| protected Hashtable completeDirMap = new Hashtable(); | |||
| protected Mapper mapperElement = null; | |||
| protected FileUtils fileUtils; | |||
| private Vector filterChains = new Vector(); | |||
| private Vector filterSets = new Vector(); | |||
| private FileUtils fileUtils; | |||
| private String inputEncoding = null; | |||
| private String outputEncoding = null; | |||
| private long granularity = 0; | |||
| @@ -20,8 +20,10 @@ package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Enumeration; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.DirectoryScanner; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.FilterSet; | |||
| import org.apache.tools.ant.types.FilterSetCollection; | |||
| @@ -61,55 +63,23 @@ public class Move extends Copy { | |||
| setOverwrite(true); | |||
| } | |||
| /** | |||
| * Performs the move operation. | |||
| */ | |||
| public void execute() throws BuildException { | |||
| // inherit doc | |||
| protected void validateAttributes() throws BuildException { | |||
| if (file != null && file.isDirectory()) { | |||
| if (destFile != null && destDir != null) { | |||
| throw new BuildException("Only one of tofile and todir " | |||
| + "may be set."); | |||
| 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) | |||
| ? fileUtils.getParentFile(destFile) : destDir; | |||
| if (destFile == null && destDir == null) { | |||
| throw new BuildException("One of tofile or todir must be set."); | |||
| } | |||
| destFile = (destFile != null) | |||
| ? destFile : new File(destDir, file.getName()); | |||
| try { | |||
| boolean renamed = false; | |||
| log("Moving directory " + file | |||
| + " to " + destFile, Project.MSG_INFO); | |||
| try { | |||
| renamed = | |||
| renameFile(file, destFile, filtering, forceOverwrite); | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException(eyeOhEx.getMessage()); | |||
| } | |||
| if (!renamed) { | |||
| StringBuffer buf = new StringBuffer( | |||
| "Failed to move directory ").append( | |||
| file.getAbsolutePath()); | |||
| if ((getFilterChains() != null && getFilterChains().size() > 0) | |||
| || (getFilterSets() != null && getFilterSets().size() > 0) | |||
| || filtering) { | |||
| buf.append( | |||
| "; use a fileset to move directories with filtering"); | |||
| } | |||
| throw new BuildException(buf.append('.').toString()); | |||
| } | |||
| } catch (BuildException e) { | |||
| if (!failonerror) { | |||
| log("Warning: " + e.getMessage(), Project.MSG_ERR); | |||
| } else { | |||
| throw e; | |||
| } | |||
| } | |||
| completeDirMap.put(file, destFile); | |||
| file = null; | |||
| } else { | |||
| super.execute(); | |||
| super.validateAttributes(); | |||
| } | |||
| } | |||
| @@ -128,21 +98,35 @@ public class Move extends Copy { | |||
| while (e.hasMoreElements()) { | |||
| File fromDir = (File) e.nextElement(); | |||
| File toDir = (File) completeDirMap.get(fromDir); | |||
| boolean renamed = false; | |||
| try { | |||
| log("Attempting to rename dir: " + fromDir | |||
| + " to " + toDir, verbosity); | |||
| renameFile(fromDir, toDir, filtering, forceOverwrite); | |||
| 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); | |||
| } | |||
| } | |||
| } | |||
| if (fileCopyMap.size() > 0) { // files to move | |||
| log("Moving " + fileCopyMap.size() + " files to " | |||
| + destDir.getAbsolutePath()); | |||
| int moveCount = fileCopyMap.size(); | |||
| if (moveCount > 0) { // files to move | |||
| log("Moving " + moveCount + " file" | |||
| + ((moveCount == 1) ? "" : "s") | |||
| + " to " + destDir.getAbsolutePath()); | |||
| Enumeration e = fileCopyMap.keys(); | |||
| while (e.hasMoreElements()) { | |||
| @@ -325,6 +309,15 @@ public class Move extends Copy { | |||
| * @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; | |||
| @@ -335,6 +328,9 @@ public class Move extends Copy { | |||
| File f = new File(d, s); | |||
| if (f.isDirectory()) { | |||
| deleteDir(f); | |||
| } else if (deleteFiles && !(f.delete())) { | |||
| throw new BuildException("Unable to delete file " | |||
| + f.getAbsolutePath()); | |||
| } else { | |||
| throw new BuildException("UNEXPECTED ERROR - The file " | |||
| + f.getAbsolutePath() | |||
| @@ -370,34 +366,19 @@ public class Move extends Copy { | |||
| boolean filtering, boolean overwrite) | |||
| throws IOException, BuildException { | |||
| boolean renamed = true; | |||
| if ((getFilterSets() != null && getFilterSets().size() > 0) | |||
| || (getFilterChains() != null && getFilterChains().size() > 0)) { | |||
| renamed = false; | |||
| } else { | |||
| if (!filtering) { | |||
| // ensure that parent dir of dest file exists! | |||
| File parent = destFile.getParentFile(); | |||
| if (parent != null && !parent.exists()) { | |||
| parent.mkdirs(); | |||
| } | |||
| if (destFile.exists()) { | |||
| if (sourceFile.isDirectory()) { | |||
| throw new BuildException( | |||
| new StringBuffer("Cannot replace ").append( | |||
| ((destFile.isFile()) ? "file " : "directory ")).append( | |||
| destFile).append(" with directory ").append( | |||
| sourceFile).toString()); | |||
| } else if (destFile.isFile() && !destFile.delete()) { | |||
| throw new BuildException("Unable to remove existing " | |||
| + "file " + destFile); | |||
| } | |||
| } | |||
| renamed = sourceFile.renameTo(destFile); | |||
| } else { | |||
| renamed = false; | |||
| boolean renamed = false; | |||
| if ((getFilterSets().size() + getFilterChains().size() == 0) | |||
| && !(filtering || destFile.isDirectory())) { | |||
| // ensure that parent dir of dest file exists! | |||
| File parent = destFile.getParentFile(); | |||
| if (parent != null && !parent.exists()) { | |||
| parent.mkdirs(); | |||
| } | |||
| if (destFile.isFile() && !destFile.delete()) { | |||
| throw new BuildException("Unable to remove existing " | |||
| + "file " + destFile); | |||
| } | |||
| renamed = sourceFile.renameTo(destFile); | |||
| } | |||
| return renamed; | |||
| } | |||
| @@ -89,6 +89,14 @@ public class MoveTest extends BuildFileTest { | |||
| assertTrue(!getProject().resolveFile("A").exists()); | |||
| } | |||
| public void testMoveFileAndFileset() { | |||
| executeTarget("testMoveFileAndFileset"); | |||
| } | |||
| public void testCompleteDirectoryMoveToExistingDir() { | |||
| executeTarget("testCompleteDirectoryMoveToExistingDir"); | |||
| } | |||
| public void testCompleteDirectoryMoveFileToFile() { | |||
| executeTarget("testCompleteDirectoryMoveFileToFile"); | |||
| } | |||
| @@ -97,24 +105,24 @@ public class MoveTest extends BuildFileTest { | |||
| executeTarget("testCompleteDirectoryMoveFileToDir"); | |||
| } | |||
| public void testCompleteDirectoryMoveFileAndFileset() { | |||
| executeTarget("testCompleteDirectoryMoveFileAndFileset"); | |||
| } | |||
| public void testCompleteDirectoryMoveFileToExistingFile() { | |||
| expectBuildExceptionContaining("testCompleteDirectoryMoveFileToExistingFile", | |||
| "", "Cannot replace file"); | |||
| executeTarget("testCompleteDirectoryMoveFileToExistingFile"); | |||
| } | |||
| public void testCompleteDirectoryMoveFileToExistingDir() { | |||
| expectBuildExceptionContaining("testCompleteDirectoryMoveFileToExistingDir", | |||
| "", "Cannot replace directory"); | |||
| executeTarget("testCompleteDirectoryMoveFileToExistingDir"); | |||
| } | |||
| public void testCompleteDirectoryMoveFileToDirWithExistingFile() { | |||
| expectBuildExceptionContaining("testCompleteDirectoryMoveFileToDirWithExistingFile", | |||
| "", "Cannot replace file"); | |||
| executeTarget("testCompleteDirectoryMoveFileToDirWithExistingFile"); | |||
| } | |||
| public void testCompleteDirectoryMoveFileToDirWithExistingDir() { | |||
| expectBuildExceptionContaining("testCompleteDirectoryMoveFileToDirWithExistingDir", | |||
| "", "Cannot replace directory"); | |||
| executeTarget("testCompleteDirectoryMoveFileToDirWithExistingDir"); | |||
| } | |||
| } | |||