Some slight changes from the orignal patch - rename of ignoremultiplemapping to enablemultiplemapping and some checkstyle changes PR: 21320 Obtained from: Evan Easton git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274923 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -118,6 +118,23 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a> | |||||
| <td align="center">No - defaults to the value of the encoding | <td align="center">No - defaults to the value of the encoding | ||||
| attribute if given or the default JVM encoding otherwise.</td> | attribute if given or the default JVM encoding otherwise.</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">outputencoding</td> | |||||
| <td valign="top">The encoding to use when writing the files. | |||||
| <em>since Ant 1.6</em>.</td> | |||||
| <td align="center">No - defaults to the value of the encoding | |||||
| attribute if given or the default JVM encoding otherwise.</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">enablemultiplemapping</td> | |||||
| <td valign="top"> | |||||
| If true the task will process to all the mappings for a | |||||
| given source path. If false the task will only process | |||||
| the first file or directory. This attribute is only relevant | |||||
| if there is a mapper subelement. | |||||
| <em>since Ant 1.6</em>.</td> | |||||
| <td align="center">No - defaults to false.</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
| @@ -103,6 +103,16 @@ to move to the <var>todir</var> directory.</p> | |||||
| <td align="center">No - defaults to the value of the encoding | <td align="center">No - defaults to the value of the encoding | ||||
| attribute if given or the default JVM encoding otherwise.</td> | attribute if given or the default JVM encoding otherwise.</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">enablemultiplemapping</td> | |||||
| <td valign="top"> | |||||
| If true the task will process to all the mappings for a | |||||
| given source path. If false the task will only process | |||||
| the first file or directory. This attribute is only relevant | |||||
| if there is a mapper subelement. | |||||
| <em>since Ant 1.6</em>.</td> | |||||
| <td align="center">No - defaults to false.</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
| <h4>mapper</h4> | <h4>mapper</h4> | ||||
| @@ -0,0 +1,175 @@ | |||||
| <?xml version="1.0"?> | |||||
| <project name="test" basedir="."> | |||||
| <path id="testclasses"> | |||||
| <pathelement location="../../../../build/testcases" /> | |||||
| <pathelement path="${java.class.path}" /> | |||||
| </path> | |||||
| <mapper id="testmapper" | |||||
| classname="org.apache.tools.ant.taskdefs.MultiMapTest$TestMapper" | |||||
| classpathref="testclasses"/> | |||||
| <property name="map.ext" value=".copy2"/> | |||||
| <property name="rootScratchDir" value="test_multi_mapper_scratch_area"/> | |||||
| <property name="baseScratchSrc" value="${rootScratchDir}/src"/> | |||||
| <target name="setup"> | |||||
| <delete dir="${baseScratchSrc}"/> | |||||
| <mkdir dir="${baseScratchSrc}"/> | |||||
| <delete dir="${baseScratchDest}"/> | |||||
| <mkdir dir="${baseScratchDest}"/> | |||||
| <touch file="${baseScratchSrc}/somefile.txt"/> | |||||
| </target> | |||||
| <!-- test simple single file to multiple file move --> | |||||
| <target name="multicopy" depends="setup"> | |||||
| <copy todir="${baseScratchDest}" enablemultiplemappings="true"> | |||||
| <fileset dir="${baseScratchSrc}" includes="somefile.txt"/> | |||||
| <mapper refid="testmapper"/> | |||||
| </copy> | |||||
| <condition property="multicopy.outcome"> | |||||
| <and> | |||||
| <available file="${baseScratchDest}/somefile.txt"/> | |||||
| <available file="${baseScratchDest}/somefile.txt${map.ext}"/> | |||||
| </and> | |||||
| </condition> | |||||
| <fail unless="multicopy.outcome">multicopy failed</fail> | |||||
| </target> | |||||
| <target name="multimove" depends="setup"> | |||||
| <move todir="${baseScratchDest}" enablemultiplemappings="true"> | |||||
| <fileset dir="${baseScratchSrc}" includes="somefile.txt"/> | |||||
| <mapper refid="testmapper"/> | |||||
| </move> | |||||
| <condition property="test2.outcome"> | |||||
| <and> | |||||
| <available file="${baseScratchDest}/somefile.txt"/> | |||||
| <available file="${baseScratchDest}/somefile.txt${map.ext}"/> | |||||
| <not> | |||||
| <available file="${baseScratchSrc}/somefile.txt"/> | |||||
| </not> | |||||
| <not> | |||||
| <available file="${baseScratchSrc}/somefile.txt${map.ext}"/> | |||||
| </not> | |||||
| </and> | |||||
| </condition> | |||||
| <fail unless="test2.outcome">mulitmove failed</fail> | |||||
| </target> | |||||
| <!-- | |||||
| test traditional single file to single file copy explicitly telling | |||||
| task to ignore multiple mappings | |||||
| --> | |||||
| <target name="singlecopy" depends="setup"> | |||||
| <copy todir="${baseScratchDest}" enablemultiplemappings="false"> | |||||
| <fileset dir="${baseScratchSrc}" includes="somefile.txt"/> | |||||
| <mapper refid="testmapper"/> | |||||
| </copy> | |||||
| <condition property="singlecopy.outcome"> | |||||
| <and> | |||||
| <available file="${baseScratchDest}/somefile.txt"/> | |||||
| <not> | |||||
| <available file="${baseScratchDest}/somefile.txt${map.ext}"/> | |||||
| </not> | |||||
| <available file="${baseScratchSrc}/somefile.txt"/> | |||||
| </and> | |||||
| </condition> | |||||
| <fail unless="singlecopy.outcome">singlecopy failed</fail> | |||||
| </target> | |||||
| <target name="singlemove" depends="setup"> | |||||
| <move todir="${baseScratchDest}" enablemultiplemappings="false"> | |||||
| <fileset dir="${baseScratchSrc}" includes="somefile.txt"/> | |||||
| <mapper refid="testmapper"/> | |||||
| </move> | |||||
| <condition property="singlemove.outcome"> | |||||
| <and> | |||||
| <available file="${baseScratchDest}/somefile.txt"/> | |||||
| <not> | |||||
| <available file="${baseScratchDest}/somefile.txt${map.ext}"/> | |||||
| </not> | |||||
| <not> | |||||
| <available file="${baseScratchSrc}/somefile.txt"/> | |||||
| </not> | |||||
| </and> | |||||
| </condition> | |||||
| <fail unless="singlemove.outcome">singlemove failed</fail> | |||||
| </target> | |||||
| <!-- test dir w/ file + empty dir multimap copy --> | |||||
| <target name="copywithempty"> | |||||
| <delete dir="${baseScratchSrc}"/> | |||||
| <mkdir dir="${baseScratchSrc}/dirwithfile"/> | |||||
| <mkdir dir="${baseScratchSrc}/emptydir"/> | |||||
| <touch file="${baseScratchSrc}/dirwithfile/somefile.txt"/> | |||||
| <delete dir="${baseScratchDest}"/> | |||||
| <mkdir dir="${baseScratchDest}"/> | |||||
| <copy todir="${baseScratchDest}" enablemultiplemappings="true"> | |||||
| <fileset dir="${baseScratchSrc}" includes="**/*"/> | |||||
| <mapper refid="testmapper"/> | |||||
| </copy> | |||||
| <condition property="copywithempty.outcome"> | |||||
| <and> | |||||
| <available file="${baseScratchDest}/dirwithfile"/> | |||||
| <available file="${baseScratchDest}/dirwithfile${map.ext}"/> | |||||
| <available file="${baseScratchDest}/dirwithfile/somefile.txt"/> | |||||
| <available file="${baseScratchDest}/dirwithfile/somefile.txt${map.ext}"/> | |||||
| <not> | |||||
| <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt"/> | |||||
| </not> | |||||
| <not> | |||||
| <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt${map.ext}"/> | |||||
| </not> | |||||
| <available file="${baseScratchDest}/emptydir"/> | |||||
| <available file="${baseScratchDest}/emptydir${map.ext}"/> | |||||
| </and> | |||||
| </condition> | |||||
| <fail unless="copywithempty.outcome">copywithempty failed</fail> | |||||
| </target> | |||||
| <!-- test dir w/ file + empty dir multimap move --> | |||||
| <target name="movewithempty"> | |||||
| <delete dir="${baseScratchSrc}"/> | |||||
| <mkdir dir="${baseScratchSrc}/dirwithfile"/> | |||||
| <mkdir dir="${baseScratchSrc}/emptydir"/> | |||||
| <touch file="${baseScratchSrc}/dirwithfile/somefile.txt"/> | |||||
| <delete dir="${baseScratchDest}"/> | |||||
| <mkdir dir="${baseScratchDest}"/> | |||||
| <move todir="${baseScratchDest}" enablemultiplemappings="true"> | |||||
| <fileset dir="${baseScratchSrc}" includes="**/*"/> | |||||
| <mapper refid="testmapper"/> | |||||
| </move> | |||||
| <condition property="movewithempty.outcome"> | |||||
| <and> | |||||
| <available file="${baseScratchDest}/dirwithfile"/> | |||||
| <available file="${baseScratchDest}/dirwithfile${map.ext}"/> | |||||
| <available file="${baseScratchDest}/dirwithfile/somefile.txt"/> | |||||
| <available file="${baseScratchDest}/dirwithfile/somefile.txt${map.ext}"/> | |||||
| <not> | |||||
| <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt"/> | |||||
| </not> | |||||
| <not> | |||||
| <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt${map.ext}"/> | |||||
| </not> | |||||
| <available file="${baseScratchDest}/emptydir"/> | |||||
| <available file="${baseScratchDest}/emptydir${map.ext}"/> | |||||
| <not> | |||||
| <available file="${baseScratchSrc}/dirwithfile"/> | |||||
| </not> | |||||
| <not> | |||||
| <available file="${baseScratchSrc}/emptydir"/> | |||||
| </not> | |||||
| </and> | |||||
| </condition> | |||||
| <fail unless="movewithempty.outcome">movewithempty failed</fail> | |||||
| </target> | |||||
| <target name="cleanup"> | |||||
| <delete dir="${rootScratchDir}"/> | |||||
| </target> | |||||
| </project> | |||||
| @@ -102,6 +102,7 @@ public class Copy extends Task { | |||||
| protected File destDir = null; // the destination directory | protected File destDir = null; // the destination directory | ||||
| protected Vector filesets = new Vector(); | protected Vector filesets = new Vector(); | ||||
| private boolean enableMultipleMappings = false; | |||||
| protected boolean filtering = false; | protected boolean filtering = false; | ||||
| protected boolean preserveLastModified = false; | protected boolean preserveLastModified = false; | ||||
| protected boolean forceOverwrite = false; | protected boolean forceOverwrite = false; | ||||
| @@ -259,6 +260,28 @@ public class Copy extends Task { | |||||
| this.includeEmpty = includeEmpty; | this.includeEmpty = includeEmpty; | ||||
| } | } | ||||
| /** | |||||
| * Attribute to handle mappers that return multiple | |||||
| * mappings for a given source path. | |||||
| * @param enableMultipleMappings If true the task will | |||||
| * copy to all the mappings for a given source path, if | |||||
| * false, only the first file or directory is | |||||
| * processed. | |||||
| * By default, this setting is false to provide backward | |||||
| * compatibility with earlier releases. | |||||
| * @since 1.6 | |||||
| */ | |||||
| public void setEnableMultipleMappings(boolean enableMultipleMappings) { | |||||
| this.enableMultipleMappings = enableMultipleMappings; | |||||
| } | |||||
| /** | |||||
| * @return the value of the enableMultipleMapping attribute | |||||
| */ | |||||
| public boolean isEnableMultipleMapping() { | |||||
| return enableMultipleMappings; | |||||
| } | |||||
| /** | /** | ||||
| * If false, note errors to the output but keep going. | * If false, note errors to the output but keep going. | ||||
| * @param failonerror true or false | * @param failonerror true or false | ||||
| @@ -354,7 +377,7 @@ public class Copy extends Task { | |||||
| if (forceOverwrite || !destFile.exists() | if (forceOverwrite || !destFile.exists() | ||||
| || (file.lastModified() > destFile.lastModified())) { | || (file.lastModified() > destFile.lastModified())) { | ||||
| fileCopyMap.put(file.getAbsolutePath(), | fileCopyMap.put(file.getAbsolutePath(), | ||||
| destFile.getAbsolutePath()); | |||||
| new String[] {destFile.getAbsolutePath()}); | |||||
| } else { | } else { | ||||
| log(file + " omitted as " + destFile | log(file + " omitted as " + destFile | ||||
| + " is up to date.", Project.MSG_VERBOSE); | + " is up to date.", Project.MSG_VERBOSE); | ||||
| @@ -528,8 +551,20 @@ public class Copy extends Task { | |||||
| for (int i = 0; i < toCopy.length; i++) { | for (int i = 0; i < toCopy.length; i++) { | ||||
| File src = new File(fromDir, toCopy[i]); | File src = new File(fromDir, toCopy[i]); | ||||
| File dest = new File(toDir, mapper.mapFileName(toCopy[i])[0]); | |||||
| map.put(src.getAbsolutePath(), dest.getAbsolutePath()); | |||||
| String[] mappedFiles = mapper.mapFileName(toCopy[i]); | |||||
| if (!enableMultipleMappings) { | |||||
| map.put(src.getAbsolutePath(), | |||||
| new String[] {new File(toDir, mappedFiles[0]).getAbsolutePath()}); | |||||
| } else { | |||||
| // reuse the array created by the mapper | |||||
| for (int k = 0; k < mappedFiles.length; k++) { | |||||
| mappedFiles[k] = new File(toDir, mappedFiles[k]).getAbsolutePath(); | |||||
| } | |||||
| map.put(src.getAbsolutePath(), mappedFiles); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -546,64 +581,74 @@ public class Copy extends Task { | |||||
| Enumeration e = fileCopyMap.keys(); | Enumeration e = fileCopyMap.keys(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| String fromFile = (String) e.nextElement(); | String fromFile = (String) e.nextElement(); | ||||
| String toFile = (String) fileCopyMap.get(fromFile); | |||||
| if (fromFile.equals(toFile)) { | |||||
| log("Skipping self-copy of " + fromFile, verbosity); | |||||
| continue; | |||||
| } | |||||
| String[] toFiles = (String[]) fileCopyMap.get(fromFile); | |||||
| try { | |||||
| log("Copying " + fromFile + " to " + toFile, verbosity); | |||||
| for (int i = 0; i < toFiles.length; i++) { | |||||
| String toFile = toFiles[i]; | |||||
| FilterSetCollection executionFilters = | |||||
| new FilterSetCollection(); | |||||
| if (filtering) { | |||||
| executionFilters | |||||
| .addFilterSet(getProject().getGlobalFilterSet()); | |||||
| } | |||||
| for (Enumeration filterEnum = filterSets.elements(); | |||||
| filterEnum.hasMoreElements();) { | |||||
| executionFilters | |||||
| .addFilterSet((FilterSet) filterEnum.nextElement()); | |||||
| if (fromFile.equals(toFile)) { | |||||
| log("Skipping self-copy of " + fromFile, verbosity); | |||||
| continue; | |||||
| } | } | ||||
| fileUtils.copyFile(fromFile, toFile, executionFilters, | |||||
| filterChains, forceOverwrite, | |||||
| preserveLastModified, inputEncoding, | |||||
| outputEncoding, getProject()); | |||||
| } catch (IOException ioe) { | |||||
| String msg = "Failed to copy " + fromFile + " to " + toFile | |||||
| + " due to " + ioe.getMessage(); | |||||
| File targetFile = new File(toFile); | |||||
| if (targetFile.exists() && !targetFile.delete()) { | |||||
| msg += " and I couldn't delete the corrupt " + toFile; | |||||
| try { | |||||
| log("Copying " + fromFile + " to " + toFile, verbosity); | |||||
| FilterSetCollection executionFilters = | |||||
| new FilterSetCollection(); | |||||
| if (filtering) { | |||||
| executionFilters | |||||
| .addFilterSet(getProject().getGlobalFilterSet()); | |||||
| } | |||||
| for (Enumeration filterEnum = filterSets.elements(); | |||||
| filterEnum.hasMoreElements();) { | |||||
| executionFilters | |||||
| .addFilterSet((FilterSet) filterEnum.nextElement()); | |||||
| } | |||||
| fileUtils.copyFile(fromFile, toFile, executionFilters, | |||||
| filterChains, forceOverwrite, | |||||
| preserveLastModified, inputEncoding, | |||||
| outputEncoding, getProject()); | |||||
| } catch (IOException ioe) { | |||||
| String msg = "Failed to copy " + fromFile + " to " + toFile | |||||
| + " due to " + ioe.getMessage(); | |||||
| File targetFile = new File(toFile); | |||||
| if (targetFile.exists() && !targetFile.delete()) { | |||||
| msg += " and I couldn't delete the corrupt " + toFile; | |||||
| } | |||||
| throw new BuildException(msg, ioe, getLocation()); | |||||
| } | } | ||||
| throw new BuildException(msg, ioe, getLocation()); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (includeEmpty) { | if (includeEmpty) { | ||||
| Enumeration e = dirCopyMap.elements(); | Enumeration e = dirCopyMap.elements(); | ||||
| int count = 0; | |||||
| int createCount = 0; | |||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| File d = new File((String) e.nextElement()); | |||||
| if (!d.exists()) { | |||||
| if (!d.mkdirs()) { | |||||
| log("Unable to create directory " | |||||
| + d.getAbsolutePath(), Project.MSG_ERR); | |||||
| } else { | |||||
| count++; | |||||
| String[] dirs = (String[]) e.nextElement(); | |||||
| for (int i = 0; i < dirs.length; i++) { | |||||
| File d = new File(dirs[i]); | |||||
| if (!d.exists()) { | |||||
| if (!d.mkdirs()) { | |||||
| log("Unable to create directory " | |||||
| + d.getAbsolutePath(), Project.MSG_ERR); | |||||
| } else { | |||||
| createCount++; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (count > 0) { | |||||
| log("Copied " + count + " empty director" | |||||
| + (count == 1 ? "y" : "ies") | |||||
| + " to " + destDir.getAbsolutePath()); | |||||
| if (createCount > 0) { | |||||
| log("Copied " + dirCopyMap.size() | |||||
| + " empty director" | |||||
| + (dirCopyMap.size() == 1 ? "y" : "ies") | |||||
| + " to " + createCount | |||||
| + " empty director" | |||||
| + (createCount == 1 ? "y" : "ies") + " under " | |||||
| + destDir.getAbsolutePath()); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -125,67 +125,29 @@ public class Move extends Copy { | |||||
| Enumeration e = fileCopyMap.keys(); | Enumeration e = fileCopyMap.keys(); | ||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| String fromFile = (String) e.nextElement(); | String fromFile = (String) e.nextElement(); | ||||
| String toFile = (String) fileCopyMap.get(fromFile); | |||||
| if (fromFile.equals(toFile)) { | |||||
| log("Skipping self-move of " + fromFile, verbosity); | |||||
| continue; | |||||
| } | |||||
| boolean moved = false; | |||||
| File f = new File(fromFile); | File f = new File(fromFile); | ||||
| boolean selfMove = false; | |||||
| if (f.exists()) { //Is this file still available to be moved? | if (f.exists()) { //Is this file still available to be moved? | ||||
| File d = new File(toFile); | |||||
| try { | |||||
| log("Attempting to rename: " + fromFile | |||||
| + " to " + toFile, verbosity); | |||||
| moved = renameFile(f, d, filtering, forceOverwrite); | |||||
| } catch (IOException ioe) { | |||||
| String msg = "Failed to rename " + fromFile | |||||
| + " to " + toFile | |||||
| + " due to " + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe, getLocation()); | |||||
| } | |||||
| String[] toFiles = (String[]) fileCopyMap.get(fromFile); | |||||
| for (int i = 0; i < toFiles.length; i++) { | |||||
| String toFile = (String) toFiles[i]; | |||||
| if (!moved) { | |||||
| try { | |||||
| log("Moving " + fromFile + " to " + toFile, | |||||
| verbosity); | |||||
| if (fromFile.equals(toFile)) { | |||||
| log("Skipping self-move of " + fromFile, verbosity); | |||||
| selfMove = true; | |||||
| FilterSetCollection executionFilters = | |||||
| new FilterSetCollection(); | |||||
| if (filtering) { | |||||
| executionFilters | |||||
| .addFilterSet(getProject().getGlobalFilterSet()); | |||||
| } | |||||
| for (Enumeration filterEnum = | |||||
| getFilterSets().elements(); | |||||
| filterEnum.hasMoreElements();) { | |||||
| executionFilters | |||||
| .addFilterSet((FilterSet) filterEnum | |||||
| .nextElement()); | |||||
| } | |||||
| getFileUtils().copyFile(f, d, executionFilters, | |||||
| getFilterChains(), | |||||
| forceOverwrite, | |||||
| getPreserveLastModified(), | |||||
| getEncoding(), | |||||
| getOutputEncoding(), | |||||
| getProject()); | |||||
| f = new File(fromFile); | |||||
| if (!f.delete()) { | |||||
| throw new BuildException("Unable to delete " | |||||
| + "file " | |||||
| + f.getAbsolutePath()); | |||||
| } | |||||
| } catch (IOException ioe) { | |||||
| String msg = "Failed to copy " + fromFile + " to " | |||||
| + toFile | |||||
| + " due to " + ioe.getMessage(); | |||||
| throw new BuildException(msg, ioe, getLocation()); | |||||
| // 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); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -194,32 +156,121 @@ public class Move extends Copy { | |||||
| if (includeEmpty) { | if (includeEmpty) { | ||||
| Enumeration e = dirCopyMap.keys(); | Enumeration e = dirCopyMap.keys(); | ||||
| int count = 0; | |||||
| int createCount = 0; | |||||
| while (e.hasMoreElements()) { | while (e.hasMoreElements()) { | ||||
| String fromDirName = (String) e.nextElement(); | String fromDirName = (String) e.nextElement(); | ||||
| String toDirName = (String) dirCopyMap.get(fromDirName); | |||||
| File fromDir = new File(fromDirName); | |||||
| File toDir = new File(toDirName); | |||||
| if (!toDir.exists()) { | |||||
| if (!toDir.mkdirs()) { | |||||
| log("Unable to create directory " | |||||
| + toDirName, Project.MSG_ERR); | |||||
| } else { | |||||
| count++; | |||||
| 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()) { | |||||
| log("Unable to create directory " | |||||
| + d.getAbsolutePath(), Project.MSG_ERR); | |||||
| } else { | |||||
| createCount++; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| if (okToDelete(fromDir)) { | |||||
| File fromDir = new File(fromDirName); | |||||
| if (!selfMove && okToDelete(fromDir)) { | |||||
| deleteDir(fromDir); | deleteDir(fromDir); | ||||
| } | } | ||||
| } | } | ||||
| if (count > 0) { | |||||
| log("Moved " + count + " empty directories to " | |||||
| 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()); | + 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 (!fromFile.delete()) { | |||||
| 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 (Enumeration filterEnum = | |||||
| getFilterSets().elements(); | |||||
| filterEnum.hasMoreElements();) { | |||||
| executionFilters | |||||
| .addFilterSet((FilterSet) filterEnum | |||||
| .nextElement()); | |||||
| } | |||||
| getFileUtils().copyFile(fromFile, toFile, executionFilters, | |||||
| getFilterChains(), | |||||
| forceOverwrite, | |||||
| getPreserveLastModified(), | |||||
| getEncoding(), | |||||
| getOutputEncoding(), | |||||
| getProject()); | |||||
| } 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 | * Its only ok to delete a directory tree if there are | ||||
| * no files in it. | * no files in it. | ||||
| @@ -0,0 +1,114 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
| * reserved. | |||||
| * | |||||
| * Redistribution and use in source and binary forms, with or without | |||||
| * modification, are permitted provided that the following conditions | |||||
| * are met: | |||||
| * | |||||
| * 1. Redistributions of source code must retain the above copyright | |||||
| * notice, this list of conditions and the following disclaimer. | |||||
| * | |||||
| * 2. Redistributions in binary form must reproduce the above copyright | |||||
| * notice, this list of conditions and the following disclaimer in | |||||
| * the documentation and/or other materials provided with the | |||||
| * distribution. | |||||
| * | |||||
| * 3. The end-user documentation included with the redistribution, if | |||||
| * any, must include the following acknowlegement: | |||||
| * "This product includes software developed by the | |||||
| * Apache Software Foundation (http://www.apache.org/)." | |||||
| * Alternately, this acknowlegement may appear in the software itself, | |||||
| * if and wherever such third-party acknowlegements normally appear. | |||||
| * | |||||
| * 4. The names "Ant" and "Apache Software | |||||
| * Foundation" must not be used to endorse or promote products derived | |||||
| * from this software without prior written permission. For written | |||||
| * permission, please contact apache@apache.org. | |||||
| * | |||||
| * 5. Products derived from this software may not be called "Apache" | |||||
| * nor may "Apache" appear in their names without prior written | |||||
| * permission of the Apache Group. | |||||
| * | |||||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
| * SUCH DAMAGE. | |||||
| * ==================================================================== | |||||
| * | |||||
| * This software consists of voluntary contributions made by many | |||||
| * individuals on behalf of the Apache Software Foundation. For more | |||||
| * information on the Apache Software Foundation, please see | |||||
| * <http://www.apache.org/>. | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs; | |||||
| import java.lang.reflect.Method; | |||||
| import org.apache.tools.ant.BuildFileTest; | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.util.FileNameMapper; | |||||
| /** | |||||
| * @author Peter Reilly | |||||
| */ | |||||
| public class MultiMapTest extends BuildFileTest { | |||||
| public MultiMapTest(String name) { | |||||
| super(name); | |||||
| } | |||||
| public void setUp() { | |||||
| configureProject("src/etc/testcases/taskdefs/multimap.xml"); | |||||
| } | |||||
| public void tearDown() { | |||||
| executeTarget("cleanup"); | |||||
| } | |||||
| public void testMultiCopy() { | |||||
| executeTarget("multicopy"); | |||||
| } | |||||
| public void testMultiMove() { | |||||
| executeTarget("multimove"); | |||||
| } | |||||
| public void testSingleCopy() { | |||||
| executeTarget("singlecopy"); | |||||
| } | |||||
| public void testSingleMove() { | |||||
| executeTarget("singlemove"); | |||||
| } | |||||
| public void testCopyWithEmpty() { | |||||
| executeTarget("copywithempty"); | |||||
| } | |||||
| public void testMoveWithEmpty() { | |||||
| executeTarget("movewithempty"); | |||||
| } | |||||
| public static class TestMapper implements FileNameMapper { | |||||
| public TestMapper() {} | |||||
| public void setFrom(String from) {} | |||||
| public void setTo(String to) {} | |||||
| public String[] mapFileName(final String source_file_name) { | |||||
| return new String[] { | |||||
| source_file_name, source_file_name+".copy2" }; | |||||
| } | |||||
| } | |||||
| } | |||||