@@ -39,10 +39,12 @@ 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.ResourceCollection;
import org.apache.tools.ant.types.ResourceFactory;
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;
import org.apache.tools.ant.util.ResourceUtils;
import org.apache.tools.ant.util.SourceFileScanner;
import org.apache.tools.ant.util.FlatFileNameMapper;
@@ -435,76 +437,94 @@ public class Copy extends Task {
HashMap filesByBasedir = new HashMap();
HashMap dirsByBasedir = new HashMap();
HashSet baseDirs = new HashSet();
ArrayList nonFileResources = new ArrayList();
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;
}
// Step (1) - beware of the ZipFileSet
if (rc instanceof FileSet && rc.isFilesystemOnly()) {
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());
}
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 or contains non-file resources
if (!rc.isFilesystemOnly() && !supportsNonFileResources()) {
throw new BuildException(
"Only FileSystem resources are supported.");
}
String[] srcFiles = ds.getIncludedFiles();
String[] srcDirs = ds.getIncludedDirectories();
if (!flatten && mapperElement == null
&& ds.isEverythingIncluded() && !fs.hasPatterns()) {
completeDirMap.put(fromDir, destDir);
Iterator resources = rc.iterator ();
while (resources.hasNext()) {
Resource r = (Resource) resources.next();
if (!r.isExist s()) {
continue ;
}
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 = NULL_FILE_PLACEHOLDER;
String name = r.getName();
if (r instanceof FileResource) {
FileResource fr = (FileResource) r;
baseDir = getKeyFile(fr.getBaseDir());
if (fr.getBaseDir() == null) {
name = fr.getFile().getAbsolutePath();
}
File baseDir = getKeyFile(fr.getBaseDir());
add(baseDir, baseDir == NULL_FILE_PLACEHOLDER
? fr.getFile().getAbsolutePath() : fr.getName(),
fr.isDirectory() ? dirsByBasedir
: filesByBasedir);
}
// copying of dirs is trivial and can be done
// for non-file resources as well as for real
// files.
if (r.isDirectory() || r instanceof FileResource) {
add(baseDir, name,
r.isDirectory() ? dirsByBasedir
: filesByBasedir);
baseDirs.add(baseDir);
} else { // a not-directory file resource
// needs special treatment
nonFileResources.add(r);
}
}
}
}
Iterator iter = baseDirs.iterator();
while (iter.hasNext()) {
File f = (File) iter.next();
List files = (List) filesByBasedir.get(f);
List dirs = (List) dirsByBasedir.get(f);
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.");
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);
}
// do all the copy operations now...
try {
doFileOperations();
@@ -515,6 +535,22 @@ public class Copy extends Task {
throw e;
}
}
if (nonFileResources.size() > 0) {
Resource[] nonFiles =
(Resource[]) nonFileResources.toArray(new Resource[0]);
// restrict to out-of-date resources
Map map = scan(nonFiles, destDir);
try {
doResourceOperations(map);
} catch (BuildException e) {
if (!failonerror) {
log("Warning: " + e.getMessage(), Project.MSG_ERR);
} else {
throw e;
}
}
}
} finally {
// clean up again, so this instance can be used a second
// time
@@ -563,7 +599,8 @@ public class Copy extends Task {
ResourceCollection rc = (ResourceCollection) rcs.elementAt(0);
if (!rc.isFilesystemOnly()) {
throw new BuildException("Only FileSystem resources are"
+ " supported.");
+ " supported when concatenating"
+ " files.");
}
if (rc.size() == 0) {
throw new BuildException(
@@ -599,14 +636,7 @@ public class Copy extends Task {
*/
protected void scan(File fromDir, File toDir, String[] files,
String[] dirs) {
FileNameMapper mapper = null;
if (mapperElement != null) {
mapper = mapperElement.getImplementation();
} else if (flatten) {
mapper = new FlatFileNameMapper();
} else {
mapper = new IdentityMapper();
}
FileNameMapper mapper = getMapper();
buildMap(fromDir, toDir, files, mapper, fileCopyMap);
if (includeEmpty) {
@@ -614,6 +644,22 @@ public class Copy extends Task {
}
}
/**
* Compares source resources to destination files to see if they
* should be copied.
*
* @param fromResources The source resources.
* @param toDir The destination directory.
*
* @return a Map with the out-of-date resources as keys and an
* array of target file names as values.
*
* @since Ant 1.7
*/
protected Map scan(Resource[] fromResources, File toDir) {
return buildMap(fromResources, toDir, getMapper());
}
/**
* Add to a map of files/directories to copy.
*
@@ -641,7 +687,6 @@ public class Copy extends Task {
}
for (int i = 0; i < toCopy.length; i++) {
File src = new File(fromDir, toCopy[i]);
String[] mappedFiles = mapper.mapFileName(toCopy[i]);
if (!enableMultipleMappings) {
@@ -657,6 +702,56 @@ public class Copy extends Task {
}
}
/**
* Create a map of resources to copy.
*
* @param fromResources The source resources.
* @param toDir the destination directory.
* @param mapper a <code>FileNameMapper</code> value.
* @return a map of source resource to array of destination files.
* @since Ant 1.7
*/
protected Map buildMap(Resource[] fromResources, final File toDir,
FileNameMapper mapper) {
HashMap map = new HashMap();
Resource[] toCopy = null;
if (forceOverwrite) {
Vector v = new Vector();
for (int i = 0; i < fromResources.length; i++) {
if (mapper.mapFileName(fromResources[i].getName()) != null) {
v.addElement(fromResources[i]);
}
}
toCopy = new Resource[v.size()];
v.copyInto(toCopy);
} else {
toCopy =
ResourceUtils.selectOutOfDateSources(this, fromResources,
mapper,
new ResourceFactory() {
public Resource getResource(String name) {
return new FileResource(toDir, name);
}
},
granularity);
}
for (int i = 0; i < toCopy.length; i++) {
String[] mappedFiles = mapper.mapFileName(toCopy[i].getName());
if (!enableMultipleMappings) {
map.put(toCopy[i],
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(toCopy[i], mappedFiles);
}
}
return map;
}
/**
* Actually does the file (and possibly empty directory) copies.
* This is a good method for subclasses to override.
@@ -738,6 +833,84 @@ public class Copy extends Task {
}
}
/**
* Actually does the resource copies.
* This is a good method for subclasses to override.
* @param map a map of source resource to array of destination files.
* @since Ant 1.7
*/
protected void doResourceOperations(Map map) {
if (map.size() > 0) {
log("Copying " + map.size()
+ " resource" + (map.size() == 1 ? "" : "s")
+ " to " + destDir.getAbsolutePath());
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Resource fromResource = (Resource) iter.next();
String[] toFiles = (String[]) map.get(fromResource);
for (int i = 0; i < toFiles.length; i++) {
String toFile = toFiles[i];
try {
log("Copying " + fromResource + " 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());
}
ResourceUtils.copyResource(fromResource,
new FileResource(destDir,
toFile),
executionFilters,
filterChains,
forceOverwrite,
preserveLastModified,
inputEncoding,
outputEncoding,
getProject());
} catch (IOException ioe) {
String msg = "Failed to copy " + fromResource
+ " 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());
}
}
}
}
}
/**
* Whether this task can deal with non-file resources.
*
* <p><copy> can while <move> can't since we don't
* know how to remove non-file resources.</p>
*
* <p>This implementation returns true only if this task is
* <copy>. Any subclass of this class that also wants to
* support non-file resources needs to override this method. We
* need to do so for backwards compatibility reasons since we
* can't expect subclasses to support resources.</p>
*
* @since Ant 1.7
*/
protected boolean supportsNonFileResources() {
return getClass().equals(Copy.class);
}
/**
* Adds the given strings to a list contained in the given map.
* The file is the key into the map.
@@ -770,4 +943,21 @@ public class Copy extends Task {
private static File getKeyFile(File f) {
return f == null ? NULL_FILE_PLACEHOLDER : f;
}
/**
* returns the mapper to use based on nested elements or the
* flatten attribute.
*/
private FileNameMapper getMapper() {
FileNameMapper mapper = null;
if (mapperElement != null) {
mapper = mapperElement.getImplementation();
} else if (flatten) {
mapper = new FlatFileNameMapper();
} else {
mapper = new IdentityMapper();
}
return mapper;
}
}