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"; | |||