git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271243 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1,552 +0,0 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.file; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Iterator; | |||||
| import org.apache.avalon.excalibur.io.FileUtil; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.types.DirectoryScanner; | |||||
| import org.apache.tools.ant.types.FileSet; | |||||
| import org.apache.tools.ant.types.FilterSet; | |||||
| import org.apache.tools.ant.types.FilterSetCollection; | |||||
| import org.apache.tools.ant.types.ScannerUtil; | |||||
| import org.apache.tools.ant.types.SourceFileScanner; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.apache.tools.ant.util.mappers.FileNameMapper; | |||||
| import org.apache.tools.ant.util.mappers.FlatFileNameMapper; | |||||
| import org.apache.tools.ant.util.mappers.IdentityMapper; | |||||
| import org.apache.tools.ant.util.mappers.Mapper; | |||||
| /** | |||||
| * 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> | |||||
| */ | |||||
| public class Copy | |||||
| extends Task | |||||
| { | |||||
| private File m_file;// the source file | |||||
| private File m_destFile;// the destination file | |||||
| private File m_destDir;// the destination directory | |||||
| private ArrayList m_filesets = new ArrayList(); | |||||
| private boolean m_filtering; | |||||
| private boolean m_preserveLastModified; | |||||
| private boolean m_overwrite; | |||||
| private boolean m_flatten; | |||||
| private boolean m_includeEmpty = true; | |||||
| private Hashtable m_fileCopyMap = new Hashtable(); | |||||
| private Hashtable m_dirCopyMap = new Hashtable(); | |||||
| private Hashtable m_completeDirMap = new Hashtable(); | |||||
| private Mapper m_mapperElement; | |||||
| private ArrayList m_filterSets = new ArrayList(); | |||||
| /** | |||||
| * Sets a single source file to copy. | |||||
| * | |||||
| * @param file The new File value | |||||
| */ | |||||
| public void setFile( final File file ) | |||||
| { | |||||
| m_file = file; | |||||
| } | |||||
| /** | |||||
| * Sets filtering. | |||||
| * | |||||
| * @param filtering The new Filtering value | |||||
| */ | |||||
| public void setFiltering( final boolean filtering ) | |||||
| { | |||||
| m_filtering = filtering; | |||||
| } | |||||
| /** | |||||
| * 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. | |||||
| * | |||||
| * @param flatten The new Flatten value | |||||
| */ | |||||
| public void setFlatten( final boolean flatten ) | |||||
| { | |||||
| m_flatten = flatten; | |||||
| } | |||||
| /** | |||||
| * Used to copy empty directories. | |||||
| * | |||||
| * @param includeEmpty The new IncludeEmptyDirs value | |||||
| */ | |||||
| public void setIncludeEmptyDirs( final boolean includeEmpty ) | |||||
| { | |||||
| m_includeEmpty = includeEmpty; | |||||
| } | |||||
| /** | |||||
| * Overwrite any existing destination file(s). | |||||
| * | |||||
| * @param overwrite The new Overwrite value | |||||
| */ | |||||
| public void setOverwrite( final boolean overwrite ) | |||||
| { | |||||
| m_overwrite = overwrite; | |||||
| } | |||||
| /** | |||||
| * Give the copied files the same last modified time as the original files. | |||||
| * | |||||
| * @param preserve The new PreserveLastModified value | |||||
| */ | |||||
| public void setPreserveLastModified( final boolean preserve ) | |||||
| { | |||||
| m_preserveLastModified = preserve; | |||||
| } | |||||
| /** | |||||
| * Sets the destination directory. | |||||
| * | |||||
| * @param destDir The new Todir value | |||||
| */ | |||||
| public void setTodir( final File destDir ) | |||||
| { | |||||
| m_destDir = destDir; | |||||
| } | |||||
| /** | |||||
| * Sets the destination file. | |||||
| * | |||||
| * @param destFile The new Tofile value | |||||
| */ | |||||
| public void setTofile( final File destFile ) | |||||
| { | |||||
| m_destFile = destFile; | |||||
| } | |||||
| /** | |||||
| * Adds a set of files (nested fileset attribute). | |||||
| * | |||||
| * @param set The feature to be added to the Fileset attribute | |||||
| */ | |||||
| public void addFileset( final FileSet set ) | |||||
| { | |||||
| m_filesets.add( set ); | |||||
| } | |||||
| /** | |||||
| * Create a nested filterset | |||||
| * | |||||
| * @return Description of the Returned Value | |||||
| */ | |||||
| public FilterSet createFilterSet() | |||||
| { | |||||
| final FilterSet filterSet = new FilterSet(); | |||||
| m_filterSets.add( filterSet ); | |||||
| return filterSet; | |||||
| } | |||||
| /** | |||||
| * Defines the FileNameMapper to use (nested mapper element). | |||||
| * | |||||
| * @return Description of the Returned Value | |||||
| * @exception TaskException Description of Exception | |||||
| */ | |||||
| public Mapper createMapper() | |||||
| throws TaskException | |||||
| { | |||||
| if( m_mapperElement != null ) | |||||
| { | |||||
| throw new TaskException( "Cannot define more than one mapper" ); | |||||
| } | |||||
| m_mapperElement = new Mapper(); | |||||
| return m_mapperElement; | |||||
| } | |||||
| /** | |||||
| * Performs the copy operation. | |||||
| * | |||||
| * @exception TaskException Description of Exception | |||||
| */ | |||||
| public void execute() | |||||
| throws TaskException | |||||
| { | |||||
| // make sure we don't have an illegal set of options | |||||
| validateAttributes(); | |||||
| // deal with the single file | |||||
| if( m_file != null ) | |||||
| { | |||||
| if( m_file.exists() ) | |||||
| { | |||||
| if( m_destFile == null ) | |||||
| { | |||||
| m_destFile = new File( m_destDir, m_file.getName() ); | |||||
| } | |||||
| if( m_overwrite || | |||||
| ( m_file.lastModified() > m_destFile.lastModified() ) ) | |||||
| { | |||||
| m_fileCopyMap.put( m_file.getAbsolutePath(), m_destFile.getAbsolutePath() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| getLogger().debug( m_file + " omitted as " + m_destFile + " is up to date." ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| String message = "Could not find file " | |||||
| + m_file.getAbsolutePath() + " to copy."; | |||||
| getLogger().info( message ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| } | |||||
| // deal with the filesets | |||||
| final int size = m_filesets.size(); | |||||
| for( int i = 0; i < size; i++ ) | |||||
| { | |||||
| final FileSet fileSet = (FileSet)m_filesets.get( i ); | |||||
| final DirectoryScanner scanner = ScannerUtil.getDirectoryScanner( fileSet ); | |||||
| final File fromDir = fileSet.getDir(); | |||||
| final String[] srcFiles = scanner.getIncludedFiles(); | |||||
| final String[] srcDirs = scanner.getIncludedDirectories(); | |||||
| final boolean isEverythingIncluded = scanner.isEverythingIncluded(); | |||||
| if( isEverythingIncluded && !m_flatten && null == m_mapperElement ) | |||||
| { | |||||
| m_completeDirMap.put( fromDir, m_destDir ); | |||||
| } | |||||
| scan( fromDir, m_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( null != m_destFile ) | |||||
| { | |||||
| m_destDir = null; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the filtersets being applied to this operation. | |||||
| * | |||||
| * @return a vector of FilterSet objects | |||||
| */ | |||||
| protected ArrayList getFilterSets() | |||||
| { | |||||
| return m_filterSets; | |||||
| } | |||||
| protected void buildMap( final File fromDir, | |||||
| final File toDir, | |||||
| final String[] names, | |||||
| final FileNameMapper mapper, | |||||
| final Hashtable map ) | |||||
| throws TaskException | |||||
| { | |||||
| final String[] toCopy = buildFilenameList( names, mapper, fromDir, toDir ); | |||||
| for( int i = 0; i < toCopy.length; i++ ) | |||||
| { | |||||
| final String destFilename = mapper.mapFileName( toCopy[ i ] )[ 0 ]; | |||||
| final File src = new File( fromDir, toCopy[ i ] ); | |||||
| final File dest = new File( toDir, destFilename ); | |||||
| map.put( src.getAbsolutePath(), dest.getAbsolutePath() ); | |||||
| } | |||||
| } | |||||
| private String[] buildFilenameList( final String[] names, | |||||
| final FileNameMapper mapper, | |||||
| final File fromDir, | |||||
| final File toDir ) | |||||
| throws TaskException | |||||
| { | |||||
| if( m_overwrite ) | |||||
| { | |||||
| final ArrayList list = new ArrayList( names.length ); | |||||
| for( int i = 0; i < names.length; i++ ) | |||||
| { | |||||
| final String name = names[ i ]; | |||||
| if( null != mapper.mapFileName( name ) ) | |||||
| { | |||||
| list.add( name ); | |||||
| } | |||||
| } | |||||
| return (String[])list.toArray( new String[ list.size() ] ); | |||||
| } | |||||
| else | |||||
| { | |||||
| final SourceFileScanner scanner = new SourceFileScanner(); | |||||
| setupLogger( scanner ); | |||||
| return scanner.restrict( names, fromDir, toDir, mapper ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Actually does the file (and possibly empty directory) copies. This is a | |||||
| * good method for subclasses to override. | |||||
| */ | |||||
| protected void doFileOperations() | |||||
| throws TaskException | |||||
| { | |||||
| if( m_fileCopyMap.size() > 0 ) | |||||
| { | |||||
| getLogger().info( "Copying " + m_fileCopyMap.size() + | |||||
| " file" + ( m_fileCopyMap.size() == 1 ? "" : "s" ) + | |||||
| " to " + m_destDir.getAbsolutePath() ); | |||||
| Enumeration e = m_fileCopyMap.keys(); | |||||
| while( e.hasMoreElements() ) | |||||
| { | |||||
| String fromFile = (String)e.nextElement(); | |||||
| String toFile = (String)m_fileCopyMap.get( fromFile ); | |||||
| if( fromFile.equals( toFile ) ) | |||||
| { | |||||
| getLogger().info( "Skipping self-copy of " + fromFile ); | |||||
| continue; | |||||
| } | |||||
| try | |||||
| { | |||||
| getLogger().info( "Copying " + fromFile + " to " + toFile ); | |||||
| final FilterSetCollection executionFilters = buildFilterSet(); | |||||
| final File src = new File( fromFile ); | |||||
| final File dest = new File( toFile ); | |||||
| if( m_overwrite ) | |||||
| { | |||||
| FileUtil.forceDelete( dest ); | |||||
| } | |||||
| FileUtils.copyFile( src, dest, executionFilters ); | |||||
| if( m_preserveLastModified ) | |||||
| { | |||||
| dest.setLastModified( src.lastModified() ); | |||||
| } | |||||
| } | |||||
| catch( final IOException ioe ) | |||||
| { | |||||
| final String msg = "Failed to copy " + fromFile + " to " + | |||||
| toFile + " due to " + ioe.getMessage(); | |||||
| throw new TaskException( msg, ioe ); | |||||
| } | |||||
| } | |||||
| } | |||||
| if( m_includeEmpty ) | |||||
| { | |||||
| Enumeration e = m_dirCopyMap.elements(); | |||||
| int count = 0; | |||||
| while( e.hasMoreElements() ) | |||||
| { | |||||
| File d = new File( (String)e.nextElement() ); | |||||
| if( !d.exists() ) | |||||
| { | |||||
| if( !d.mkdirs() ) | |||||
| { | |||||
| getLogger().error( "Unable to create directory " + d.getAbsolutePath() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| count++; | |||||
| } | |||||
| } | |||||
| } | |||||
| if( count > 0 ) | |||||
| { | |||||
| getLogger().info( "Copied " + count + | |||||
| " empty director" + | |||||
| ( count == 1 ? "y" : "ies" ) + | |||||
| " to " + m_destDir.getAbsolutePath() ); | |||||
| } | |||||
| } | |||||
| } | |||||
| protected final FilterSetCollection buildFilterSet() | |||||
| { | |||||
| final FilterSetCollection executionFilters = new FilterSetCollection(); | |||||
| if( m_filtering ) | |||||
| { | |||||
| executionFilters.addFilterSet( getProject().getGlobalFilterSet() ); | |||||
| } | |||||
| for( final Iterator filterEnum = m_filterSets.iterator(); filterEnum.hasNext(); ) | |||||
| { | |||||
| executionFilters.addFilterSet( (FilterSet)filterEnum.next() ); | |||||
| } | |||||
| return executionFilters; | |||||
| } | |||||
| /** | |||||
| * Compares source files to destination files to see if they should be | |||||
| * copied. | |||||
| */ | |||||
| protected void scan( File fromDir, File toDir, String[] files, String[] dirs ) | |||||
| throws TaskException | |||||
| { | |||||
| FileNameMapper mapper = null; | |||||
| if( m_mapperElement != null ) | |||||
| { | |||||
| mapper = m_mapperElement.getImplementation(); | |||||
| } | |||||
| else if( m_flatten ) | |||||
| { | |||||
| mapper = new FlatFileNameMapper(); | |||||
| } | |||||
| else | |||||
| { | |||||
| mapper = new IdentityMapper(); | |||||
| } | |||||
| buildMap( fromDir, toDir, files, mapper, m_fileCopyMap ); | |||||
| if( m_includeEmpty ) | |||||
| { | |||||
| buildMap( fromDir, toDir, dirs, mapper, m_dirCopyMap ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Ensure we have a consistent and legal set of attributes, and set any | |||||
| * internal flags necessary based on different combinations of attributes. | |||||
| * | |||||
| * @exception TaskException Description of Exception | |||||
| */ | |||||
| protected void validateAttributes() | |||||
| throws TaskException | |||||
| { | |||||
| if( m_file == null && m_filesets.size() == 0 ) | |||||
| { | |||||
| throw new TaskException( "Specify at least one source - a file or a fileset." ); | |||||
| } | |||||
| if( m_destFile != null && m_destDir != null ) | |||||
| { | |||||
| throw new TaskException( "Only one of tofile and todir may be set." ); | |||||
| } | |||||
| if( m_destFile == null && m_destDir == null ) | |||||
| { | |||||
| throw new TaskException( "One of tofile or todir must be set." ); | |||||
| } | |||||
| if( m_file != null && m_file.exists() && m_file.isDirectory() ) | |||||
| { | |||||
| throw new TaskException( "Use a fileset to copy directories." ); | |||||
| } | |||||
| if( m_destFile != null && m_filesets.size() > 0 ) | |||||
| { | |||||
| if( m_filesets.size() > 1 ) | |||||
| { | |||||
| throw new TaskException( | |||||
| "Cannot concatenate multiple files into a single file." ); | |||||
| } | |||||
| else | |||||
| { | |||||
| FileSet fs = (FileSet)m_filesets.get( 0 ); | |||||
| DirectoryScanner ds = ScannerUtil.getDirectoryScanner( fs ); | |||||
| String[] srcFiles = ds.getIncludedFiles(); | |||||
| if( srcFiles.length > 0 ) | |||||
| { | |||||
| if( m_file == null ) | |||||
| { | |||||
| m_file = new File( srcFiles[ 0 ] ); | |||||
| m_filesets.remove( 0 ); | |||||
| } | |||||
| else | |||||
| { | |||||
| throw new TaskException( | |||||
| "Cannot concatenate multiple files into a single file." ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| throw new TaskException( | |||||
| "Cannot perform operation from directory to file." ); | |||||
| } | |||||
| } | |||||
| } | |||||
| if( m_destFile != null ) | |||||
| { | |||||
| m_destDir = new File( m_destFile.getParent() );// be 1.1 friendly | |||||
| } | |||||
| } | |||||
| protected ArrayList getFilesets() | |||||
| { | |||||
| return m_filesets; | |||||
| } | |||||
| protected boolean isFiltering() | |||||
| { | |||||
| return m_filtering; | |||||
| } | |||||
| protected boolean isForceOverwrite() | |||||
| { | |||||
| return m_overwrite; | |||||
| } | |||||
| protected boolean isIncludeEmpty() | |||||
| { | |||||
| return m_includeEmpty; | |||||
| } | |||||
| protected Hashtable getFileCopyMap() | |||||
| { | |||||
| return m_fileCopyMap; | |||||
| } | |||||
| protected Hashtable getDirCopyMap() | |||||
| { | |||||
| return m_dirCopyMap; | |||||
| } | |||||
| protected Hashtable getCompleteDirMap() | |||||
| { | |||||
| return m_completeDirMap; | |||||
| } | |||||
| protected File getDestDir() | |||||
| { | |||||
| return m_destDir; | |||||
| } | |||||
| } | |||||
| @@ -1,552 +0,0 @@ | |||||
| /* | |||||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||||
| * | |||||
| * This software is published under the terms of the Apache Software License | |||||
| * version 1.1, a copy of which has been included with this distribution in | |||||
| * the LICENSE.txt file. | |||||
| */ | |||||
| package org.apache.tools.ant.taskdefs.file; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Iterator; | |||||
| import org.apache.avalon.excalibur.io.FileUtil; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.types.DirectoryScanner; | |||||
| import org.apache.tools.ant.types.FileSet; | |||||
| import org.apache.tools.ant.types.FilterSet; | |||||
| import org.apache.tools.ant.types.FilterSetCollection; | |||||
| import org.apache.tools.ant.types.ScannerUtil; | |||||
| import org.apache.tools.ant.types.SourceFileScanner; | |||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.apache.tools.ant.util.mappers.FileNameMapper; | |||||
| import org.apache.tools.ant.util.mappers.FlatFileNameMapper; | |||||
| import org.apache.tools.ant.util.mappers.IdentityMapper; | |||||
| import org.apache.tools.ant.util.mappers.Mapper; | |||||
| /** | |||||
| * 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> | |||||
| */ | |||||
| public class Copy | |||||
| extends Task | |||||
| { | |||||
| private File m_file;// the source file | |||||
| private File m_destFile;// the destination file | |||||
| private File m_destDir;// the destination directory | |||||
| private ArrayList m_filesets = new ArrayList(); | |||||
| private boolean m_filtering; | |||||
| private boolean m_preserveLastModified; | |||||
| private boolean m_overwrite; | |||||
| private boolean m_flatten; | |||||
| private boolean m_includeEmpty = true; | |||||
| private Hashtable m_fileCopyMap = new Hashtable(); | |||||
| private Hashtable m_dirCopyMap = new Hashtable(); | |||||
| private Hashtable m_completeDirMap = new Hashtable(); | |||||
| private Mapper m_mapperElement; | |||||
| private ArrayList m_filterSets = new ArrayList(); | |||||
| /** | |||||
| * Sets a single source file to copy. | |||||
| * | |||||
| * @param file The new File value | |||||
| */ | |||||
| public void setFile( final File file ) | |||||
| { | |||||
| m_file = file; | |||||
| } | |||||
| /** | |||||
| * Sets filtering. | |||||
| * | |||||
| * @param filtering The new Filtering value | |||||
| */ | |||||
| public void setFiltering( final boolean filtering ) | |||||
| { | |||||
| m_filtering = filtering; | |||||
| } | |||||
| /** | |||||
| * 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. | |||||
| * | |||||
| * @param flatten The new Flatten value | |||||
| */ | |||||
| public void setFlatten( final boolean flatten ) | |||||
| { | |||||
| m_flatten = flatten; | |||||
| } | |||||
| /** | |||||
| * Used to copy empty directories. | |||||
| * | |||||
| * @param includeEmpty The new IncludeEmptyDirs value | |||||
| */ | |||||
| public void setIncludeEmptyDirs( final boolean includeEmpty ) | |||||
| { | |||||
| m_includeEmpty = includeEmpty; | |||||
| } | |||||
| /** | |||||
| * Overwrite any existing destination file(s). | |||||
| * | |||||
| * @param overwrite The new Overwrite value | |||||
| */ | |||||
| public void setOverwrite( final boolean overwrite ) | |||||
| { | |||||
| m_overwrite = overwrite; | |||||
| } | |||||
| /** | |||||
| * Give the copied files the same last modified time as the original files. | |||||
| * | |||||
| * @param preserve The new PreserveLastModified value | |||||
| */ | |||||
| public void setPreserveLastModified( final boolean preserve ) | |||||
| { | |||||
| m_preserveLastModified = preserve; | |||||
| } | |||||
| /** | |||||
| * Sets the destination directory. | |||||
| * | |||||
| * @param destDir The new Todir value | |||||
| */ | |||||
| public void setTodir( final File destDir ) | |||||
| { | |||||
| m_destDir = destDir; | |||||
| } | |||||
| /** | |||||
| * Sets the destination file. | |||||
| * | |||||
| * @param destFile The new Tofile value | |||||
| */ | |||||
| public void setTofile( final File destFile ) | |||||
| { | |||||
| m_destFile = destFile; | |||||
| } | |||||
| /** | |||||
| * Adds a set of files (nested fileset attribute). | |||||
| * | |||||
| * @param set The feature to be added to the Fileset attribute | |||||
| */ | |||||
| public void addFileset( final FileSet set ) | |||||
| { | |||||
| m_filesets.add( set ); | |||||
| } | |||||
| /** | |||||
| * Create a nested filterset | |||||
| * | |||||
| * @return Description of the Returned Value | |||||
| */ | |||||
| public FilterSet createFilterSet() | |||||
| { | |||||
| final FilterSet filterSet = new FilterSet(); | |||||
| m_filterSets.add( filterSet ); | |||||
| return filterSet; | |||||
| } | |||||
| /** | |||||
| * Defines the FileNameMapper to use (nested mapper element). | |||||
| * | |||||
| * @return Description of the Returned Value | |||||
| * @exception TaskException Description of Exception | |||||
| */ | |||||
| public Mapper createMapper() | |||||
| throws TaskException | |||||
| { | |||||
| if( m_mapperElement != null ) | |||||
| { | |||||
| throw new TaskException( "Cannot define more than one mapper" ); | |||||
| } | |||||
| m_mapperElement = new Mapper(); | |||||
| return m_mapperElement; | |||||
| } | |||||
| /** | |||||
| * Performs the copy operation. | |||||
| * | |||||
| * @exception TaskException Description of Exception | |||||
| */ | |||||
| public void execute() | |||||
| throws TaskException | |||||
| { | |||||
| // make sure we don't have an illegal set of options | |||||
| validateAttributes(); | |||||
| // deal with the single file | |||||
| if( m_file != null ) | |||||
| { | |||||
| if( m_file.exists() ) | |||||
| { | |||||
| if( m_destFile == null ) | |||||
| { | |||||
| m_destFile = new File( m_destDir, m_file.getName() ); | |||||
| } | |||||
| if( m_overwrite || | |||||
| ( m_file.lastModified() > m_destFile.lastModified() ) ) | |||||
| { | |||||
| m_fileCopyMap.put( m_file.getAbsolutePath(), m_destFile.getAbsolutePath() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| getLogger().debug( m_file + " omitted as " + m_destFile + " is up to date." ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| String message = "Could not find file " | |||||
| + m_file.getAbsolutePath() + " to copy."; | |||||
| getLogger().info( message ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| } | |||||
| // deal with the filesets | |||||
| final int size = m_filesets.size(); | |||||
| for( int i = 0; i < size; i++ ) | |||||
| { | |||||
| final FileSet fileSet = (FileSet)m_filesets.get( i ); | |||||
| final DirectoryScanner scanner = ScannerUtil.getDirectoryScanner( fileSet ); | |||||
| final File fromDir = fileSet.getDir(); | |||||
| final String[] srcFiles = scanner.getIncludedFiles(); | |||||
| final String[] srcDirs = scanner.getIncludedDirectories(); | |||||
| final boolean isEverythingIncluded = scanner.isEverythingIncluded(); | |||||
| if( isEverythingIncluded && !m_flatten && null == m_mapperElement ) | |||||
| { | |||||
| m_completeDirMap.put( fromDir, m_destDir ); | |||||
| } | |||||
| scan( fromDir, m_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( null != m_destFile ) | |||||
| { | |||||
| m_destDir = null; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Get the filtersets being applied to this operation. | |||||
| * | |||||
| * @return a vector of FilterSet objects | |||||
| */ | |||||
| protected ArrayList getFilterSets() | |||||
| { | |||||
| return m_filterSets; | |||||
| } | |||||
| protected void buildMap( final File fromDir, | |||||
| final File toDir, | |||||
| final String[] names, | |||||
| final FileNameMapper mapper, | |||||
| final Hashtable map ) | |||||
| throws TaskException | |||||
| { | |||||
| final String[] toCopy = buildFilenameList( names, mapper, fromDir, toDir ); | |||||
| for( int i = 0; i < toCopy.length; i++ ) | |||||
| { | |||||
| final String destFilename = mapper.mapFileName( toCopy[ i ] )[ 0 ]; | |||||
| final File src = new File( fromDir, toCopy[ i ] ); | |||||
| final File dest = new File( toDir, destFilename ); | |||||
| map.put( src.getAbsolutePath(), dest.getAbsolutePath() ); | |||||
| } | |||||
| } | |||||
| private String[] buildFilenameList( final String[] names, | |||||
| final FileNameMapper mapper, | |||||
| final File fromDir, | |||||
| final File toDir ) | |||||
| throws TaskException | |||||
| { | |||||
| if( m_overwrite ) | |||||
| { | |||||
| final ArrayList list = new ArrayList( names.length ); | |||||
| for( int i = 0; i < names.length; i++ ) | |||||
| { | |||||
| final String name = names[ i ]; | |||||
| if( null != mapper.mapFileName( name ) ) | |||||
| { | |||||
| list.add( name ); | |||||
| } | |||||
| } | |||||
| return (String[])list.toArray( new String[ list.size() ] ); | |||||
| } | |||||
| else | |||||
| { | |||||
| final SourceFileScanner scanner = new SourceFileScanner(); | |||||
| setupLogger( scanner ); | |||||
| return scanner.restrict( names, fromDir, toDir, mapper ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Actually does the file (and possibly empty directory) copies. This is a | |||||
| * good method for subclasses to override. | |||||
| */ | |||||
| protected void doFileOperations() | |||||
| throws TaskException | |||||
| { | |||||
| if( m_fileCopyMap.size() > 0 ) | |||||
| { | |||||
| getLogger().info( "Copying " + m_fileCopyMap.size() + | |||||
| " file" + ( m_fileCopyMap.size() == 1 ? "" : "s" ) + | |||||
| " to " + m_destDir.getAbsolutePath() ); | |||||
| Enumeration e = m_fileCopyMap.keys(); | |||||
| while( e.hasMoreElements() ) | |||||
| { | |||||
| String fromFile = (String)e.nextElement(); | |||||
| String toFile = (String)m_fileCopyMap.get( fromFile ); | |||||
| if( fromFile.equals( toFile ) ) | |||||
| { | |||||
| getLogger().info( "Skipping self-copy of " + fromFile ); | |||||
| continue; | |||||
| } | |||||
| try | |||||
| { | |||||
| getLogger().info( "Copying " + fromFile + " to " + toFile ); | |||||
| final FilterSetCollection executionFilters = buildFilterSet(); | |||||
| final File src = new File( fromFile ); | |||||
| final File dest = new File( toFile ); | |||||
| if( m_overwrite ) | |||||
| { | |||||
| FileUtil.forceDelete( dest ); | |||||
| } | |||||
| FileUtils.copyFile( src, dest, executionFilters ); | |||||
| if( m_preserveLastModified ) | |||||
| { | |||||
| dest.setLastModified( src.lastModified() ); | |||||
| } | |||||
| } | |||||
| catch( final IOException ioe ) | |||||
| { | |||||
| final String msg = "Failed to copy " + fromFile + " to " + | |||||
| toFile + " due to " + ioe.getMessage(); | |||||
| throw new TaskException( msg, ioe ); | |||||
| } | |||||
| } | |||||
| } | |||||
| if( m_includeEmpty ) | |||||
| { | |||||
| Enumeration e = m_dirCopyMap.elements(); | |||||
| int count = 0; | |||||
| while( e.hasMoreElements() ) | |||||
| { | |||||
| File d = new File( (String)e.nextElement() ); | |||||
| if( !d.exists() ) | |||||
| { | |||||
| if( !d.mkdirs() ) | |||||
| { | |||||
| getLogger().error( "Unable to create directory " + d.getAbsolutePath() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| count++; | |||||
| } | |||||
| } | |||||
| } | |||||
| if( count > 0 ) | |||||
| { | |||||
| getLogger().info( "Copied " + count + | |||||
| " empty director" + | |||||
| ( count == 1 ? "y" : "ies" ) + | |||||
| " to " + m_destDir.getAbsolutePath() ); | |||||
| } | |||||
| } | |||||
| } | |||||
| protected final FilterSetCollection buildFilterSet() | |||||
| { | |||||
| final FilterSetCollection executionFilters = new FilterSetCollection(); | |||||
| if( m_filtering ) | |||||
| { | |||||
| executionFilters.addFilterSet( getProject().getGlobalFilterSet() ); | |||||
| } | |||||
| for( final Iterator filterEnum = m_filterSets.iterator(); filterEnum.hasNext(); ) | |||||
| { | |||||
| executionFilters.addFilterSet( (FilterSet)filterEnum.next() ); | |||||
| } | |||||
| return executionFilters; | |||||
| } | |||||
| /** | |||||
| * Compares source files to destination files to see if they should be | |||||
| * copied. | |||||
| */ | |||||
| protected void scan( File fromDir, File toDir, String[] files, String[] dirs ) | |||||
| throws TaskException | |||||
| { | |||||
| FileNameMapper mapper = null; | |||||
| if( m_mapperElement != null ) | |||||
| { | |||||
| mapper = m_mapperElement.getImplementation(); | |||||
| } | |||||
| else if( m_flatten ) | |||||
| { | |||||
| mapper = new FlatFileNameMapper(); | |||||
| } | |||||
| else | |||||
| { | |||||
| mapper = new IdentityMapper(); | |||||
| } | |||||
| buildMap( fromDir, toDir, files, mapper, m_fileCopyMap ); | |||||
| if( m_includeEmpty ) | |||||
| { | |||||
| buildMap( fromDir, toDir, dirs, mapper, m_dirCopyMap ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Ensure we have a consistent and legal set of attributes, and set any | |||||
| * internal flags necessary based on different combinations of attributes. | |||||
| * | |||||
| * @exception TaskException Description of Exception | |||||
| */ | |||||
| protected void validateAttributes() | |||||
| throws TaskException | |||||
| { | |||||
| if( m_file == null && m_filesets.size() == 0 ) | |||||
| { | |||||
| throw new TaskException( "Specify at least one source - a file or a fileset." ); | |||||
| } | |||||
| if( m_destFile != null && m_destDir != null ) | |||||
| { | |||||
| throw new TaskException( "Only one of tofile and todir may be set." ); | |||||
| } | |||||
| if( m_destFile == null && m_destDir == null ) | |||||
| { | |||||
| throw new TaskException( "One of tofile or todir must be set." ); | |||||
| } | |||||
| if( m_file != null && m_file.exists() && m_file.isDirectory() ) | |||||
| { | |||||
| throw new TaskException( "Use a fileset to copy directories." ); | |||||
| } | |||||
| if( m_destFile != null && m_filesets.size() > 0 ) | |||||
| { | |||||
| if( m_filesets.size() > 1 ) | |||||
| { | |||||
| throw new TaskException( | |||||
| "Cannot concatenate multiple files into a single file." ); | |||||
| } | |||||
| else | |||||
| { | |||||
| FileSet fs = (FileSet)m_filesets.get( 0 ); | |||||
| DirectoryScanner ds = ScannerUtil.getDirectoryScanner( fs ); | |||||
| String[] srcFiles = ds.getIncludedFiles(); | |||||
| if( srcFiles.length > 0 ) | |||||
| { | |||||
| if( m_file == null ) | |||||
| { | |||||
| m_file = new File( srcFiles[ 0 ] ); | |||||
| m_filesets.remove( 0 ); | |||||
| } | |||||
| else | |||||
| { | |||||
| throw new TaskException( | |||||
| "Cannot concatenate multiple files into a single file." ); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| throw new TaskException( | |||||
| "Cannot perform operation from directory to file." ); | |||||
| } | |||||
| } | |||||
| } | |||||
| if( m_destFile != null ) | |||||
| { | |||||
| m_destDir = new File( m_destFile.getParent() );// be 1.1 friendly | |||||
| } | |||||
| } | |||||
| protected ArrayList getFilesets() | |||||
| { | |||||
| return m_filesets; | |||||
| } | |||||
| protected boolean isFiltering() | |||||
| { | |||||
| return m_filtering; | |||||
| } | |||||
| protected boolean isForceOverwrite() | |||||
| { | |||||
| return m_overwrite; | |||||
| } | |||||
| protected boolean isIncludeEmpty() | |||||
| { | |||||
| return m_includeEmpty; | |||||
| } | |||||
| protected Hashtable getFileCopyMap() | |||||
| { | |||||
| return m_fileCopyMap; | |||||
| } | |||||
| protected Hashtable getDirCopyMap() | |||||
| { | |||||
| return m_dirCopyMap; | |||||
| } | |||||
| protected Hashtable getCompleteDirMap() | |||||
| { | |||||
| return m_completeDirMap; | |||||
| } | |||||
| protected File getDestDir() | |||||
| { | |||||
| return m_destDir; | |||||
| } | |||||
| } | |||||