git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@292247 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -10,15 +10,18 @@ | |||
| <h2><a name="copy">Copy</a></h2> | |||
| <h3>Description</h3> | |||
| <p>Copies a file or FileSet to a new file or directory. By default, files are | |||
| <p>Copies a file or resource collection to a new file or directory. By default, files are | |||
| only copied if the source file is newer than the destination file, | |||
| or when the destination file does not exist. However, you can explicitly | |||
| overwrite files with the <code>overwrite</code> attribute.</p> | |||
| <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select a | |||
| set of files to copy. | |||
| To use a <code><fileset></code>, the <code>todir</code> attribute | |||
| must be set.</p> | |||
| <p><a href="../CoreTypes/resources.html#collection">Resource | |||
| Collection</a>s are used to select a group of files to copy. Only | |||
| file system based resource collections are supported, this includes <a | |||
| href="../CoreTypes/fileset.html">fileset</a>s, <a | |||
| href="../CoreTypes/filelist.html">filelist</a> and <a | |||
| href="../using.html#path">path</a>. To use a resource collection, the | |||
| <code>todir</code> attribute must be set.</p> | |||
| <p> | |||
| <strong>Note: </strong>If you employ filters in your copy operation, you should | |||
| @@ -39,7 +42,7 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a> | |||
| <td valign="top">file</td> | |||
| <td valign="top">The file to copy.</td> | |||
| <td valign="top" align="center">Yes, unless a nested | |||
| <code><fileset></code> element is used.</td> | |||
| resource collection element is used.</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">preservelastmodified</td> | |||
| @@ -52,7 +55,7 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a> | |||
| <td valign="top">The file to copy to.</td> | |||
| <td valign="top" align="center" rowspan="2">With the <code>file</code> | |||
| attribute, either <code>tofile</code> or <code>todir</code> can be used. | |||
| With nested <code><fileset></code> elements, if the set of files | |||
| With nested resource collection elements, if the number of included files | |||
| is greater than 1, or if only the <code>dir</code> attribute is | |||
| specified in the <code><fileset></code>, or if the | |||
| <code>file</code> attribute is also specified, then only | |||
| @@ -141,10 +144,12 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a> | |||
| </table> | |||
| <h3>Parameters specified as nested elements</h3> | |||
| <h4>fileset</h4> | |||
| <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select | |||
| sets of files to copy. | |||
| To use a fileset, the <code>todir</code> attribute must be set.</p> | |||
| <h4>fileset or any other filesystem based resource collection</h4> | |||
| <p><a href="../CoreTypes/resources.html#collection">Resource | |||
| Collection</a>s are used to select groups of files to copy. To use a | |||
| resource collection, the <code>todir</code> attribute must be set.</p> | |||
| <p>Prior to Ant 1.7 only <code><fileset></code> has been | |||
| supported as a nested element.</p> | |||
| <h4>mapper</h4> | |||
| <p>You can define filename transformations by using a nested <a | |||
| @@ -156,6 +161,13 @@ sets of files to copy. | |||
| one can use a filenamemapper type in place of the mapper element. | |||
| </p> | |||
| <p>Note that the source name handed to the mapper depends on the | |||
| resource collection you use. If you use <code><fileset></code> | |||
| or any other collection that provides a base directory, the name | |||
| passed to the mapper will be a relative filename, relative to the base | |||
| directory. In any other case the absolute filename of the source will | |||
| be used.</p> | |||
| <h4>filterset</h4> | |||
| <p><a href="../CoreTypes/filterset.html">FilterSet</a>s are used to replace | |||
| tokens in files that are copied. | |||
| @@ -207,7 +219,6 @@ followed by <code><filterset></code> elements. | |||
| </copy> | |||
| </pre> | |||
| <p><b>Copy a set of files to a directory, replacing @TITLE@ with Foo Bar | |||
| in all files.</b></p> | |||
| <pre> | |||
| @@ -219,6 +230,16 @@ in all files.</b></p> | |||
| </copy> | |||
| </pre> | |||
| <p><b>Collect all items from the current CLASSPATH setting into a | |||
| destination directory, flattening the directory structure.</b></p> | |||
| <pre> | |||
| <copy todir="dest" flatten="true"> | |||
| <path> | |||
| <pathelement path="${java.class.path}"/> | |||
| </path> | |||
| </copy> | |||
| </pre> | |||
| <p><strong>Unix Note:</strong> File permissions are not retained when files | |||
| are copied; they end up with the default <code>UMASK</code> permissions | |||
| instead. This | |||
| @@ -10,13 +10,22 @@ | |||
| <h2><a name="move">Move</a></h2> | |||
| <h3>Description</h3> | |||
| <p>Moves a file to a new file or directory, or sets of files to | |||
| <p>Moves a file to a new file or directory, or collections of files to | |||
| a new directory. By default, the | |||
| destination file is overwritten if it already exists. When <var>overwrite</var> 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> | |||
| <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select sets of files | |||
| to move to the <var>todir</var> directory.</p> | |||
| <p><a href="../CoreTypes/resources.html#collection">Resource | |||
| Collection</a>s are used to select a group of files to move. Only | |||
| file system based resource collections are supported, this includes <a | |||
| href="../CoreTypes/fileset.html">fileset</a>s, <a | |||
| href="../CoreTypes/filelist.html">filelist</a> and <a | |||
| href="../using.html#path">path</a>. Prior to Ant 1.7 only | |||
| <code><fileset></code> has been supported as a nested element. | |||
| To use a resource collection, the <code>todir</code> attribute must be | |||
| set.</p> | |||
| <p><b>Since Ant 1.6.3</b>, the <i>file</i> attribute may be used to move | |||
| (rename) an entire directory. If <i>tofile</i> denotes an existing file, or | |||
| there is a directory by the same name in <i>todir</i>, the action will fail. | |||
| @@ -32,7 +41,7 @@ there is a directory by the same name in <i>todir</i>, the action will fail. | |||
| <td valign="top">file</td> | |||
| <td valign="top">the file or directory to move</td> | |||
| <td valign="top" align="center">One of <var>file</var> or | |||
| at least one nested fileset element</td> | |||
| at least one nested resource collection element</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">preservelastmodified</td> | |||
| @@ -135,6 +144,12 @@ there is a directory by the same name in <i>todir</i>, the action will fail. | |||
| href="../CoreTypes/mapper.html">mapper</a> element. The default mapper used by | |||
| <code><move></code> is the <a | |||
| href="../CoreTypes/mapper.html#identity-mapper">identity</a>.</p> | |||
| <p>Note that the source name handed to the mapper depends on the | |||
| resource collection you use. If you use <code><fileset></code> | |||
| or any other collection that provides a base directory, the name | |||
| passed to the mapper will be a relative filename, relative to the base | |||
| directory. In any other case the absolute filename of the source will | |||
| be used.</p> | |||
| <h4>filterchain</h4> | |||
| <p>The Move task supports nested <a href="../CoreTypes/filterchain.html"> | |||
| FilterChain</a>s.</p> | |||
| @@ -173,6 +188,15 @@ followed by <code><filterset></code> elements. | |||
| </fileset> | |||
| </move> | |||
| </pre> | |||
| <p><b>Move a list of files to a new directory</b></p> | |||
| <pre> | |||
| <move todir="some/new/dir"> | |||
| <filelist dir="my/src/dir"> | |||
| <file name="file1.txt"/> | |||
| <file name="file2.txt"/> | |||
| </filelist> | |||
| </move> | |||
| </pre> | |||
| <p><b>Append <code>".bak"</code> to the names of all files | |||
| in a directory.</b></p> | |||
| <pre> | |||
| @@ -13,10 +13,10 @@ | |||
| <h3>Description</h3> | |||
| <p>Synchronize a target directory from the files defined in one or | |||
| more filesets.</p> | |||
| more filesystem based <a href="../CoreTypes/resources.html#collection">Resource Collection</a>s.</p> | |||
| <p>Any file in the target directory that has not been matched by at | |||
| least one of the nested filesets gets removed. I.e. if you exclude a | |||
| least one of the nested resource collection gets removed. I.e. if you exclude a | |||
| file in your sources and a file of that name is present in the target | |||
| dir, it will get removed from the target.</p> | |||
| @@ -29,7 +29,7 @@ dir, it will get removed from the target.</p> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">todir</td> | |||
| <td valign="top">the target directory to sync with the filesets</td> | |||
| <td valign="top">the target directory to sync with the resource collections</td> | |||
| <td align="center" valign="top">Yes</td> | |||
| </tr> | |||
| <tr> | |||
| @@ -40,7 +40,7 @@ dir, it will get removed from the target.</p> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">includeEmptyDirs</td> | |||
| <td valign="top">Copy any empty directories included in the FileSet(s). | |||
| <td valign="top">Copy any empty directories included in the resource collection(s). | |||
| </td> | |||
| <td valign="top" align="center">No; defaults to true.</td> | |||
| </tr> | |||
| @@ -72,9 +72,12 @@ dir, it will get removed from the target.</p> | |||
| <h3>Parameters specified as nested elements</h3> | |||
| <h4>fileset</h4> | |||
| <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select | |||
| sets of files and directories.</p> | |||
| <h4>fileset or any other filesystem based resource collection</h4> | |||
| <p><a href="../CoreTypes/resources.html#collection">Resource | |||
| Collection</a>s are used to select groups of files to copy. To use a | |||
| resource collection, the <code>todir</code> attribute must be set.</p> | |||
| <p>Prior to Ant 1.7 only <code><fileset></code> has been | |||
| supported as a nested element.</p> | |||
| <h4>preserveInTarget</h4> | |||
| @@ -76,6 +76,14 @@ a=b= | |||
| </copy> | |||
| </target> | |||
| <target name="test_single_file_path"> | |||
| <copy tofile="copytest_single_file_path.tmp"> | |||
| <path> | |||
| <pathelement location="copy.xml"/> | |||
| </path> | |||
| </copy> | |||
| </target> | |||
| <target name="testFilterSet"> | |||
| <copy file="copy.filterset" tofile="copy.filterset.tmp"> | |||
| <filterset> | |||
| @@ -121,76 +129,75 @@ a=b= | |||
| </copy> | |||
| </target> | |||
| <!-- | |||
| <!-- | |||
| <typedef name="resource" classname="org.apache.tools.ant.types.Resource"/> | |||
| <typedef name="resources" classname="org.apache.tools.ant.types.resources.Resources"/> | |||
| --> | |||
| <property name="to.dir" value="copy-todir-tmp"/> | |||
| <property name="from.dir" value="copy-fromdir-tmp"/> | |||
| <target name="testResource.prepare"> | |||
| <mkdir dir="${from.dir}"/> | |||
| <concat destfile="${from.dir}/file1.txt">This is file 1</concat> | |||
| <concat destfile="${from.dir}/file2.txt">This is file 2</concat> | |||
| <concat destfile="${from.dir}/file3.txt">This is file 3</concat> | |||
| <concat destfile="${from.dir}/fileNR.txt">This is file @NR@</concat> | |||
| </target> | |||
| <target name="testFileResourcePlain" depends="testResource.prepare"> | |||
| <copy todir="${to.dir}"> | |||
| <copy todir="${to.dir}" flatten="true"> | |||
| <resources> | |||
| <file file="${from.dir}/file1.txt"/> | |||
| <file file="${from.dir}/file2.txt"/> | |||
| <file file="${from.dir}/file3.txt"/> | |||
| </resources> | |||
| </copy> | |||
| </resources> | |||
| </copy> | |||
| </target> | |||
| <target name="testFileResourceWithMapper" depends="testResource.prepare"> | |||
| <copy todir="${to.dir}"> | |||
| <copy todir="${to.dir}" flatten="true"> | |||
| <resources> | |||
| <file file="${from.dir}/file1.txt"/> | |||
| <file file="${from.dir}/file2.txt"/> | |||
| <file file="${from.dir}/file3.txt"/> | |||
| </resources> | |||
| </resources> | |||
| <regexpmapper from="^(.*)\.txt$$" to="\1.txt.bak"/> | |||
| </copy> | |||
| </copy> | |||
| </target> | |||
| <property name="to.dir" value="copy-todir-tmp"/> | |||
| <property name="from.dir" value="copy-todir-tmp"/> | |||
| <target name="testResource.prepare"> | |||
| <mkdir dir="${from.dir}"/> | |||
| <concat destfile="${to.dir}/file1.txt">This is file 1</concat> | |||
| <concat destfile="${to.dir}/file2.txt">This is file 2</concat> | |||
| <concat destfile="${to.dir}/file3.txt">This is file 3</concat> | |||
| <concat destfile="${to.dir}/fileNR.txt">This is file @nr@</concat> | |||
| </target> | |||
| <target name="testFileResourceWithFilter" depends="testResource.prepare"> | |||
| <copy todir="${to.dir}"> | |||
| <copy todir="${to.dir}" flatten="true"> | |||
| <resources> | |||
| <file file="${from.dir}/fileNR.txt"/> | |||
| </resources> | |||
| </resources> | |||
| <filterset> | |||
| <filter token="NR" value="42"/> | |||
| </filterset> | |||
| </copy> | |||
| <filter token="NR" value="42"/> | |||
| </filterset> | |||
| </copy> | |||
| </target> | |||
| <target name="testResourcePlain"> | |||
| </target> | |||
| <target name="testResourcePlainWithMapper"> | |||
| </target> | |||
| <target name="testResourcePlainWithFilter"> | |||
| </target> | |||
| <target name="testOnlineResources"> | |||
| </target> | |||
| <target name="testPathAsResource"> | |||
| <target name="testPathAsResource" depends="testResource.prepare"> | |||
| <copy todir="${to.dir}"> | |||
| <path> | |||
| <fileset dir="${from.dir}"/> | |||
| </path> | |||
| </copy> | |||
| </path> | |||
| </copy> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete file="copytest1.tmp"/> | |||
| @@ -204,7 +211,8 @@ a=b= | |||
| <delete dir="copytest1dir"/> | |||
| <delete quiet="yes" file="copy.filter.out"/> | |||
| <delete quiet="yes" file="copy.filter.inp"/> | |||
| <delete dir="${to.dir}"/> | |||
| <delete dir="${from.dir}"/> | |||
| <delete dir="${to.dir}"/> | |||
| </target> | |||
| </project> | |||
| @@ -59,6 +59,26 @@ | |||
| </move> | |||
| </target> | |||
| <target name="testCompleteDirectoryMove2"> | |||
| <mkdir dir="A"/> | |||
| <touch file="A/1"/> | |||
| <move todir="E"> | |||
| <path> | |||
| <fileset dir="A"/> | |||
| </path> | |||
| </move> | |||
| </target> | |||
| <target name="testPathElementMove"> | |||
| <mkdir dir="A"/> | |||
| <touch file="A/1"/> | |||
| <move todir="E" flatten="true"> | |||
| <path> | |||
| <pathelement location="A/1"/> | |||
| </path> | |||
| </move> | |||
| </target> | |||
| <target name="testMoveFileAndFileset"> | |||
| <mkdir dir="A" /> | |||
| <touch> | |||
| @@ -35,6 +35,19 @@ | |||
| </sync> | |||
| </target> | |||
| <target name="copyandremove-with-filelist" depends="setup"> | |||
| <mkdir dir="${src}/a/b/c"/> | |||
| <touch file="${src}/a/b/c/d"/> | |||
| <mkdir dir="${dest}/e"/> | |||
| <touch file="${dest}/e/f"/> | |||
| <sync todir="${dest}"> | |||
| <filelist dir="${src}"> | |||
| <file name="a/b/c/d"/> | |||
| <file name="not-there"/> | |||
| </filelist> | |||
| </sync> | |||
| </target> | |||
| <target name="copyandremove-emptypreserve" depends="setup"> | |||
| <mkdir dir="${src}/a/b/c"/> | |||
| <touch file="${src}/a/b/c/d"/> | |||
| @@ -19,9 +19,15 @@ package org.apache.tools.ant.taskdefs; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Vector; | |||
| import java.util.Hashtable; | |||
| import java.util.ArrayList; | |||
| import java.util.Enumeration; | |||
| import java.util.HashMap; | |||
| import java.util.HashSet; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.BuildException; | |||
| @@ -32,9 +38,8 @@ import org.apache.tools.ant.types.FilterSet; | |||
| import org.apache.tools.ant.types.FilterChain; | |||
| import org.apache.tools.ant.types.FilterSetCollection; | |||
| import org.apache.tools.ant.types.Resource; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.ResourceCollection; | |||
| import org.apache.tools.ant.types.resources.Resources; | |||
| import org.apache.tools.ant.types.resources.FileResource; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| import org.apache.tools.ant.util.FileNameMapper; | |||
| import org.apache.tools.ant.util.IdentityMapper; | |||
| @@ -57,10 +62,12 @@ import org.apache.tools.ant.util.FlatFileNameMapper; | |||
| * @ant.task category="filesystem" | |||
| */ | |||
| public class Copy extends Task { | |||
| private static final File NULL_FILE_PLACEHOLDER = new File("/NULL_FILE"); | |||
| protected File file = null; // the source file | |||
| protected File destFile = null; // the destination file | |||
| protected File destDir = null; // the destination directory | |||
| protected Vector filesets = new Vector(); | |||
| protected Vector rcs = new Vector(); | |||
| private boolean enableMultipleMappings = false; | |||
| protected boolean filtering = false; | |||
| @@ -276,43 +283,17 @@ public class Copy extends Task { | |||
| * @param set a set of files to copy. | |||
| */ | |||
| public void addFileset(FileSet set) { | |||
| filesets.addElement(set); | |||
| add(set); | |||
| } | |||
| /* JHM: It would be the finest solution to use this method directly. | |||
| * But if I understood the IntrospectionHelper(final Class bean) | |||
| * right - especially line 258ff (the last "else if" statement), | |||
| * I must have a <b>class</b> with an no-arg constructor. But I only | |||
| * have an interface. :-( | |||
| * So I have to add the three methods ... But I can reuse this | |||
| * method :-) | |||
| * | |||
| */ | |||
| public void add(ResourceCollection res) { | |||
| //TODO: implement resources | |||
| } | |||
| /** | |||
| * Adds a <code>path</code> element as a nested ResourceCollection. | |||
| * @param path | |||
| * Add a collection of files to copy. | |||
| * @param res a resource collection to copy. | |||
| * @since Ant 1.7 | |||
| */ | |||
| public void addPath(Path path) { | |||
| //add((ResourceCollection)path); | |||
| } | |||
| /** | |||
| * Adds a Resource element as a nested ResourceCollection. | |||
| * @param path | |||
| * / | |||
| public void add(Resource res) { | |||
| add((ResourceCollection)res); | |||
| } | |||
| /** | |||
| * Adds a <code>resources</code> element as a nested ResourceCollection. | |||
| * @param path | |||
| * / | |||
| public void add(Resources res) { | |||
| add((ResourceCollection)res); | |||
| public void add(ResourceCollection res) { | |||
| rcs.add(res); | |||
| } | |||
| */ | |||
| /** | |||
| * Define the mapper to map source to destination files. | |||
| @@ -400,10 +381,10 @@ public class Copy extends Task { | |||
| File savedFile = file; // may be altered in validateAttributes | |||
| File savedDestFile = destFile; | |||
| File savedDestDir = destDir; | |||
| FileSet savedFileSet = null; | |||
| if (file == null && destFile != null && filesets.size() == 1) { | |||
| ResourceCollection savedRc = null; | |||
| if (file == null && destFile != null && rcs.size() == 1) { | |||
| // will be removed in validateAttributes | |||
| savedFileSet = (FileSet) filesets.elementAt(0); | |||
| savedRc = (ResourceCollection) rcs.elementAt(0); | |||
| } | |||
| // make sure we don't have an illegal set of options | |||
| validateAttributes(); | |||
| @@ -434,30 +415,96 @@ public class Copy extends Task { | |||
| } | |||
| } | |||
| } | |||
| // deal with the filesets | |||
| for (int i = 0; i < filesets.size(); i++) { | |||
| FileSet fs = (FileSet) filesets.elementAt(i); | |||
| DirectoryScanner ds = null; | |||
| try { | |||
| ds = fs.getDirectoryScanner(getProject()); | |||
| } catch (BuildException e) { | |||
| if (failonerror | |||
| || !e.getMessage().endsWith(" not found.")) { | |||
| throw e; | |||
| } else { | |||
| log("Warning: " + e.getMessage()); | |||
| continue; | |||
| } | |||
| } | |||
| File fromDir = fs.getDir(getProject()); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| String[] srcDirs = ds.getIncludedDirectories(); | |||
| if (!flatten && mapperElement == null | |||
| && ds.isEverythingIncluded() && !fs.hasPatterns()) { | |||
| completeDirMap.put(fromDir, destDir); | |||
| } | |||
| scan(fromDir, destDir, srcFiles, srcDirs); | |||
| // deal with the ResourceCollections | |||
| /* for historical and performance reasons we have to do | |||
| things in a rather complex way. | |||
| (1) Move is optimized to move directories if a fileset | |||
| has been included completely, therefore FileSets need a | |||
| special treatment. This is also required to support | |||
| the failOnError semantice (skip filesets with broken | |||
| basedir but handle the remaining collections). | |||
| (2) We carry around a few protected methods that work | |||
| on basedirs and arrays of names. To optimize stuff, all | |||
| resources with the same basedir get collected in | |||
| separate lists and then each list is handled in one go. | |||
| */ | |||
| HashMap filesByBasedir = new HashMap(); | |||
| HashMap dirsByBasedir = new HashMap(); | |||
| HashSet baseDirs = new HashSet(); | |||
| for (int i = 0; i < rcs.size(); i++) { | |||
| ResourceCollection rc = (ResourceCollection) rcs.elementAt(i); | |||
| if (rc.isFilesystemOnly()) { | |||
| // Step (1) | |||
| if (rc instanceof FileSet) { | |||
| FileSet fs = (FileSet) rc; | |||
| DirectoryScanner ds = null; | |||
| try { | |||
| ds = fs.getDirectoryScanner(getProject()); | |||
| } catch (BuildException e) { | |||
| if (failonerror | |||
| || !e.getMessage().endsWith(" not found.")) { | |||
| throw e; | |||
| } else { | |||
| log("Warning: " + e.getMessage()); | |||
| continue; | |||
| } | |||
| } | |||
| File fromDir = fs.getDir(getProject()); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| String[] srcDirs = ds.getIncludedDirectories(); | |||
| if (!flatten && mapperElement == null | |||
| && ds.isEverythingIncluded() && !fs.hasPatterns()) { | |||
| completeDirMap.put(fromDir, destDir); | |||
| } | |||
| add(fromDir, srcFiles, filesByBasedir); | |||
| add(fromDir, srcDirs, dirsByBasedir); | |||
| baseDirs.add(fromDir); | |||
| } else { // not a fileset | |||
| Iterator resources = rc.iterator(); | |||
| while (resources.hasNext()) { | |||
| FileResource fr = (FileResource) resources.next(); | |||
| if (!fr.isExists()) { | |||
| continue; | |||
| } | |||
| File baseDir = getKeyFile(fr.getBaseDir()); | |||
| add(baseDir, | |||
| baseDir == NULL_FILE_PLACEHOLDER | |||
| ? fr.getFile().getAbsolutePath() : fr.getName(), | |||
| fr.isDirectory() ? dirsByBasedir | |||
| : filesByBasedir); | |||
| baseDirs.add(baseDir); | |||
| } | |||
| } | |||
| Iterator iter = baseDirs.iterator(); | |||
| while (iter.hasNext()) { | |||
| File f = (File) iter.next(); | |||
| List files = (List) filesByBasedir.get(f); | |||
| List dirs = (List) dirsByBasedir.get(f); | |||
| String[] srcFiles = new String[0]; | |||
| if (files != null) { | |||
| srcFiles = (String[]) files.toArray(srcFiles); | |||
| } | |||
| String[] srcDirs = new String[0]; | |||
| if (dirs != null) { | |||
| srcDirs = (String[]) dirs.toArray(srcDirs); | |||
| } | |||
| scan(f == NULL_FILE_PLACEHOLDER ? null : f, destDir, | |||
| srcFiles, srcDirs); | |||
| } | |||
| } else { // not a File resource collection | |||
| throw new BuildException("Only FileSystem resources are" | |||
| + " supported."); | |||
| } | |||
| } | |||
| // do all the copy operations now... | |||
| try { | |||
| @@ -475,8 +522,8 @@ public class Copy extends Task { | |||
| file = savedFile; | |||
| destFile = savedDestFile; | |||
| destDir = savedDestDir; | |||
| if (savedFileSet != null) { | |||
| filesets.insertElementAt(savedFileSet, 0); | |||
| if (savedRc != null) { | |||
| rcs.insertElementAt(savedRc, 0); | |||
| } | |||
| fileCopyMap.clear(); | |||
| dirCopyMap.clear(); | |||
| @@ -495,9 +542,9 @@ public class Copy extends Task { | |||
| * @exception BuildException if an error occurs. | |||
| */ | |||
| protected void validateAttributes() throws BuildException { | |||
| if (file == null && filesets.size() == 0) { | |||
| if (file == null && rcs.size() == 0) { | |||
| throw new BuildException( | |||
| "Specify at least one source--a file or a fileset."); | |||
| "Specify at least one source--a file or a resource collection."); | |||
| } | |||
| if (destFile != null && destDir != null) { | |||
| throw new BuildException( | |||
| @@ -507,24 +554,26 @@ public class Copy extends Task { | |||
| throw new BuildException("One of tofile or todir must be set."); | |||
| } | |||
| if (file != null && file.isDirectory()) { | |||
| throw new BuildException("Use a fileset to copy directories."); | |||
| throw new BuildException("Use a resource collection to copy directories."); | |||
| } | |||
| if (destFile != null && filesets.size() > 0) { | |||
| if (filesets.size() > 1) { | |||
| if (destFile != null && rcs.size() > 0) { | |||
| if (rcs.size() > 1) { | |||
| throw new BuildException( | |||
| "Cannot concatenate multiple files into a single file."); | |||
| } else { | |||
| FileSet fs = (FileSet) filesets.elementAt(0); | |||
| DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
| String[] srcFiles = ds.getIncludedFiles(); | |||
| if (srcFiles.length == 0) { | |||
| ResourceCollection rc = (ResourceCollection) rcs.elementAt(0); | |||
| if (!rc.isFilesystemOnly()) { | |||
| throw new BuildException("Only FileSystem resources are" | |||
| + " supported."); | |||
| } | |||
| if (rc.size() == 0) { | |||
| throw new BuildException( | |||
| "Cannot perform operation from directory to file."); | |||
| } else if (srcFiles.length == 1) { | |||
| } else if (rc.size() == 1) { | |||
| FileResource r = (FileResource) rc.iterator().next(); | |||
| if (file == null) { | |||
| file = new File(ds.getBasedir(), srcFiles[0]); | |||
| filesets.removeElementAt(0); | |||
| file = r.getFile(); | |||
| rcs.removeElementAt(0); | |||
| } else { | |||
| throw new BuildException( | |||
| "Cannot concatenate multiple files into a single file."); | |||
| @@ -689,4 +738,37 @@ public class Copy extends Task { | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Adds the given strings to a list contained in the given map. | |||
| * The file is the key into the map. | |||
| */ | |||
| private static void add(File baseDir, String[] names, Map m) { | |||
| if (names != null) { | |||
| baseDir = getKeyFile(baseDir); | |||
| List l = (List) m.get(baseDir); | |||
| if (l == null) { | |||
| l = new ArrayList(names.length); | |||
| m.put(baseDir, l); | |||
| } | |||
| l.addAll(java.util.Arrays.asList(names)); | |||
| } | |||
| } | |||
| /** | |||
| * Adds the given string to a list contained in the given map. | |||
| * The file is the key into the map. | |||
| */ | |||
| private static void add(File baseDir, String name, Map m) { | |||
| if (name != null) { | |||
| add(baseDir, new String[] {name}, m); | |||
| } | |||
| } | |||
| /** | |||
| * Either returns its argument or a plaeholder if the argument is null. | |||
| */ | |||
| private static File getKeyFile(File f) { | |||
| return f == null ? NULL_FILE_PLACEHOLDER : f; | |||
| } | |||
| } | |||
| @@ -35,6 +35,7 @@ import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.types.AbstractFileSet; | |||
| import org.apache.tools.ant.types.FileSet; | |||
| import org.apache.tools.ant.types.PatternSet; | |||
| import org.apache.tools.ant.types.ResourceCollection; | |||
| import org.apache.tools.ant.types.selectors.FileSelector; | |||
| import org.apache.tools.ant.types.selectors.NoneSelector; | |||
| @@ -212,9 +213,11 @@ public class Sync extends Task { | |||
| // delete them. | |||
| for (int i = dirs.length - 1; i >= 0; --i) { | |||
| File f = new File(toDir, dirs[i]); | |||
| if (f.list().length < 1) { | |||
| log("Removing orphan directory: " + f, Project.MSG_DEBUG); | |||
| f.delete(); | |||
| ++removedCount[0]; | |||
| } | |||
| } | |||
| return removedCount; | |||
| } | |||
| @@ -310,7 +313,16 @@ public class Sync extends Task { | |||
| * @param set a fileset | |||
| */ | |||
| public void addFileset(FileSet set) { | |||
| myCopy.addFileset(set); | |||
| add(set); | |||
| } | |||
| /** | |||
| * Adds a collection of filesystem resources to copy. | |||
| * @param rc a resource collection | |||
| * @since Ant 1.7 | |||
| */ | |||
| public void add(ResourceCollection rc) { | |||
| myCopy.add(rc); | |||
| } | |||
| /** | |||
| @@ -121,6 +121,13 @@ public class CopyTest extends BuildFileTest { | |||
| assertTrue(file.exists()); | |||
| } | |||
| public void testSingleFilePath() { | |||
| executeTarget("test_single_file_path"); | |||
| File file = new File(getProjectDir(), | |||
| "copytest_single_file_path.tmp"); | |||
| assertTrue(file.exists()); | |||
| } | |||
| public void testTranscoding() throws IOException { | |||
| executeTarget("testTranscoding"); | |||
| File f1 = getProject().resolveFile("copy/expected/utf-8"); | |||
| @@ -148,7 +155,7 @@ public class CopyTest extends BuildFileTest { | |||
| assertTrue(getBuildException().getMessage().endsWith(" not found.")); | |||
| } | |||
| public void _testFileResourcePlain() { | |||
| public void testFileResourcePlain() { | |||
| executeTarget("testFileResourcePlain"); | |||
| File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt"); | |||
| File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt"); | |||
| @@ -168,23 +175,23 @@ public class CopyTest extends BuildFileTest { | |||
| assertTrue(file3.exists()); | |||
| } | |||
| public void _testFileResourceWithFilter() { | |||
| public void testFileResourceWithFilter() { | |||
| executeTarget("testFileResourceWithFilter"); | |||
| File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/fileNR.txt"); | |||
| assertTrue(file1.exists()); | |||
| try { | |||
| String file1Content = FILE_UTILS.readFully(new FileReader(file1)); | |||
| assertEquals(file1Content, "This is file 42"); | |||
| } catch (IOException e) { | |||
| // no-op: not a real business error | |||
| } | |||
| String file1Content = FILE_UTILS.readFully(new FileReader(file1)); | |||
| assertEquals("This is file 42", file1Content); | |||
| } catch (IOException e) { | |||
| // no-op: not a real business error | |||
| } | |||
| } | |||
| public void _testPathAsResource() { | |||
| public void testPathAsResource() { | |||
| executeTarget("testPathAsResource"); | |||
| File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt.bak"); | |||
| File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt.bak"); | |||
| File file3 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file3.txt.bak"); | |||
| File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt"); | |||
| File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt"); | |||
| File file3 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file3.txt"); | |||
| assertTrue(file1.exists()); | |||
| assertTrue(file2.exists()); | |||
| assertTrue(file3.exists()); | |||
| @@ -82,11 +82,28 @@ public class MoveTest extends BuildFileTest { | |||
| } | |||
| public void testCompleteDirectoryMove() throws IOException { | |||
| executeTarget("testCompleteDirectoryMove"); | |||
| testCompleteDirectoryMove("testCompleteDirectoryMove"); | |||
| } | |||
| public void testCompleteDirectoryMove2() throws IOException { | |||
| testCompleteDirectoryMove("testCompleteDirectoryMove2"); | |||
| } | |||
| private void testCompleteDirectoryMove(String target) throws IOException { | |||
| executeTarget(target); | |||
| assertTrue(getProject().resolveFile("E").exists()); | |||
| assertTrue(getProject().resolveFile("E/1").exists()); | |||
| assertTrue(!getProject().resolveFile("A/1").exists()); | |||
| // <path> swallows the basedir, it seems | |||
| //assertTrue(!getProject().resolveFile("A").exists()); | |||
| } | |||
| public void testPathElementMove() throws IOException { | |||
| executeTarget("testPathElementMove"); | |||
| assertTrue(getProject().resolveFile("E").exists()); | |||
| assertTrue(getProject().resolveFile("E/1").exists()); | |||
| assertTrue(!getProject().resolveFile("A/1").exists()); | |||
| assertTrue(!getProject().resolveFile("A").exists()); | |||
| assertTrue(getProject().resolveFile("A").exists()); | |||
| } | |||
| public void testMoveFileAndFileset() { | |||
| @@ -60,7 +60,15 @@ public class SyncTest extends BuildFileTest { | |||
| } | |||
| public void testCopyAndRemove() { | |||
| executeTarget("copyandremove"); | |||
| testCopyAndRemove("copyandremove"); | |||
| } | |||
| public void testCopyAndRemoveWithFileList() { | |||
| testCopyAndRemove("copyandremove-with-filelist"); | |||
| } | |||
| private void testCopyAndRemove(String target) { | |||
| executeTarget(target); | |||
| String d = getProject().getProperty("dest") + "/a/b/c/d"; | |||
| assertFileIsPresent(d); | |||
| String f = getProject().getProperty("dest") + "/e/f"; | |||