git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271671 13f79535-47bb-0310-9956-ffa450edef68master
@@ -0,0 +1,514 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2000-2002 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 "The Jakarta Project", "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 org.apache.tools.ant.Task; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.Project; | |||||
import org.apache.tools.ant.DirectoryScanner; | |||||
import org.apache.tools.ant.types.FileSet; | |||||
import org.apache.tools.ant.types.Mapper; | |||||
import org.apache.tools.ant.types.FilterChain; | |||||
import org.apache.tools.ant.types.FilterSet; | |||||
import org.apache.tools.ant.types.FilterSetCollection; | |||||
import org.apache.tools.ant.util.FileUtils; | |||||
import org.apache.tools.ant.util.FileNameMapper; | |||||
import org.apache.tools.ant.util.FlatFileNameMapper; | |||||
import org.apache.tools.ant.util.IdentityMapper; | |||||
import org.apache.tools.ant.util.SourceFileScanner; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.util.Vector; | |||||
import java.util.Hashtable; | |||||
import java.util.Enumeration; | |||||
/** | |||||
* A consolidated copy task. Copies a file or directory to a new file | |||||
* or directory. Files are only copied if the source file is newer | |||||
* than the destination file, or when the destination file does not | |||||
* exist. It is possible to explicitly overwrite existing files.</p> | |||||
* | |||||
* <p>This implementation is based on Arnout Kuiper's initial design | |||||
* document, the following mailing list discussions, and the | |||||
* copyfile/copydir tasks.</p> | |||||
* | |||||
* @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | |||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||||
* @author <A href="gholam@xtra.co.nz">Michael McCallum</A> | |||||
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||||
* | |||||
* @version $Revision$ | |||||
* | |||||
* @ant:task category="filesystem" | |||||
*/ | |||||
public class Copy extends Task { | |||||
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 boolean filtering = false; | |||||
protected boolean preserveLastModified = false; | |||||
protected boolean forceOverwrite = false; | |||||
protected boolean flatten = false; | |||||
protected int verbosity = Project.MSG_VERBOSE; | |||||
protected boolean includeEmpty = true; | |||||
protected Hashtable fileCopyMap = new Hashtable(); | |||||
protected Hashtable dirCopyMap = new Hashtable(); | |||||
protected Hashtable completeDirMap = new Hashtable(); | |||||
protected Mapper mapperElement = null; | |||||
private Vector filterChains = new Vector(); | |||||
private Vector filterSets = new Vector(); | |||||
private FileUtils fileUtils; | |||||
private String encoding = null; | |||||
public Copy() { | |||||
fileUtils = FileUtils.newFileUtils(); | |||||
} | |||||
protected FileUtils getFileUtils() {return fileUtils;} | |||||
/** | |||||
* Sets a single source file to copy. | |||||
*/ | |||||
public void setFile(File file) { | |||||
this.file = file; | |||||
} | |||||
/** | |||||
* Sets the destination file. | |||||
*/ | |||||
public void setTofile(File destFile) { | |||||
this.destFile = destFile; | |||||
} | |||||
/** | |||||
* Sets the destination directory. | |||||
*/ | |||||
public void setTodir(File destDir) { | |||||
this.destDir = destDir; | |||||
} | |||||
/** | |||||
* Create a nested filterchain | |||||
*/ | |||||
public FilterChain createFilterChain() { | |||||
FilterChain filterChain = new FilterChain(); | |||||
filterChains.addElement(filterChain); | |||||
return filterChain; | |||||
} | |||||
/** | |||||
* Create a nested filterset | |||||
*/ | |||||
public FilterSet createFilterSet() { | |||||
FilterSet filterSet = new FilterSet(); | |||||
filterSets.addElement(filterSet); | |||||
return filterSet; | |||||
} | |||||
/** | |||||
* Give the copied files the same last modified time as the original files. | |||||
* @deprecated setPreserveLastModified(String) has been deprecated and | |||||
* replaced with setPreserveLastModified(boolean) to | |||||
* consistently let the Introspection mechanism work. | |||||
*/ | |||||
public void setPreserveLastModified(String preserve) { | |||||
setPreserveLastModified(Project.toBoolean(preserve)); | |||||
} | |||||
/** | |||||
* Give the copied files the same last modified time as the original files. | |||||
*/ | |||||
public void setPreserveLastModified(boolean preserve) { | |||||
preserveLastModified = preserve; | |||||
} | |||||
/** | |||||
* Whether to give the copied files the same last modified time as | |||||
* the original files. | |||||
* | |||||
* @since 1.32, Ant 1.5 | |||||
*/ | |||||
public boolean getPreserveLastModified() { | |||||
return preserveLastModified; | |||||
} | |||||
/** | |||||
* Get the filtersets being applied to this operation. | |||||
* | |||||
* @return a vector of FilterSet objects | |||||
*/ | |||||
protected Vector getFilterSets() { | |||||
return filterSets; | |||||
} | |||||
/** | |||||
* Get the filterchains being applied to this operation. | |||||
* | |||||
* @return a vector of FilterChain objects | |||||
*/ | |||||
protected Vector getFilterChains() { | |||||
return filterChains; | |||||
} | |||||
/** | |||||
* Sets filtering. | |||||
*/ | |||||
public void setFiltering(boolean filtering) { | |||||
this.filtering = filtering; | |||||
} | |||||
/** | |||||
* Overwrite any existing destination file(s). | |||||
*/ | |||||
public void setOverwrite(boolean overwrite) { | |||||
this.forceOverwrite = overwrite; | |||||
} | |||||
/** | |||||
* When copying directory trees, the files can be "flattened" | |||||
* into a single directory. If there are multiple files with | |||||
* the same name in the source directory tree, only the first | |||||
* file will be copied into the "flattened" directory, unless | |||||
* the forceoverwrite attribute is true. | |||||
*/ | |||||
public void setFlatten(boolean flatten) { | |||||
this.flatten = flatten; | |||||
} | |||||
/** | |||||
* Used to force listing of all names of copied files. | |||||
*/ | |||||
public void setVerbose(boolean verbose) { | |||||
if (verbose) { | |||||
this.verbosity = Project.MSG_INFO; | |||||
} else { | |||||
this.verbosity = Project.MSG_VERBOSE; | |||||
} | |||||
} | |||||
/** | |||||
* Used to copy empty directories. | |||||
*/ | |||||
public void setIncludeEmptyDirs(boolean includeEmpty) { | |||||
this.includeEmpty = includeEmpty; | |||||
} | |||||
/** | |||||
* Adds a set of files (nested fileset attribute). | |||||
*/ | |||||
public void addFileset(FileSet set) { | |||||
filesets.addElement(set); | |||||
} | |||||
/** | |||||
* Defines the FileNameMapper to use (nested mapper element). | |||||
*/ | |||||
public Mapper createMapper() throws BuildException { | |||||
if (mapperElement != null) { | |||||
throw new BuildException("Cannot define more than one mapper", | |||||
location); | |||||
} | |||||
mapperElement = new Mapper(project); | |||||
return mapperElement; | |||||
} | |||||
/** | |||||
* Sets the character encoding | |||||
* | |||||
* @since 1.32, Ant 1.5 | |||||
*/ | |||||
public void setEncoding (String encoding) { | |||||
this.encoding = encoding; | |||||
} | |||||
/** | |||||
* @return the character encoding, <code>null</code> if not set. | |||||
* | |||||
* @since 1.32, Ant 1.5 | |||||
*/ | |||||
public String getEncoding() { | |||||
return encoding; | |||||
} | |||||
/** | |||||
* Performs the copy operation. | |||||
*/ | |||||
public void execute() throws BuildException { | |||||
// make sure we don't have an illegal set of options | |||||
validateAttributes(); | |||||
// deal with the single file | |||||
if (file != null) { | |||||
if (file.exists()) { | |||||
if (destFile == null) { | |||||
destFile = new File(destDir, file.getName()); | |||||
} | |||||
if (forceOverwrite || | |||||
(file.lastModified() > destFile.lastModified())) { | |||||
fileCopyMap.put(file.getAbsolutePath(), destFile.getAbsolutePath()); | |||||
} else { | |||||
log(file + " omitted as " + destFile + " is up to date.", | |||||
Project.MSG_VERBOSE); | |||||
} | |||||
} else { | |||||
String message = "Could not find file " | |||||
+ file.getAbsolutePath() + " to copy."; | |||||
log(message); | |||||
throw new BuildException(message); | |||||
} | |||||
} | |||||
// deal with the filesets | |||||
for (int i=0; i<filesets.size(); i++) { | |||||
FileSet fs = (FileSet) filesets.elementAt(i); | |||||
DirectoryScanner ds = fs.getDirectoryScanner(project); | |||||
File fromDir = fs.getDir(project); | |||||
String[] srcFiles = ds.getIncludedFiles(); | |||||
String[] srcDirs = ds.getIncludedDirectories(); | |||||
boolean isEverythingIncluded = ds.isEverythingIncluded(); | |||||
if (isEverythingIncluded | |||||
&& !flatten && mapperElement == null) { | |||||
completeDirMap.put(fromDir, destDir); | |||||
} | |||||
scan(fromDir, destDir, srcFiles, srcDirs); | |||||
} | |||||
// do all the copy operations now... | |||||
doFileOperations(); | |||||
// clean up destDir again - so this instance can be used a second | |||||
// time without throwing an exception | |||||
if (destFile != null) { | |||||
destDir = null; | |||||
} | |||||
fileCopyMap.clear(); | |||||
dirCopyMap.clear(); | |||||
completeDirMap.clear(); | |||||
} | |||||
//************************************************************************ | |||||
// protected and private methods | |||||
//************************************************************************ | |||||
/** | |||||
* Ensure we have a consistent and legal set of attributes, and set | |||||
* any internal flags necessary based on different combinations | |||||
* of attributes. | |||||
*/ | |||||
protected void validateAttributes() throws BuildException { | |||||
if (file == null && filesets.size() == 0) { | |||||
throw new BuildException("Specify at least one source - a file or a fileset."); | |||||
} | |||||
if (destFile != null && destDir != null) { | |||||
throw new BuildException("Only one of tofile and todir may be set."); | |||||
} | |||||
if (destFile == null && destDir == null) { | |||||
throw new BuildException("One of tofile or todir must be set."); | |||||
} | |||||
if (file != null && file.exists() && file.isDirectory()) { | |||||
throw new BuildException("Use a fileset to copy directories."); | |||||
} | |||||
if (destFile != null && filesets.size() > 0) { | |||||
if (filesets.size() > 1) { | |||||
throw new BuildException( | |||||
"Cannot concatenate multiple files into a single file."); | |||||
} else { | |||||
FileSet fs = (FileSet) filesets.elementAt(0); | |||||
DirectoryScanner ds = fs.getDirectoryScanner(project); | |||||
String[] srcFiles = ds.getIncludedFiles(); | |||||
if (srcFiles.length > 0) { | |||||
if (file == null) { | |||||
file = new File(ds.getBasedir(), srcFiles[0]); | |||||
filesets.removeElementAt(0); | |||||
} else { | |||||
throw new BuildException( | |||||
"Cannot concatenate multiple files into a single file."); | |||||
} | |||||
} else { | |||||
throw new BuildException( | |||||
"Cannot perform operation from directory to file."); | |||||
} | |||||
} | |||||
} | |||||
if (destFile != null) { | |||||
destDir = new File(destFile.getParent()); // be 1.1 friendly | |||||
} | |||||
} | |||||
/** | |||||
* Compares source files to destination files to see if they should be | |||||
* copied. | |||||
*/ | |||||
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(); | |||||
} | |||||
buildMap(fromDir, toDir, files, mapper, fileCopyMap); | |||||
if (includeEmpty) { | |||||
buildMap(fromDir, toDir, dirs, mapper, dirCopyMap); | |||||
} | |||||
} | |||||
protected void buildMap(File fromDir, File toDir, String[] names, | |||||
FileNameMapper mapper, Hashtable map) { | |||||
String[] toCopy = null; | |||||
if (forceOverwrite) { | |||||
Vector v = new Vector(); | |||||
for (int i=0; i<names.length; i++) { | |||||
if (mapper.mapFileName(names[i]) != null) { | |||||
v.addElement(names[i]); | |||||
} | |||||
} | |||||
toCopy = new String[v.size()]; | |||||
v.copyInto(toCopy); | |||||
} else { | |||||
SourceFileScanner ds = new SourceFileScanner(this); | |||||
toCopy = ds.restrict(names, fromDir, toDir, mapper); | |||||
} | |||||
for (int i = 0; i < toCopy.length; i++) { | |||||
File src = new File(fromDir, toCopy[i]); | |||||
File dest = new File(toDir, mapper.mapFileName(toCopy[i])[0]); | |||||
map.put( src.getAbsolutePath(), dest.getAbsolutePath() ); | |||||
} | |||||
} | |||||
/** | |||||
* Actually does the file (and possibly empty directory) copies. | |||||
* This is a good method for subclasses to override. | |||||
*/ | |||||
protected void doFileOperations() { | |||||
if (fileCopyMap.size() > 0) { | |||||
log("Copying " + fileCopyMap.size() + | |||||
" file" + (fileCopyMap.size() == 1 ? "" : "s") + | |||||
" to " + destDir.getAbsolutePath() ); | |||||
Enumeration e = fileCopyMap.keys(); | |||||
while (e.hasMoreElements()) { | |||||
String fromFile = (String) e.nextElement(); | |||||
String toFile = (String) fileCopyMap.get(fromFile); | |||||
if( fromFile.equals( toFile ) ) { | |||||
log("Skipping self-copy of " + fromFile, verbosity); | |||||
continue; | |||||
} | |||||
try { | |||||
log("Copying " + fromFile + " to " + toFile, verbosity); | |||||
FilterSetCollection executionFilters = new FilterSetCollection(); | |||||
if (filtering) { | |||||
executionFilters.addFilterSet(project.getGlobalFilterSet()); | |||||
} | |||||
for (Enumeration filterEnum = filterSets.elements(); filterEnum.hasMoreElements();) { | |||||
executionFilters.addFilterSet((FilterSet)filterEnum.nextElement()); | |||||
} | |||||
fileUtils.copyFile(fromFile, toFile, executionFilters, filterChains, | |||||
forceOverwrite, preserveLastModified, | |||||
encoding, project); | |||||
} catch (IOException ioe) { | |||||
String msg = "Failed to copy " + fromFile + " to " + toFile | |||||
+ " due to " + ioe.getMessage(); | |||||
throw new BuildException(msg, ioe, location); | |||||
} | |||||
} | |||||
} | |||||
if (includeEmpty) { | |||||
Enumeration e = dirCopyMap.elements(); | |||||
int count = 0; | |||||
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++; | |||||
} | |||||
} | |||||
} | |||||
if (count > 0) { | |||||
log("Copied " + count + | |||||
" empty director" + | |||||
(count==1?"y":"ies") + | |||||
" to " + destDir.getAbsolutePath()); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,312 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2000-2002 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 "The Jakarta Project", "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 org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.Project; | |||||
import org.apache.tools.ant.types.FilterSetCollection; | |||||
import org.apache.tools.ant.types.FilterSet; | |||||
import org.apache.tools.ant.types.FileSet; | |||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.util.Enumeration; | |||||
import java.util.Vector; | |||||
/** | |||||
* Moves a file or directory to a new file or directory. By default, | |||||
* the destination is overwriten when existing. When overwrite 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>Source files and directories are only deleted when the file or | |||||
* directory has been copied to the destination successfully. Filtering | |||||
* also works.</p> | |||||
* | |||||
* <p>This implementation is based on Arnout Kuiper's initial design | |||||
* document, the following mailing list discussions, and the | |||||
* copyfile/copydir tasks.</p> | |||||
* | |||||
* @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | |||||
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||||
* @version $Revision$ | |||||
* | |||||
* @ant:task category="filesystem" | |||||
*/ | |||||
public class Move extends Copy { | |||||
private Vector filterSets = null; | |||||
private Vector filterChains = null; | |||||
public Move() { | |||||
super(); | |||||
forceOverwrite = true; | |||||
} | |||||
//************************************************************************ | |||||
// protected and private methods | |||||
//************************************************************************ | |||||
protected void doFileOperations() { | |||||
filterSets = getFilterSets(); | |||||
filterChains = getFilterChains(); | |||||
//Attempt complete directory renames, if any, first. | |||||
if (completeDirMap.size() > 0) { | |||||
Enumeration e = completeDirMap.keys(); | |||||
while (e.hasMoreElements()) { | |||||
File fromDir = (File) e.nextElement(); | |||||
File toDir = (File) completeDirMap.get(fromDir); | |||||
try { | |||||
log("Attempting to rename dir: " + fromDir + | |||||
" to " + toDir, verbosity); | |||||
renameFile(fromDir, toDir, filtering, forceOverwrite); | |||||
} catch (IOException ioe) { | |||||
String msg = "Failed to rename dir " + fromDir | |||||
+ " to " + toDir | |||||
+ " due to " + ioe.getMessage(); | |||||
throw new BuildException(msg, ioe, location); | |||||
} | |||||
} | |||||
} | |||||
if (fileCopyMap.size() > 0) { // files to move | |||||
log("Moving " + fileCopyMap.size() + " files to " + | |||||
destDir.getAbsolutePath() ); | |||||
Enumeration e = fileCopyMap.keys(); | |||||
while (e.hasMoreElements()) { | |||||
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); | |||||
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, location); | |||||
} | |||||
if (!moved) { | |||||
try { | |||||
log("Moving " + fromFile + " to " + toFile, verbosity); | |||||
FilterSetCollection executionFilters = new FilterSetCollection(); | |||||
if (filtering) { | |||||
executionFilters.addFilterSet(project.getGlobalFilterSet()); | |||||
} | |||||
for (Enumeration filterEnum = getFilterSets().elements(); filterEnum.hasMoreElements();) { | |||||
executionFilters.addFilterSet((FilterSet)filterEnum.nextElement()); | |||||
} | |||||
getFileUtils().copyFile(f, d, executionFilters, filterChains, | |||||
forceOverwrite, | |||||
getPreserveLastModified(), | |||||
getEncoding(), project); | |||||
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, location); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (includeEmpty) { | |||||
Enumeration e = dirCopyMap.elements(); | |||||
int count = 0; | |||||
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++; | |||||
} | |||||
} | |||||
} | |||||
if (count > 0) { | |||||
log("Moved " + count + " empty directories to " + destDir.getAbsolutePath()); | |||||
} | |||||
} | |||||
if (filesets.size() > 0) { | |||||
Enumeration e = filesets.elements(); | |||||
while (e.hasMoreElements()) { | |||||
FileSet fs = (FileSet)e.nextElement(); | |||||
File dir = fs.getDir(project); | |||||
if (okToDelete(dir)) { | |||||
deleteDir(dir); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Its only ok to delete a directory tree if there are | |||||
* no files in it. | |||||
*/ | |||||
protected boolean okToDelete(File d) { | |||||
String[] list = d.list(); | |||||
if (list == null) { | |||||
return false; | |||||
} // maybe io error? | |||||
for (int i = 0; i < list.length; i++) { | |||||
String s = list[i]; | |||||
File f = new File(d, s); | |||||
if (f.isDirectory()) { | |||||
if (!okToDelete(f)) { | |||||
return false; | |||||
} | |||||
} else { | |||||
return false; // found a file | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Go and delete the directory tree. | |||||
*/ | |||||
protected void deleteDir(File d) { | |||||
String[] list = d.list(); | |||||
if (list == null) { | |||||
return; | |||||
} // on an io error list() can return null | |||||
for (int i = 0; i < list.length; i++) { | |||||
String s = list[i]; | |||||
File f = new File(d, s); | |||||
if (f.isDirectory()) { | |||||
deleteDir(f); | |||||
} else { | |||||
throw new BuildException("UNEXPECTED ERROR - The file " + f.getAbsolutePath() + " should not exist!"); | |||||
} | |||||
} | |||||
log("Deleting directory " + d.getAbsolutePath(), verbosity); | |||||
if (!d.delete()) { | |||||
throw new BuildException("Unable to delete directory " + d.getAbsolutePath()); | |||||
} | |||||
} | |||||
/** | |||||
* Attempts to rename a file from a source to a destination. | |||||
* If overwrite is set to true, this method overwrites existing file | |||||
* even if the destination file is newer. Otherwise, the source file is | |||||
* renamed only if the destination file is older than it. | |||||
* Method then checks if token filtering is used. If it is, this method | |||||
* returns false assuming it is the responsibility to the copyFile method. | |||||
* | |||||
* @throws IOException | |||||
*/ | |||||
protected boolean renameFile(File sourceFile, File destFile, | |||||
boolean filtering, boolean overwrite) | |||||
throws IOException, BuildException { | |||||
boolean renamed = true; | |||||
if ((filterSets != null && filterSets.size() > 0) || | |||||
(filterChains != null && filterChains.size() > 0)) { | |||||
renamed = false; | |||||
} else { | |||||
if (!filtering) { | |||||
// ensure that parent dir of dest file exists! | |||||
// not using getParentFile method to stay 1.1 compat | |||||
String parentPath = destFile.getParent(); | |||||
if (parentPath != null) { | |||||
File parent = new File(parentPath); | |||||
if (!parent.exists()) { | |||||
parent.mkdirs(); | |||||
} | |||||
} | |||||
if (destFile.exists()) { | |||||
if (!destFile.delete()) { | |||||
throw new BuildException("Unable to remove existing file " | |||||
+ destFile); | |||||
} | |||||
} | |||||
renamed = sourceFile.renameTo(destFile); | |||||
} else { | |||||
renamed = false; | |||||
} | |||||
} | |||||
return renamed; | |||||
} | |||||
} |
@@ -73,9 +73,11 @@ import java.text.DecimalFormat; | |||||
import java.util.Random; | import java.util.Random; | ||||
import java.util.Stack; | import java.util.Stack; | ||||
import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
import java.util.Vector; | |||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.filters.util.ChainReaderHelper; | |||||
import org.apache.tools.ant.types.FilterSetCollection; | import org.apache.tools.ant.types.FilterSetCollection; | ||||
/** | /** | ||||
@@ -87,6 +89,7 @@ import org.apache.tools.ant.types.FilterSetCollection; | |||||
* @author duncan@x180.com | * @author duncan@x180.com | ||||
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | ||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | ||||
* @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||||
* | * | ||||
* @version $Revision$ | * @version $Revision$ | ||||
*/ | */ | ||||
@@ -178,6 +181,28 @@ public class FileUtils { | |||||
overwrite, preserveLastModified, encoding); | overwrite, preserveLastModified, encoding); | ||||
} | } | ||||
/** | |||||
* Convienence method to copy a file from a source to a | |||||
* destination specifying if token filtering must be used, if | |||||
* filter chains must be used, if source files may overwrite | |||||
* newer destination files and the last modified time of | |||||
* <code>destFile</code> file should be made equal | |||||
* to the last modified time of <code>sourceFile</code>. | |||||
* | |||||
* @throws IOException | |||||
* | |||||
* @since 1.15, Ant 1.5 | |||||
*/ | |||||
public void copyFile(String sourceFile, String destFile, | |||||
FilterSetCollection filters, Vector filterChains, | |||||
boolean overwrite, boolean preserveLastModified, | |||||
String encoding, Project project) | |||||
throws IOException { | |||||
copyFile(new File(sourceFile), new File(destFile), filters, | |||||
filterChains, overwrite, preserveLastModified, | |||||
encoding, project); | |||||
} | |||||
/** | /** | ||||
* Convienence method to copy a file from a source to a destination. | * Convienence method to copy a file from a source to a destination. | ||||
* No filtering is performed. | * No filtering is performed. | ||||
@@ -243,6 +268,27 @@ public class FileUtils { | |||||
FilterSetCollection filters, boolean overwrite, | FilterSetCollection filters, boolean overwrite, | ||||
boolean preserveLastModified, String encoding) | boolean preserveLastModified, String encoding) | ||||
throws IOException { | throws IOException { | ||||
copyFile(sourceFile, destFile, filters, null, overwrite, | |||||
preserveLastModified, encoding, null); | |||||
} | |||||
/** | |||||
* Convienence method to copy a file from a source to a | |||||
* destination specifying if token filtering must be used, if | |||||
* filter chains must be used, if source files may overwrite | |||||
* newer destination files and the last modified time of | |||||
* <code>destFile</code> file should be made equal | |||||
* to the last modified time of <code>sourceFile</code>. | |||||
* | |||||
* @throws IOException | |||||
* | |||||
* @since 1.15, Ant 1.5 | |||||
*/ | |||||
public void copyFile(File sourceFile, File destFile, | |||||
FilterSetCollection filters, Vector filterChains, | |||||
boolean overwrite, boolean preserveLastModified, | |||||
String encoding, Project project) | |||||
throws IOException { | |||||
if (overwrite || !destFile.exists() || | if (overwrite || !destFile.exists() || | ||||
destFile.lastModified() < sourceFile.lastModified()) { | destFile.lastModified() < sourceFile.lastModified()) { | ||||
@@ -258,7 +304,12 @@ public class FileUtils { | |||||
parent.mkdirs(); | parent.mkdirs(); | ||||
} | } | ||||
if (filters != null && filters.hasFilters()) { | |||||
final boolean filterSetsAvailable = (filters != null | |||||
&& filters.hasFilters()); | |||||
final boolean filterChainsAvailable = (filterChains != null | |||||
&& filterChains.size() > 0); | |||||
if (filterSetsAvailable || filterChainsAvailable) { | |||||
BufferedReader in = null; | BufferedReader in = null; | ||||
BufferedWriter out = null; | BufferedWriter out = null; | ||||
@@ -266,8 +317,20 @@ public class FileUtils { | |||||
in = new BufferedReader(new FileReader(sourceFile)); | in = new BufferedReader(new FileReader(sourceFile)); | ||||
out = new BufferedWriter(new FileWriter(destFile)); | out = new BufferedWriter(new FileWriter(destFile)); | ||||
} else { | } else { | ||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile), encoding)); | |||||
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destFile), encoding)); | |||||
in = new BufferedReader(new InputStreamReader( | |||||
new FileInputStream(sourceFile), encoding)); | |||||
out = new BufferedWriter(new OutputStreamWriter( | |||||
new FileOutputStream(destFile), encoding)); | |||||
} | |||||
if (filterChainsAvailable) { | |||||
ChainReaderHelper crh = new ChainReaderHelper(); | |||||
crh.setBufferSize(8192); | |||||
crh.setPrimaryReader(in); | |||||
crh.setFilterChains(filterChains); | |||||
crh.setProject(project); | |||||
Reader rdr = crh.getAssembledReader(); | |||||
in = new BufferedReader(rdr); | |||||
} | } | ||||
int length; | int length; | ||||
@@ -277,7 +340,11 @@ public class FileUtils { | |||||
if (line.length() == 0) { | if (line.length() == 0) { | ||||
out.newLine(); | out.newLine(); | ||||
} else { | } else { | ||||
newline = filters.replaceTokens(line); | |||||
if (filterSetsAvailable) { | |||||
newline = filters.replaceTokens(line); | |||||
} else { | |||||
newline = line; | |||||
} | |||||
out.write(newline); | out.write(newline); | ||||
out.newLine(); | out.newLine(); | ||||
} | } | ||||