From d408d9939072098ea4b59307fabc6f5fd936d572 Mon Sep 17 00:00:00 2001 From: Peter Donald Date: Sat, 9 Feb 2002 05:15:29 +0000 Subject: [PATCH] Copy across the copy task and strip out filtering git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271238 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/antlib/file/CopyTask.java | 466 ++++++++++++++++++ .../apache/antlib/file/Resources.properties | 15 + 2 files changed, 481 insertions(+) create mode 100644 proposal/myrmidon/src/java/org/apache/antlib/file/CopyTask.java diff --git a/proposal/myrmidon/src/java/org/apache/antlib/file/CopyTask.java b/proposal/myrmidon/src/java/org/apache/antlib/file/CopyTask.java new file mode 100644 index 000000000..b3c1628ea --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/antlib/file/CopyTask.java @@ -0,0 +1,466 @@ +/* + * 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.antlib.file; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.apache.avalon.excalibur.i18n.ResourceManager; +import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.excalibur.io.FileUtil; +import org.apache.myrmidon.api.AbstractTask; +import org.apache.myrmidon.api.TaskException; +import org.apache.tools.ant.types.DirectoryScanner; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.ScannerUtil; +import org.apache.tools.ant.types.SourceFileScanner; +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; + +/** + * This is a task used to copy files. + * + * @ant:task name="copy" + * @author Peter Donald + * @author Glenn McAllister + * @author Stefan Bodewig + * @author Michael McCallum + * @author Magesh Umasankar + * @version $Revision$ $Date$ + */ +public class CopyTask + extends AbstractTask +{ + private final static Resources REZ = + ResourceManager.getPackageResources( CopyTask.class ); + + private File m_file; + private ArrayList m_filesets = new ArrayList(); + private File m_destFile; + private File m_destDir; + private boolean m_preserveLastModified; + private boolean m_overwrite; + private boolean m_flatten; + private boolean m_includeEmpty = true; + private Mapper m_mapper; + + private HashMap m_fileMap = new HashMap(); + private HashMap m_dirMap = new HashMap(); + + /** + * Sets a single source file to copy. + */ + public void setFile( final File file ) + { + m_file = file; + } + + public void addFileset( final FileSet set ) + { + m_filesets.add( set ); + } + + public void setDestFile( final File destFile ) + { + m_destFile = destFile; + } + + public void setDestDir( final File destDir ) + { + m_destDir = destDir; + } + + public void setPreserveLastModified( boolean preserveLastModified ) + { + m_preserveLastModified = preserveLastModified; + } + + /** + * Overwrite any existing destination file(s). + */ + public void setOverwrite( boolean overwrite ) + { + m_overwrite = 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. + * + * @param flatten The new Flatten value + */ + public void setFlatten( final boolean flatten ) + { + m_flatten = flatten; + } + + /** + * Defines the FileNameMapper to use (nested mapper element). + */ + public void addMapper( final Mapper mapper ) + throws TaskException + { + if( null != m_mapper ) + { + final String message = "Cannot define more than one mapper"; + throw new TaskException( message ); + } + m_mapper = mapper; + } + + public void execute() + throws TaskException + { + validate(); + + // deal with the single file + if( m_file != null ) + { + if( null == m_destFile ) + { + m_destFile = new File( m_destDir, m_file.getName() ); + } + + if( m_overwrite || + ( m_file.lastModified() > m_destFile.lastModified() ) ) + { + m_fileMap.put( m_file.getAbsolutePath(), m_destFile.getAbsolutePath() ); + } + else + { + final String message = + REZ.getString( "copy.omit-uptodate.notice", m_file, m_destFile ); + getLogger().debug( 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(); + + scan( fromDir, m_destDir, srcFiles, srcDirs ); + } + + // do all the copy operations now... + doFileOperations( m_fileMap, m_dirMap ); + } + + protected void validate() + throws TaskException + { + final int fileSetSize = m_filesets.size(); + + if( null == m_file && 0 == fileSetSize ) + { + final String message = REZ.getString( "copy.missing-src.error" ); + throw new TaskException( message ); + } + + if( null != m_destFile && null != m_destDir ) + { + final String message = REZ.getString( "copy.one-dest-only.error" ); + throw new TaskException( message ); + } + + if( null != m_file && m_file.exists() && m_file.isDirectory() ) + { + final String message = REZ.getString( "copy.fileset-for-dirs.error" ); + throw new TaskException( message ); + } + + if( null != m_destFile && fileSetSize > 0 ) + { + if( fileSetSize > 1 ) + { + final String message = REZ.getString( "copy.need-destdir.error" ); + throw new TaskException( message ); + } + else + { + final FileSet fileSet = (FileSet)m_filesets.get( 0 ); + final DirectoryScanner scanner = ScannerUtil.getDirectoryScanner( fileSet ); + final String[] srcFiles = scanner.getIncludedFiles(); + + if( srcFiles.length > 0 ) + { + if( m_file == null ) + { + m_file = new File( srcFiles[ 0 ] ); + m_filesets.remove( 0 ); + } + else + { + final String message = REZ.getString( "copy.bad-mapping.error" ); + throw new TaskException( message ); + } + } + else + { + final String message = REZ.getString( "copy.bad-operation.error" ); + throw new TaskException( message ); + } + } + } + + if( null != m_file && !m_file.exists() ) + { + final String message = + REZ.getString( "copy.missing-file.error", m_file.getAbsolutePath() ); + throw new TaskException( message ); + } + + if( null != m_destFile ) + { + m_destDir = m_destFile.getParentFile(); + } + } + + /** + * Compares source files to destination files to see if they should be + * copied. + */ + private void scan( final File sourceDir, + final File destDir, + final String[] files, + final String[] dirs ) + throws TaskException + { + final FileNameMapper mapper = getFilenameMapper(); + + buildMap( sourceDir, destDir, files, mapper, m_fileMap ); + + if( m_includeEmpty ) + { + buildMap( sourceDir, destDir, dirs, mapper, m_dirMap ); + } + } + + private void buildMap( final File sourceDir, + final File destDir, + final String[] files, + final FileNameMapper mapper, + final Map map ) + throws TaskException + { + final String[] toCopy = buildFilenameList( files, mapper, sourceDir, destDir ); + for( int i = 0; i < toCopy.length; i++ ) + { + final String destFilename = mapper.mapFileName( toCopy[ i ] )[ 0 ]; + final File source = new File( sourceDir, toCopy[ i ] ); + final File destination = new File( destDir, destFilename ); + map.put( source.getAbsolutePath(), destination.getAbsolutePath() ); + } + } + + /** + * Utility method to build up a list of files needed between both + * but only getting the files that need updating (unless overwrite is true). + */ + 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 ); + } + } + + /** + * Perform the oepration on all the files (and possibly empty directorys). + */ + private void doFileOperations( final Map fileCopyMap, final Map dirCopyMap ) + throws TaskException + { + final int fileCount = fileCopyMap.size(); + if( fileCount > 0 ) + { + doOperationOnFiles( fileCopyMap ); + } + + if( m_includeEmpty ) + { + doOperationOnDirs( dirCopyMap ); + } + } + + /** + * perform operation on files. + */ + private void doOperationOnFiles( final Map fileMap ) + throws TaskException + { + final int fileCount = fileMap.size(); + displayFilecountNotice( fileCount ); + + final Iterator names = fileMap.keySet().iterator(); + while( names.hasNext() ) + { + final String source = (String)names.next(); + final String destination = (String)fileMap.get( source ); + + if( source.equals( destination ) ) + { + final String message = + REZ.getString( "copy.selfcopy-ignored.notice", source ); + getLogger().info( message ); + continue; + } + + try + { + final String message = + REZ.getString( "copy.filecopy.notice", source, destination ); + getLogger().info( message ); + + doOperation( source, destination ); + } + catch( final IOException ioe ) + { + final String message = + REZ.getString( "copy.filecopy.error", source, destination, ioe ); + throw new TaskException( message, ioe ); + } + } + } + + /** + * perform operation on directories. + */ + private void doOperationOnDirs( final Map dirMap ) + { + final Iterator dirs = dirMap.values().iterator(); + int count = 0; + while( dirs.hasNext() ) + { + final String pathname = (String)dirs.next(); + final File dir = new File( pathname ); + if( !dir.exists() ) + { + if( !dir.mkdirs() ) + { + final String message = + REZ.getString( "copy.dircopy.error", dir.getAbsolutePath() ); + getLogger().error( message ); + } + else + { + count++; + } + } + } + + if( count > 0 ) + { + displayDirCopyNotice( count ); + } + } + + /** + * Utility method to determine and retrieve FilenameMapper. + */ + private FileNameMapper getFilenameMapper() + throws TaskException + { + if( null != m_mapper ) + { + return m_mapper.getImplementation(); + } + else if( m_flatten ) + { + return new FlatFileNameMapper(); + } + else + { + return new IdentityMapper(); + } + } + + /** + * Utility method to perform operation to transform a single source file + * to a destination. + */ + private void doOperation( final String sourceFilename, + final String destinationFilename ) + throws IOException + { + final File source = new File( sourceFilename ); + final File destination = new File( destinationFilename ); + + if( m_overwrite ) + { + FileUtil.forceDelete( destination ); + } + + FileUtil.copyFile( source, destination ); + + if( m_preserveLastModified ) + { + destination.setLastModified( source.lastModified() ); + } + } + + /** + * Utility method to display notice about how many dirs copied. + */ + private void displayDirCopyNotice( final int count ) + { + final String message = + REZ.getString( "copy.dir-count.notice", + new Integer( count ), + m_destDir.getAbsolutePath() ); + getLogger().info( message ); + } + + /** + * Utility method to display notice about how many files copied. + */ + private void displayFilecountNotice( final int count ) + { + if( getLogger().isInfoEnabled() ) + { + final String message = + REZ.getString( "copy.file-count.notice", + new Integer( count ), + m_destDir.getAbsolutePath() ); + getLogger().info( message ); + } + } +} diff --git a/proposal/myrmidon/src/java/org/apache/antlib/file/Resources.properties b/proposal/myrmidon/src/java/org/apache/antlib/file/Resources.properties index 29552e401..e0910e0e2 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/file/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/antlib/file/Resources.properties @@ -19,3 +19,18 @@ delete.delete-file.notice=Deleting {0}. delete.delete-file.error=Unable to delete file {0}. delete.delete-file.error=Deleting {0} files from {1}. delete.summary.notice=Deleted {0,choice,0#zero directories|1#1 directory|2<{0} directories} from {1}. + +copy.omit-uptodate.notice={0} omitted as {1} is up to date. +copy.missing-src.error=No source file or fileset specified. +copy.one-dest-only.error=Only one of destFile or destDir may be set. +copy.fileset-for-dirs.error=Use a fileset to copy directories. +copy.need-destdir.error=Cannot copy multiple files into a single file. +copy.bad-mapping.error=Cannot concatenate multiple files into a single file. +copy.bad-operation.error=Cannot perform operation from directory to file. +copy.missing-file.error=Could not find file {0} to copy. +copy.dir-count.notice=Copied {0} empty director{0,choice,1#y|2