donaldp 02/01/27 02:07:16
Modified: proposal/myrmidon/src/main/org/apache/tools/ant/types
ScannerUtil.java
Added: proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive
ZipScanner.java ZipFileSet.java Zip.java
WhenEmpty.java War.java Untar.java
TarLongFileMode.java TarFileSet.java Tar.java
Jar.java Expand.java Ear.java
Removed: proposal/myrmidon/src/main/org/apache/tools/ant/types
ZipScanner.java ZipFileSet.java
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs
Zip.java WhenEmpty.java War.java Untar.java
TarLongFileMode.java TarFileSet.java Tar.java
Jar.java Expand.java Ear.java
Log:
Move zip/tar related archiving and un-archiving classes into new package
Revision Changes Path
1.6 +4 -2
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/types/ScannerUtil.java
Index: ScannerUtil.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/types/ScannerUtil.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ScannerUtil.java 27 Jan 2002 09:57:41 -0000 1.5
+++ ScannerUtil.java 27 Jan 2002 10:07:15 -0000 1.6
@@ -14,7 +14,9 @@
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.framework.PatternUtil;
import org.apache.myrmidon.framework.PatternSet;
-import org.apache.tools.ant.taskdefs.TarFileSet;
+import org.apache.tools.ant.taskdefs.archive.TarFileSet;
+import org.apache.tools.ant.taskdefs.archive.ZipFileSet;
+import org.apache.tools.ant.taskdefs.archive.ZipScanner;
/**
*
@@ -22,7 +24,7 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
* @author Arnout J. Kuiper <a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Magesh Umasankar</a>
- * @version $Revision: 1.5 $ $Date: 2002/01/27 09:57:41 $
+ * @version $Revision: 1.6 $ $Date: 2002/01/27 10:07:15 $
*/
public class ScannerUtil
{
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/ZipScanner.java
Index: ZipScanner.java
===================================================================
/*
* 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.archive;
import java.io.File;
import org.apache.tools.ant.types.DirectoryScanner;
/**
* ZipScanner accesses the pattern matching algorithm in DirectoryScanner,
which
* are protected methods that can only be accessed by subclassing. This
* implementation of FileScanner defines getIncludedFiles to return only the
Zip
* File which is being scanned, not the matching Zip entries. Arguably, it
* should return the matching entries, however this would complicate existing
* code which assumes that FileScanners return a set of file system files that
* can be accessed directly.
*
* @author Don Ferguson <a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>
*/
public class ZipScanner
extends DirectoryScanner
{
/**
* The zip file which should be scanned.
*/
private File m_src;
/**
* Sets the srcFile for scanning. This is the jar or zip file that is
* scanned for matching entries.
*
* @param srcFile the (non-null) zip file name for scanning
*/
public void setSrc( final File srcFile )
{
m_src = srcFile;
}
/**
* Returns an empty list of directories to create.
*
* @return The IncludedDirectories value
*/
public String[] getIncludedDirectories()
{
return new String[ 0 ];
}
/**
* Returns the zip file itself, not the matching entries within the zip
* file. This keeps the uptodate test in the Zip task simple; otherwise
we'd
* need to treat zip filesets specially.
*
* @return the source file from which entries will be extracted.
*/
public String[] getIncludedFiles()
{
final String[] result = new String[ 1 ];
result[ 0 ] = m_src.getAbsolutePath();
return result;
}
/**
* Initialize DirectoryScanner data structures.
*/
public void init()
{
if( getIncludes() == null )
{
// No includes supplied, so set it to 'matches all'
setIncludes( new String[ 1 ] );
getIncludes()[ 0 ] = "**";
}
if( getExcludes() == null )
{
setExcludes( new String[ 0 ] );
}
}
/**
* Matches a jar entry against the includes/excludes list, normalizing the
* path separator.
*
* @param path the (non-null) path name to test for inclusion
* @return <code>true</code> if the path should be included
<code>false</code>
* otherwise.
*/
public boolean match( String path )
{
final String vpath =
path.replace( '/', File.separatorChar ).replace( '\\',
File.separatorChar );
return isIncluded( vpath ) && !isExcluded( vpath );
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/ZipFileSet.java
Index: ZipFileSet.java
===================================================================
/*
* 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.archive;
import java.io.File;
import org.apache.tools.ant.types.FileSet;
/**
* A ZipFileSet is a FileSet with extra attributes useful in the context of
* Zip/Jar tasks. A ZipFileSet extends FileSets with the ability to extract a
* subset of the entries of a Zip file for inclusion in another Zip file. It
* also includes a prefix attribute which is prepended to each entry in the
* output Zip file. At present, ZipFileSets are not surfaced in the public
API.
* FileSets nested in a Zip task are instantiated as ZipFileSets, and their
* attributes are only recognized in the context of the the Zip task. It is
not
* possible to define a ZipFileSet outside of the Zip task and refer to it
via a
* refid. However a standard FileSet may be included by reference in the Zip
* task, and attributes in the refering ZipFileSet can augment FileSet
* definition.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Don Ferguson</a>
*/
public class ZipFileSet
extends FileSet
{
private File m_src;
private String m_prefix = "";
private String m_fullpath = "";
/**
* Set the full pathname of the single entry in this fileset.
*
* @param fullpath The new Fullpath value
*/
public void setFullpath( final String fullpath )
{
m_fullpath = fullpath;
}
/**
* Prepend this prefix to the path for each zip entry. Does not perform
* reference test; the referenced file set can be augmented with a prefix.
*
* @param prefix The prefix to prepend to entries in the zip file.
*/
public void setPrefix( final String prefix )
{
m_prefix = prefix;
}
/**
* Set the source Zip file for the zipfileset. Prevents both "dir" and
"src"
* from being specified.
*
* @param srcFile The zip file from which to extract entries.
*/
public void setSrc( final File src )
{
m_src = src;
}
/**
* Return the full pathname of the single entry in this fileset.
*
* @return The Fullpath value
*/
public String getFullpath()
{
return m_fullpath;
}
/**
* Return the prefix prepended to entries in the zip file.
*
* @return The Prefix value
*/
public String getPrefix()
{
return m_prefix;
}
/**
* Get the zip file from which entries will be extracted. References are
not
* followed, since it is not possible to have a reference to a ZipFileSet,
* only to a FileSet.
*
* @return The Src value
*/
public File getSrc()
{
return m_src;
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/Zip.java
Index: Zip.java
===================================================================
/*
* 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.archive;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Stack;
import java.util.zip.CRC32;
import java.util.zip.ZipInputStream;
import org.apache.aut.zip.ZipEntry;
import org.apache.aut.zip.ZipOutputStream;
import org.apache.myrmidon.api.TaskException;
import org.apache.tools.ant.types.DirectoryScanner;
import org.apache.tools.ant.types.FileScanner;
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.MergingMapper;
import org.apache.tools.ant.taskdefs.MatchingTask;
/**
* Create a ZIP archive.
*
* @author James Davidson <a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>
* @author Jon S. Stevens <a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
*/
public class Zip
extends MatchingTask
{
// For directories:
private final static long EMPTY_CRC = new CRC32().getValue();
private boolean m_compress = true;
private boolean m_update;
private boolean m_filesonly;
protected String m_archiveType = "zip";
protected String m_emptyBehavior = "skip";
private ArrayList m_filesets = new ArrayList();
protected Hashtable m_addedDirs = new Hashtable();
private ArrayList m_addedFiles = new ArrayList();
protected File m_file;
/**
* true when we are adding new files into the Zip file, as opposed to
adding
* back the unchanged files
*/
private boolean m_addingNewFiles;
private File m_baseDir;
/**
* Encoding to use for filenames, defaults to the platform's default
* encoding.
*/
private String m_encoding;
private static String[][] grabFileNames( final FileScanner[] scanners )
throws TaskException
{
String[][] result = new String[ scanners.length ][];
for( int i = 0; i < scanners.length; i++ )
{
String[] files = scanners[ i ].getIncludedFiles();
String[] dirs = scanners[ i ].getIncludedDirectories();
result[ i ] = new String[ files.length + dirs.length ];
System.arraycopy( files, 0, result[ i ], 0, files.length );
System.arraycopy( dirs, 0, result[ i ], files.length, dirs.length
);
}
return result;
}
private static File[] grabFiles( final FileScanner[] scanners,
final String[][] filenames )
{
final ArrayList files = new ArrayList();
for( int i = 0; i < filenames.length; i++ )
{
final File baseDir = scanners[ i ].getBasedir();
for( int j = 0; j < filenames[ i ].length; j++ )
{
files.add( new File( baseDir, filenames[ i ][ j ] ) );
}
}
final File[] toret = new File[ files.size() ];
return (File[])files.toArray( toret );
}
/**
* This is the base directory to look in for things to zip.
*
* @param baseDir The new Basedir value
*/
public void setBasedir( final File baseDir )
{
m_baseDir = baseDir;
}
/**
* Sets whether we want to compress the files or only store them.
*
* @param c The new Compress value
*/
public void setCompress( final boolean compress )
{
m_compress = compress;
}
/**
* Encoding to use for filenames, defaults to the platform's default
* encoding. <p>
*
* For a list of possible values see <a
*
href="http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html">
*
http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
* </a>.</p>
*
* @param encoding The new Encoding value
*/
public void setEncoding( final String encoding )
{
m_encoding = encoding;
}
/**
* This is the name/location of where to create the .zip file.
*
* @param file The new File value
*/
public void setFile( final File file )
{
m_file = file;
}
/**
* Emulate Sun's jar utility by not adding parent dirs
*
* @param f The new Filesonly value
*/
public void setFilesonly( final boolean filesonly )
{
m_filesonly = filesonly;
}
/**
* Sets whether we want to update the file (if it exists) or create a new
* one.
*
* @param c The new Update value
*/
public void setUpdate( final boolean update )
{
m_update = update;
}
/**
* Sets behavior of the task when no files match. Possible values are:
* <code>fail</code> (throw an exception and halt the build);
<code>skip</code>
* (do not create any archive, but issue a warning); <code>create</code>
* (make an archive with no entries). Default for zip tasks is
<code>skip</code>
* ; for jar tasks, <code>create</code>.
*
* @param we The new Whenempty value
*/
public void setWhenempty( final WhenEmpty we )
{
m_emptyBehavior = we.getValue();
}
/**
* Are we updating an existing archive?
*
* @return The InUpdateMode value
*/
protected final boolean isInUpdateMode()
{
return m_update;
}
/**
* Adds a set of files (nested fileset attribute).
*/
public void addFileset( final FileSet set )
{
m_filesets.add( set );
}
/**
* Adds a set of files (nested zipfileset attribute) that can be read from
* an archive and be given a prefix/fullpath.
*
* @param set The feature to be added to the Zipfileset attribute
*/
public void addZipfileset( final ZipFileSet set )
{
m_filesets.add( set );
}
public void execute()
throws TaskException
{
if( m_baseDir == null && m_filesets.size() == 0 &&
"zip".equals( m_archiveType ) )
{
final String message = "basedir attribute must be set, or at
least " +
"one fileset must be given!";
throw new TaskException( message );
}
if( m_file == null )
{
final String message = "You must specify the " +
m_archiveType + " file to create!";
throw new TaskException( message );
}
// Renamed version of original file, if it exists
File renamedFile = null;
// Whether or not an actual update is required -
// we don't need to update if the original file doesn't exist
m_addingNewFiles = true;
m_update = m_update && m_file.exists();
if( m_update )
{
try
{
renamedFile = File.createTempFile( "zip", ".tmp",
m_file.getParentFile() );
}
catch( final IOException ioe )
{
throw new TaskException( ioe.toString(), ioe );
}
try
{
if( !m_file.renameTo( renamedFile ) )
{
throw new TaskException( "Unable to rename old file to
temporary file" );
}
}
catch( SecurityException e )
{
throw new TaskException( "Not allowed to rename old file to
temporary file" );
}
}
// Create the scanners to pass to isUpToDate().
ArrayList dss = new ArrayList();
if( m_baseDir != null )
{
dss.add( getDirectoryScanner( m_baseDir ) );
}
for( int i = 0; i < m_filesets.size(); i++ )
{
final FileSet fileSet = (FileSet)m_filesets.get( i );
final DirectoryScanner scanner = getScanner( fileSet );
dss.add( scanner );
}
int dssSize = dss.size();
FileScanner[] scanners = new FileScanner[ dssSize ];
scanners = (FileScanner[])dss.toArray( scanners );
// quick exit if the target is up to date
// can also handle empty archives
if( isUpToDate( scanners, m_file ) )
{
return;
}
String action = m_update ? "Updating " : "Building ";
getLogger().info( action + m_archiveType + ": " +
m_file.getAbsolutePath() );
boolean success = false;
try
{
ZipOutputStream zOut =
new ZipOutputStream( new FileOutputStream( m_file ) );
zOut.setEncoding( m_encoding );
try
{
if( m_compress )
{
zOut.setMethod( ZipOutputStream.DEFLATED );
}
else
{
zOut.setMethod( ZipOutputStream.STORED );
}
initZipOutputStream( zOut );
// Add the implicit fileset to the archive.
if( m_baseDir != null )
{
addFiles( getDirectoryScanner( m_baseDir ), zOut, "", ""
);
}
// Add the explicit filesets to the archive.
addFiles( m_filesets, zOut );
if( m_update )
{
m_addingNewFiles = false;
ZipFileSet oldFiles = new ZipFileSet();
oldFiles.setSrc( renamedFile );
StringBuffer exclusionPattern = new StringBuffer();
for( int i = 0; i < m_addedFiles.size(); i++ )
{
if( i != 0 )
{
exclusionPattern.append( "," );
}
exclusionPattern.append( (String)m_addedFiles.get( i
) );
}
oldFiles.setExcludes( exclusionPattern.toString() );
ArrayList tmp = new ArrayList();
tmp.add( oldFiles );
addFiles( tmp, zOut );
}
finalizeZipOutputStream( zOut );
success = true;
}
finally
{
// Close the output stream.
try
{
if( zOut != null )
{
zOut.close();
}
}
catch( IOException ex )
{
// If we're in this finally clause because of an
exception, we don't
// really care if there's an exception when closing the
stream. E.g. if it
// throws "ZIP file must have at least one entry",
because an exception happened
// before we added any files, then we must swallow this
exception. Otherwise,
// the error that's reported will be the close() error,
which is not the real
// cause of the problem.
if( success )
{
throw ex;
}
}
}
}
catch( IOException ioe )
{
String msg = "Problem creating " + m_archiveType + ": " +
ioe.getMessage();
// delete a bogus ZIP file
if( !m_file.delete() )
{
msg += " (and the archive is probably corrupt but I could not
delete it)";
}
if( m_update )
{
if( !renamedFile.renameTo( m_file ) )
{
msg += " (and I couldn't rename the temporary file " +
renamedFile.getName() + " back)";
}
}
throw new TaskException( msg, ioe );
}
// If we've been successful on an update, delete the temporary file
if( success && m_update )
{
if( !renamedFile.delete() )
{
final String message = "Warning: unable to delete temporary
file " +
renamedFile.getName();
getLogger().warn( message );
}
}
}
private DirectoryScanner getScanner( final FileSet fileSet )
throws TaskException
{
if( fileSet instanceof ZipFileSet )
{
final ZipFileSet zipFileSet = (ZipFileSet)fileSet;
return ScannerUtil.getZipScanner( zipFileSet );
}
else
{
return ScannerUtil.getDirectoryScanner( fileSet );
}
}
protected void addFileAs( final File file, final String name )
throws TaskException
{
// Create a ZipFileSet for this file, and pass it up.
final ZipFileSet fs = new ZipFileSet();
fs.setDir( file.getParentFile() );
fs.setIncludes( file.getName() );
fs.setFullpath( name );
addFileset( fs );
}
/**
* Indicates if the task is adding new files into the archive as opposed
to
* copying back unchanged files from the backup copy
*
* @return The AddingNewFiles value
*/
protected final boolean isAddingNewFiles()
{
return m_addingNewFiles;
}
/**
* Check whether the archive is up-to-date; and handle behavior for empty
* archives.
*
* @param scanners list of prepared scanners containing files to archive
* @param zipFile intended archive file (may or may not exist)
* @return true if nothing need be done (may have done something already);
* false if archive creation should proceed
* @exception TaskException if it likes
*/
protected boolean isUpToDate( FileScanner[] scanners, File zipFile )
throws TaskException
{
String[][] fileNames = grabFileNames( scanners );
File[] files = grabFiles( scanners, fileNames );
if( files.length == 0 )
{
if( m_emptyBehavior.equals( "skip" ) )
{
final String message = "Warning: skipping " + m_archiveType +
" archive " + zipFile +
" because no files were included.";
getLogger().warn( message );
return true;
}
else if( m_emptyBehavior.equals( "fail" ) )
{
throw new TaskException( "Cannot create " + m_archiveType + "
archive " + zipFile +
": no files were included." );
}
else
{
// Create.
return createEmptyZip( zipFile );
}
}
else
{
for( int i = 0; i < files.length; ++i )
{
if( files[ i ].equals( zipFile ) )
{
throw new TaskException( "A zip file cannot include
itself" );
}
}
if( !zipFile.exists() )
{
return false;
}
final SourceFileScanner scanner = new SourceFileScanner();
setupLogger( scanner );
MergingMapper mm = new MergingMapper();
mm.setTo( zipFile.getAbsolutePath() );
for( int i = 0; i < scanners.length; i++ )
{
if( scanner.restrict( fileNames[ i ], scanners[ i
].getBasedir(), null,
mm ).length > 0 )
{
return false;
}
}
return true;
}
}
/**
* Add all files of the given FileScanner to the ZipOutputStream prependig
* the given prefix to each filename. <p>
*
* Ensure parent directories have been added as well.
*
* @param scanner The feature to be added to the Files attribute
* @param zOut The feature to be added to the Files attribute
* @param prefix The feature to be added to the Files attribute
* @param fullpath The feature to be added to the Files attribute
* @exception IOException Description of Exception
*/
protected void addFiles( FileScanner scanner, ZipOutputStream zOut,
String prefix, String fullpath )
throws IOException, TaskException
{
if( prefix.length() > 0 && fullpath.length() > 0 )
{
throw new TaskException( "Both prefix and fullpath attributes may
not be set on the same fileset." );
}
File thisBaseDir = scanner.getBasedir();
// directories that matched include patterns
String[] dirs = scanner.getIncludedDirectories();
if( dirs.length > 0 && fullpath.length() > 0 )
{
throw new TaskException( "fullpath attribute may only be
specified for filesets that specify a single file." );
}
for( int i = 0; i < dirs.length; i++ )
{
if( "".equals( dirs[ i ] ) )
{
continue;
}
String name = dirs[ i ].replace( File.separatorChar, '/' );
if( !name.endsWith( "/" ) )
{
name += "/";
}
addParentDirs( thisBaseDir, name, zOut, prefix );
}
// files that matched include patterns
String[] files = scanner.getIncludedFiles();
if( files.length > 1 && fullpath.length() > 0 )
{
throw new TaskException( "fullpath attribute may only be
specified for filesets that specify a single file." );
}
for( int i = 0; i < files.length; i++ )
{
File f = new File( thisBaseDir, files[ i ] );
if( fullpath.length() > 0 )
{
// Add this file at the specified location.
addParentDirs( null, fullpath, zOut, "" );
zipFile( f, zOut, fullpath );
}
else
{
// Add this file with the specified prefix.
String name = files[ i ].replace( File.separatorChar, '/' );
addParentDirs( thisBaseDir, name, zOut, prefix );
zipFile( f, zOut, prefix + name );
}
}
}
/**
* Iterate over the given ArrayList of (zip)filesets and add all files to
the
* ZipOutputStream using the given prefix or fullpath.
*
* @param filesets The feature to be added to the Files attribute
* @param zOut The feature to be added to the Files attribute
* @exception IOException Description of Exception
*/
protected void addFiles( ArrayList filesets, ZipOutputStream zOut )
throws IOException, TaskException
{
// Add each fileset in the ArrayList.
for( int i = 0; i < filesets.size(); i++ )
{
FileSet fs = (FileSet)filesets.get( i );
DirectoryScanner ds = getScanner( fs );
String prefix = "";
String fullpath = "";
if( fs instanceof ZipFileSet )
{
ZipFileSet zfs = (ZipFileSet)fs;
prefix = zfs.getPrefix();
fullpath = zfs.getFullpath();
}
if( prefix.length() > 0
&& !prefix.endsWith( "/" )
&& !prefix.endsWith( "\\" ) )
{
prefix += "/";
}
// Need to manually add either fullpath's parent directory, or
// the prefix directory, to the archive.
if( prefix.length() > 0 )
{
addParentDirs( null, prefix, zOut, "" );
zipDir( null, zOut, prefix );
}
else if( fullpath.length() > 0 )
{
addParentDirs( null, fullpath, zOut, "" );
}
if( fs instanceof ZipFileSet
&& ( (ZipFileSet)fs ).getSrc() != null )
{
addZipEntries( (ZipFileSet)fs, ds, zOut, prefix, fullpath );
}
else
{
// Add the fileset.
addFiles( ds, zOut, prefix, fullpath );
}
}
}
/**
* Ensure all parent dirs of a given entry have been added.
*
* @param baseDir The feature to be added to the ParentDirs attribute
* @param entry The feature to be added to the ParentDirs attribute
* @param zOut The feature to be added to the ParentDirs attribute
* @param prefix The feature to be added to the ParentDirs attribute
* @exception IOException Description of Exception
*/
protected void addParentDirs( File baseDir, String entry,
ZipOutputStream zOut, String prefix )
throws IOException
{
if( !m_filesonly )
{
Stack directories = new Stack();
int slashPos = entry.length();
while( ( slashPos = entry.lastIndexOf( (int)'/', slashPos - 1 ) )
!= -1 )
{
String dir = entry.substring( 0, slashPos + 1 );
if( m_addedDirs.get( prefix + dir ) != null )
{
break;
}
directories.push( dir );
}
while( !directories.isEmpty() )
{
String dir = (String)directories.pop();
File f = null;
if( baseDir != null )
{
f = new File( baseDir, dir );
}
else
{
f = new File( dir );
}
zipDir( f, zOut, prefix + dir );
}
}
}
protected void addZipEntries( ZipFileSet fs, DirectoryScanner ds,
ZipOutputStream zOut, String prefix, String
fullpath )
throws IOException, TaskException
{
if( prefix.length() > 0 && fullpath.length() > 0 )
{
throw new TaskException( "Both prefix and fullpath attributes may
not be set on the same fileset." );
}
ZipScanner zipScanner = (ZipScanner)ds;
File zipSrc = fs.getSrc();
ZipEntry entry;
java.util.zip.ZipEntry origEntry;
ZipInputStream in = null;
try
{
in = new ZipInputStream( new FileInputStream( zipSrc ) );
while( ( origEntry = in.getNextEntry() ) != null )
{
entry = new ZipEntry( origEntry );
String vPath = entry.getName();
if( zipScanner.match( vPath ) )
{
if( fullpath.length() > 0 )
{
addParentDirs( null, fullpath, zOut, "" );
zipFile( in, zOut, fullpath, entry.getTime() );
}
else
{
addParentDirs( null, vPath, zOut, prefix );
if( !entry.isDirectory() )
{
zipFile( in, zOut, prefix + vPath,
entry.getTime() );
}
}
}
}
}
finally
{
if( in != null )
{
in.close();
}
}
}
/**
* Create an empty zip file
*
* @param zipFile Description of Parameter
* @return true if the file is then considered up to date.
*/
protected boolean createEmptyZip( File zipFile )
throws TaskException
{
// In this case using java.util.zip will not work
// because it does not permit a zero-entry archive.
// Must create it manually.
getLogger().info( "Note: creating empty " + m_archiveType + " archive
" + zipFile );
try
{
OutputStream os = new FileOutputStream( zipFile );
try
{
// Cf. PKZIP specification.
byte[] empty = new byte[ 22 ];
empty[ 0 ] = 80;// P
empty[ 1 ] = 75;// K
empty[ 2 ] = 5;
empty[ 3 ] = 6;
// remainder zeros
os.write( empty );
}
finally
{
os.close();
}
}
catch( IOException ioe )
{
throw new TaskException( "Could not create empty ZIP archive",
ioe );
}
return true;
}
protected void finalizeZipOutputStream( ZipOutputStream zOut )
throws IOException, TaskException
{
}
protected void initZipOutputStream( ZipOutputStream zOut )
throws IOException, TaskException
{
}
protected void zipDir( File dir, ZipOutputStream zOut, String vPath )
throws IOException
{
if( m_addedDirs.get( vPath ) != null )
{
// don't add directories we've already added.
// no warning if we try, it is harmless in and of itself
return;
}
m_addedDirs.put( vPath, vPath );
ZipEntry ze = new ZipEntry( vPath );
if( dir != null && dir.exists() )
{
ze.setTime( dir.lastModified() );
}
else
{
ze.setTime( System.currentTimeMillis() );
}
ze.setSize( 0 );
ze.setMethod( ZipEntry.STORED );
// This is faintly ridiculous:
ze.setCrc( EMPTY_CRC );
// this is 040775 | MS-DOS directory flag in reverse byte order
ze.setExternalAttributes( 0x41FD0010L );
zOut.putNextEntry( ze );
}
protected void zipFile( InputStream in, ZipOutputStream zOut, String
vPath,
long lastModified )
throws IOException, TaskException
{
ZipEntry ze = new ZipEntry( vPath );
ze.setTime( lastModified );
/*
* XXX ZipOutputStream.putEntry expects the ZipEntry to know its
* size and the CRC sum before you start writing the data when using
* STORED mode.
*
* This forces us to process the data twice.
*
* I couldn't find any documentation on this, just found out by try
* and error.
*/
if( !m_compress )
{
long size = 0;
CRC32 cal = new CRC32();
if( !in.markSupported() )
{
// Store data into a byte[]
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[ 8 * 1024 ];
int count = 0;
do
{
size += count;
cal.update( buffer, 0, count );
bos.write( buffer, 0, count );
count = in.read( buffer, 0, buffer.length );
} while( count != -1 );
in = new ByteArrayInputStream( bos.toByteArray() );
}
else
{
in.mark( Integer.MAX_VALUE );
byte[] buffer = new byte[ 8 * 1024 ];
int count = 0;
do
{
size += count;
cal.update( buffer, 0, count );
count = in.read( buffer, 0, buffer.length );
} while( count != -1 );
in.reset();
}
ze.setSize( size );
ze.setCrc( cal.getValue() );
}
zOut.putNextEntry( ze );
byte[] buffer = new byte[ 8 * 1024 ];
int count = 0;
do
{
if( count != 0 )
{
zOut.write( buffer, 0, count );
}
count = in.read( buffer, 0, buffer.length );
} while( count != -1 );
m_addedFiles.add( vPath );
}
protected void zipFile( File file, ZipOutputStream zOut, String vPath )
throws IOException, TaskException
{
if( file.equals( m_file ) )
{
throw new TaskException( "A zip file cannot include itself" );
}
FileInputStream fIn = new FileInputStream( file );
try
{
zipFile( fIn, zOut, vPath, file.lastModified() );
}
finally
{
fIn.close();
}
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/WhenEmpty.java
Index: WhenEmpty.java
===================================================================
/*
* 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.archive;
import org.apache.tools.ant.types.EnumeratedAttribute;
/**
* Possible behaviors when there are no matching files for the task.
*/
public class WhenEmpty
extends EnumeratedAttribute
{
public String[] getValues()
{
return new String[]{"fail", "skip", "create"};
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/War.java
Index: War.java
===================================================================
/*
* 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.archive;
import java.io.File;
import java.io.IOException;
import org.apache.myrmidon.api.TaskException;
import org.apache.aut.zip.ZipOutputStream;
/**
* Creates a WAR archive.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
*/
public class War
extends Jar
{
private File m_webxml;
private boolean m_descriptorAdded;
public War()
{
super();
m_archiveType = "war";
m_emptyBehavior = "create";
}
public void setWebxml( final File descr )
throws TaskException
{
m_webxml = descr;
if( !m_webxml.exists() )
{
final String message = "Deployment descriptor: " +
m_webxml + " does not exist.";
throw new TaskException( message );
}
addFileAs(descr, "WEB-INF/web.xml" );
}
public void addClasses( final ZipFileSet fs )
{
// We just set the prefix for this fileset, and pass it up.
fs.setPrefix( "WEB-INF/classes/" );
super.addFileset( fs );
}
public void addLib( final ZipFileSet fs )
{
// We just set the prefix for this fileset, and pass it up.
fs.setPrefix( "WEB-INF/lib/" );
super.addFileset( fs );
}
public void addWebinf( final ZipFileSet fs )
{
// We just set the prefix for this fileset, and pass it up.
fs.setPrefix( "WEB-INF/" );
super.addFileset( fs );
}
protected void initZipOutputStream( final ZipOutputStream zOut )
throws IOException, TaskException
{
// If no webxml file is specified, it's an error.
if( m_webxml == null && !isInUpdateMode() )
{
throw new TaskException( "webxml attribute is required" );
}
super.initZipOutputStream( zOut );
}
protected void zipFile( final File file,
final ZipOutputStream zOut,
final String vPath )
throws IOException, TaskException
{
// If the file being added is WEB-INF/web.xml, we warn if it's not the
// one specified in the "webxml" attribute - or if it's being added
twice,
// meaning the same file is specified by the "webxml" attribute and in
// a <fileset> element.
if( vPath.equalsIgnoreCase( "WEB-INF/web.xml" ) )
{
if( m_webxml == null || !m_webxml.equals( file ) ||
m_descriptorAdded )
{
final String message = "Warning: selected " + m_archiveType +
" files include a WEB-INF/web.xml which will be ignored "
+
"(please use webxml attribute to " + m_archiveType + "
task)";
getLogger().warn( message );
}
else
{
super.zipFile( file, zOut, vPath );
m_descriptorAdded = true;
}
}
else
{
super.zipFile( file, zOut, vPath );
}
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/Untar.java
Index: Untar.java
===================================================================
/*
* 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.archive;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.myrmidon.api.TaskException;
import org.apache.aut.tar.TarEntry;
import org.apache.aut.tar.TarInputStream;
/**
* Untar a file. Heavily based on the Expand task.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Magesh Umasankar</a>
*/
public class Untar extends Expand
{
protected void expandFile( File srcF, File dir )
throws TaskException
{
TarInputStream tis = null;
try
{
getLogger().info( "Expanding: " + srcF + " into " + dir );
tis = new TarInputStream( new FileInputStream( srcF ) );
TarEntry te = null;
while( ( te = tis.getNextEntry() ) != null )
{
extractFile( srcF, dir, tis,
te.getName(),
te.getModTime(), te.isDirectory() );
}
getLogger().debug( "expand complete" );
}
catch( IOException ioe )
{
throw new TaskException( "Error while expanding " +
srcF.getPath(), ioe );
}
finally
{
if( tis != null )
{
try
{
tis.close();
}
catch( IOException e )
{
}
}
}
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/TarLongFileMode.java
Index: TarLongFileMode.java
===================================================================
/*
* 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.archive;
import org.apache.myrmidon.api.TaskException;
import org.apache.tools.ant.types.EnumeratedAttribute;
/**
* Valid Modes for LongFile attribute to Tar Task
*
* @author <a href="mailto:[EMAIL PROTECTED]">Magesh Umasankar</a>
*/
public class TarLongFileMode
extends EnumeratedAttribute
{
// permissable values for longfile attribute
public final static String WARN = "warn";
public final static String FAIL = "fail";
public final static String TRUNCATE = "truncate";
public final static String GNU = "gnu";
public final static String OMIT = "omit";
private final String[] validModes = {WARN, FAIL, TRUNCATE, GNU, OMIT};
public TarLongFileMode()
throws TaskException
{
super();
setValue( WARN );
}
public String[] getValues()
{
return validModes;
}
public boolean isFailMode()
{
return FAIL.equalsIgnoreCase( getValue() );
}
public boolean isGnuMode()
{
return GNU.equalsIgnoreCase( getValue() );
}
public boolean isOmitMode()
{
return OMIT.equalsIgnoreCase( getValue() );
}
public boolean isTruncateMode()
{
return TRUNCATE.equalsIgnoreCase( getValue() );
}
public boolean isWarnMode()
{
return WARN.equalsIgnoreCase( getValue() );
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/TarFileSet.java
Index: TarFileSet.java
===================================================================
/*
* 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.archive;
import org.apache.tools.ant.types.FileSet;
public class TarFileSet
extends FileSet
{
private int m_mode = 0100644;
private String m_userName = "";
private String m_groupName = "";
public void setGroup( final String groupName )
{
m_groupName = groupName;
}
public void setMode( final String octalString )
{
m_mode = 0100000 | Integer.parseInt( octalString, 8 );
}
public void setUserName( final String userName )
{
m_userName = userName;
}
protected String getGroup()
{
return m_groupName;
}
protected int getMode()
{
return m_mode;
}
protected String getUserName()
{
return m_userName;
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/Tar.java
Index: Tar.java
===================================================================
/*
* 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.archive;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.aut.tar.TarEntry;
import org.apache.aut.tar.TarOutputStream;
import org.apache.avalon.excalibur.io.IOUtil;
import org.apache.myrmidon.api.TaskException;
import org.apache.tools.ant.types.SourceFileScanner;
import org.apache.tools.ant.types.ScannerUtil;
import org.apache.tools.ant.util.mappers.MergingMapper;
import org.apache.tools.ant.taskdefs.MatchingTask;
/**
* Creates a TAR archive.
*
* @author Stefano Mazzocchi <a href="mailto:[EMAIL PROTECTED]">
* [EMAIL PROTECTED]</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Magesh Umasankar</a>
*/
public class Tar
extends MatchingTask
{
private TarLongFileMode longFileMode = createMode();
private TarLongFileMode createMode()
{
try
{
return new TarLongFileMode();
}
catch( TaskException e )
{
throw new IllegalStateException( e.getMessage() );
}
}
ArrayList filesets = new ArrayList();
ArrayList fileSetFiles = new ArrayList();
/**
* Indicates whether the user has been warned about long files already.
*/
private boolean longWarningGiven = false;
File baseDir;
File tarFile;
/**
* This is the base directory to look in for things to tar.
*
* @param baseDir The new Basedir value
*/
public void setBasedir( File baseDir )
{
this.baseDir = baseDir;
}
/**
* Set how to handle long files. Allowable values are truncate - paths are
* truncated to the maximum length fail - paths greater than the maximim
* cause a build exception warn - paths greater than the maximum cause a
* warning and GNU is used gnu - GNU extensions are used for any paths
* greater than the maximum. omit - paths greater than the maximum are
* omitted from the archive
*
* @param mode The new Longfile value
*/
public void setLongfile( TarLongFileMode mode )
{
this.longFileMode = mode;
}
/**
* This is the name/location of where to create the tar file.
*
* @param tarFile The new Tarfile value
*/
public void setTarfile( File tarFile )
{
this.tarFile = tarFile;
}
public TarFileSet createTarFileSet()
{
TarFileSet fileset = new TarFileSet();
filesets.add( fileset );
return fileset;
}
public void execute()
throws TaskException
{
if( tarFile == null )
{
throw new TaskException( "tarfile attribute must be set!" );
}
if( tarFile.exists() && tarFile.isDirectory() )
{
throw new TaskException( "tarfile is a directory!" );
}
if( tarFile.exists() && !tarFile.canWrite() )
{
throw new TaskException( "Can not write to the specified
tarfile!" );
}
if( baseDir != null )
{
if( !baseDir.exists() )
{
throw new TaskException( "basedir does not exist!" );
}
// add the main fileset to the list of filesets to process.
final TarFileSet mainFileSet = new TarFileSet( /*fileset*/ );
mainFileSet.setDir( baseDir );
filesets.add( mainFileSet );
}
if( filesets.size() == 0 )
{
throw new TaskException( "You must supply either a basdir
attribute or some nested filesets." );
}
// check if tr is out of date with respect to each
// fileset
boolean upToDate = true;
for( Iterator e = filesets.iterator(); e.hasNext(); )
{
TarFileSet fs = (TarFileSet)e.next();
String[] files = ScannerUtil.getFiles( fs );
if( !archiveIsUpToDate( files ) )
{
upToDate = false;
}
for( int i = 0; i < files.length; ++i )
{
if( tarFile.equals( new File( fs.getDir(), files[ i ] ) ) )
{
throw new TaskException( "A tar file cannot include
itself" );
}
}
}
if( upToDate )
{
getLogger().info( "Nothing to do: " + tarFile.getAbsolutePath() +
" is up to date." );
return;
}
getLogger().info( "Building tar: " + tarFile.getAbsolutePath() );
TarOutputStream tOut = null;
try
{
tOut = new TarOutputStream( new FileOutputStream( tarFile ) );
tOut.setDebug( true );
if( longFileMode.isTruncateMode() )
{
tOut.setLongFileMode( TarOutputStream.LONGFILE_TRUNCATE );
}
else if( longFileMode.isFailMode() ||
longFileMode.isOmitMode() )
{
tOut.setLongFileMode( TarOutputStream.LONGFILE_ERROR );
}
else
{
// warn or GNU
tOut.setLongFileMode( TarOutputStream.LONGFILE_GNU );
}
longWarningGiven = false;
for( Iterator e = filesets.iterator(); e.hasNext(); )
{
TarFileSet fs = (TarFileSet)e.next();
String[] files = ScannerUtil.getFiles( fs );
for( int i = 0; i < files.length; i++ )
{
File f = new File( fs.getDir(), files[ i ] );
String name = files[ i ].replace( File.separatorChar, '/'
);
tarFile( f, tOut, name, fs );
}
}
}
catch( IOException ioe )
{
String msg = "Problem creating TAR: " + ioe.getMessage();
throw new TaskException( msg, ioe );
}
finally
{
if( tOut != null )
{
try
{
// close up
tOut.close();
}
catch( IOException e )
{
}
}
}
}
private boolean archiveIsUpToDate( final String[] files )
throws TaskException
{
final SourceFileScanner scanner = new SourceFileScanner();
setupLogger( scanner );
final MergingMapper mapper = new MergingMapper();
mapper.setTo( tarFile.getAbsolutePath() );
return scanner.restrict( files, baseDir, null, mapper ).length == 0;
}
private void tarFile( final File file,
final TarOutputStream output,
String path,
final TarFileSet tarFileSet )
throws IOException, TaskException
{
// don't add "" to the archive
if( path.length() <= 0 )
{
return;
}
if( file.isDirectory() && !path.endsWith( "/" ) )
{
path += "/";
}
if( path.length() >= TarEntry.NAMELEN )
{
if( longFileMode.isOmitMode() )
{
final String message = "Omitting: " + path;
getLogger().info( message );
return;
}
else if( longFileMode.isWarnMode() )
{
final String message = "Entry: " + path + " longer than " +
TarEntry.NAMELEN + " characters.";
getLogger().warn( message );
if( !longWarningGiven )
{
final String message2 = "Resulting tar file can only be
processed successfully"
+ " by GNU compatible tar commands";
getLogger().warn( message2 );
longWarningGiven = true;
}
}
else if( longFileMode.isFailMode() )
{
final String message = "Entry: " + path + " longer than " +
TarEntry.NAMELEN + "characters.";
throw new TaskException( message );
}
}
FileInputStream input = null;
try
{
final TarEntry entry = new TarEntry( path );
entry.setModTime( file.lastModified() );
if( !file.isDirectory() )
{
entry.setSize( file.length() );
entry.setMode( tarFileSet.getMode() );
}
entry.setUserName( tarFileSet.getUserName() );
entry.setGroupName( tarFileSet.getGroup() );
output.putNextEntry( entry );
if( !file.isDirectory() )
{
input = new FileInputStream( file );
IOUtil.copy( input, output );
}
output.closeEntry();
}
finally
{
IOUtil.shutdownStream( input );
}
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/Jar.java
Index: Jar.java
===================================================================
/*
* 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.archive;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.zip.ZipFile;
import org.apache.myrmidon.api.TaskException;
import org.apache.tools.ant.types.FileScanner;
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.taskdefs.ManifestException;
import org.apache.aut.zip.ZipOutputStream;
/**
* Creates a JAR archive.
*
* @author James Davidson <a href="mailto:[EMAIL PROTECTED]">[EMAIL
PROTECTED]</a>
*/
public class Jar
extends Zip
{
/**
* The index file name.
*/
private final static String INDEX_NAME = "META-INF/INDEX.LIST";
/**
* true if a manifest has been specified in the task
*/
private boolean buildFileManifest;
/**
* jar index is JDK 1.3+ only
*/
private boolean m_index;
private Manifest m_execManifest;
private Manifest m_manifest;
private File m_manifestFile;
/**
* constructor
*/
public Jar()
{
super();
m_archiveType = "jar";
m_emptyBehavior = "create";
setEncoding( "UTF8" );
}
/**
* Set whether or not to create an index list for classes to speed up
* classloading.
*
* @param flag The new Index value
*/
public void setIndex( boolean flag )
{
m_index = flag;
}
public void setManifest( File manifestFile )
throws TaskException
{
if( !manifestFile.exists() )
{
final String message = "Manifest file: " + manifestFile + " does
not exist.";
throw new TaskException( message );
}
this.m_manifestFile = manifestFile;
Reader r = null;
try
{
r = new FileReader( manifestFile );
Manifest newManifest = new Manifest( r );
if( m_manifest == null )
{
m_manifest = Manifest.getDefaultManifest();
}
m_manifest.merge( newManifest );
}
catch( ManifestException e )
{
final String message = "Manifest " + manifestFile + " is invalid:
" + e.getMessage();
getLogger().error( message );
throw new TaskException( message, e );
}
catch( IOException e )
{
final String message = "Unable to read manifest file: " +
manifestFile;
throw new TaskException( message, e );
}
finally
{
if( r != null )
{
try
{
r.close();
}
catch( IOException e )
{
// do nothing
}
}
}
}
public void setWhenempty( WhenEmpty we )
{
final String message = "JARs are never empty, they contain at least a
manifest file";
getLogger().warn( message );
}
public void addManifest( Manifest newManifest )
throws ManifestException, TaskException
{
if( m_manifest == null )
{
m_manifest = Manifest.getDefaultManifest();
}
m_manifest.merge( newManifest );
buildFileManifest = true;
}
public void addMetainf( ZipFileSet fs )
{
// We just set the prefix for this fileset, and pass it up.
fs.setPrefix( "META-INF/" );
super.addFileset( fs );
}
/**
* Check whether the archive is up-to-date;
*
* @param scanners list of prepared scanners containing files to archive
* @param zipFile intended archive file (may or may not exist)
* @return true if nothing need be done (may have done something already);
* false if archive creation should proceed
* @exception TaskException if it likes
*/
protected boolean isUpToDate( FileScanner[] scanners, File zipFile )
throws TaskException
{
// need to handle manifest as a special check
if( buildFileManifest || m_manifestFile == null )
{
java.util.zip.ZipFile theZipFile = null;
try
{
theZipFile = new ZipFile( zipFile );
java.util.zip.ZipEntry entry = theZipFile.getEntry(
"META-INF/MANIFEST.MF" );
if( entry == null )
{
getLogger().debug( "Updating jar since the current jar
has no manifest" );
return false;
}
Manifest currentManifest = new Manifest( new
InputStreamReader( theZipFile.getInputStream( entry ) ) );
if( m_manifest == null )
{
m_manifest = Manifest.getDefaultManifest();
}
if( !currentManifest.equals( m_manifest ) )
{
getLogger().debug( "Updating jar since jar manifest has
changed" );
return false;
}
}
catch( Exception e )
{
// any problems and we will rebuild
getLogger().debug( "Updating jar since cannot read current
jar manifest: " + e.getClass().getName() + e.getMessage() );
return false;
}
finally
{
if( theZipFile != null )
{
try
{
theZipFile.close();
}
catch( IOException e )
{
//ignore
}
}
}
}
else if( m_manifestFile.lastModified() > zipFile.lastModified() )
{
return false;
}
return super.isUpToDate( scanners, zipFile );
}
protected boolean createEmptyZip( File zipFile )
{
// Jar files always contain a manifest and can never be empty
return false;
}
protected void finalizeZipOutputStream( ZipOutputStream zOut )
throws IOException, TaskException
{
if( m_index )
{
createIndexList( zOut );
}
}
protected void initZipOutputStream( ZipOutputStream zOut )
throws IOException, TaskException
{
try
{
m_execManifest = Manifest.getDefaultManifest();
if( m_manifest != null )
{
m_execManifest.merge( m_manifest );
}
for( Iterator e = m_execManifest.getWarnings(); e.hasNext(); )
{
getLogger().warn( "Manifest warning: " + (String)e.next() );
}
zipDir( null, zOut, "META-INF/" );
// time to write the manifest
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter writer = new PrintWriter( baos );
m_execManifest.write( writer );
writer.flush();
ByteArrayInputStream bais = new ByteArrayInputStream(
baos.toByteArray() );
super.zipFile( bais, zOut, "META-INF/MANIFEST.MF",
System.currentTimeMillis() );
super.initZipOutputStream( zOut );
}
catch( ManifestException e )
{
getLogger().error( "Manifest is invalid: " + e.getMessage() );
throw new TaskException( "Invalid Manifest", e );
}
}
protected void zipFile( File file, ZipOutputStream zOut, String vPath )
throws IOException, TaskException
{
// If the file being added is META-INF/MANIFEST.MF, we warn if it's
not the
// one specified in the "manifest" attribute - or if it's being added
twice,
// meaning the same file is specified by the "manifeset" attribute
and in
// a <fileset> element.
if( vPath.equalsIgnoreCase( "META-INF/MANIFEST.MF" ) )
{
final String message = "Warning: selected " + m_archiveType +
" files include a META-INF/MANIFEST.MF which will be ignored
" +
"(please use manifest attribute to " + m_archiveType + "
task)";
getLogger().warn( message );
}
else
{
super.zipFile( file, zOut, vPath );
}
}
protected void zipFile( InputStream is, ZipOutputStream zOut, String
vPath, long lastModified )
throws IOException, TaskException
{
// If the file being added is META-INF/MANIFEST.MF, we merge it with
the
// current manifest
if( vPath.equalsIgnoreCase( "META-INF/MANIFEST.MF" ) )
{
try
{
zipManifestEntry( is );
}
catch( IOException e )
{
throw new TaskException( "Unable to read manifest file: ", e
);
}
}
else
{
super.zipFile( is, zOut, vPath, lastModified );
}
}
/**
* Create the index list to speed up classloading. This is a JDK 1.3+
* specific feature and is enabled by default. [EMAIL PROTECTED]
* http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index}
*
* @param zOut the zip stream representing the jar being built.
* @throws IOException thrown if there is an error while creating the
index
* and adding it to the zip stream.
*/
private void createIndexList( ZipOutputStream zOut )
throws IOException, TaskException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// encoding must be UTF8 as specified in the specs.
PrintWriter writer = new PrintWriter( new OutputStreamWriter( baos,
"UTF8" ) );
// version-info blankline
writer.println( "JarIndex-Version: 1.0" );
writer.println();
// header newline
writer.println( m_file.getName() );
// JarIndex is sorting the directories by ascending order.
// it's painful to do in JDK 1.1 and it has no value but cosmetic
// since it will be read into a hashtable by the classloader.
Enumeration enum = m_addedDirs.keys();
while( enum.hasMoreElements() )
{
String dir = (String)enum.nextElement();
// try to be smart, not to be fooled by a weird directory name
// @fixme do we need to check for directories starting by ./ ?
dir = dir.replace( '\\', '/' );
int pos = dir.lastIndexOf( '/' );
if( pos != -1 )
{
dir = dir.substring( 0, pos );
}
// looks like nothing from META-INF should be added
// and the check is not case insensitive.
// see sun.misc.JarIndex
if( dir.startsWith( "META-INF" ) )
{
continue;
}
// name newline
writer.println( dir );
}
writer.flush();
ByteArrayInputStream bais = new ByteArrayInputStream(
baos.toByteArray() );
super.zipFile( bais, zOut, INDEX_NAME, System.currentTimeMillis() );
}
/**
* Handle situation when we encounter a manifest file If we haven't been
* given one, we use this one. If we have, we merge the manifest in,
* provided it is a new file and not the old one from the JAR we are
* updating
*
* @param is Description of Parameter
* @exception IOException Description of Exception
*/
private void zipManifestEntry( InputStream is )
throws IOException, TaskException
{
try
{
if( m_execManifest == null )
{
m_execManifest = new Manifest( new InputStreamReader( is ) );
}
else if( isAddingNewFiles() )
{
m_execManifest.merge( new Manifest( new InputStreamReader( is
) ) );
}
}
catch( ManifestException e )
{
getLogger().error( "Manifest is invalid: " + e.getMessage() );
throw new TaskException( "Invalid Manifest", e );
}
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/Expand.java
Index: Expand.java
===================================================================
/*
* 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.archive;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.avalon.excalibur.io.FileUtil;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.api.TaskContext;
import org.apache.tools.ant.types.DirectoryScanner;
import org.apache.tools.ant.types.FileSet;
import org.apache.myrmidon.framework.PatternSet;
import org.apache.myrmidon.framework.PatternUtil;
import org.apache.tools.ant.types.ScannerUtil;
import org.apache.tools.ant.taskdefs.MatchingTask;
/**
* Unzip a file.
*
* @author [EMAIL PROTECTED]
* @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Magesh Umasankar</a>
*/
public class Expand extends MatchingTask
{// req
private boolean overwrite = true;
private ArrayList patternsets = new ArrayList();
private ArrayList filesets = new ArrayList();
private File dest;//req
private File source;
/**
* Set the destination directory. File will be unzipped into the
destination
* directory.
*
* @param d Path to the directory.
*/
public void setDest( File d )
{
this.dest = d;
}
/**
* Should we overwrite files in dest, even if they are newer than the
* corresponding entries in the archive?
*
* @param b The new Overwrite value
*/
public void setOverwrite( boolean b )
{
overwrite = b;
}
/**
* Set the path to zip-file.
*
* @param s Path to zip-file.
*/
public void setSrc( File s )
{
this.source = s;
}
/**
* Add a fileset
*
* @param set The feature to be added to the Fileset attribute
*/
public void addFileset( FileSet set )
{
filesets.add( set );
}
/**
* Add a patternset
*
* @param set The feature to be added to the Patternset attribute
*/
public void addPatternset( PatternSet set )
{
patternsets.add( set );
}
/**
* Do the work.
*
* @exception TaskException Thrown in unrecoverable error.
*/
public void execute()
throws TaskException
{
if( source == null && filesets.size() == 0 )
{
throw new TaskException( "src attribute and/or filesets must be
specified" );
}
if( dest == null )
{
throw new TaskException(
"Dest attribute must be specified" );
}
if( dest.exists() && !dest.isDirectory() )
{
throw new TaskException( "Dest must be a directory." );
}
if( source != null )
{
if( source.isDirectory() )
{
throw new TaskException( "Src must not be a directory." +
" Use nested filesets instead." );
}
else
{
expandFile( source, dest );
}
}
if( filesets.size() > 0 )
{
for( int j = 0; j < filesets.size(); j++ )
{
FileSet fs = (FileSet)filesets.get( j );
DirectoryScanner ds = ScannerUtil.getDirectoryScanner( fs );
File fromDir = fs.getDir();
String[] files = ds.getIncludedFiles();
for( int i = 0; i < files.length; ++i )
{
File file = new File( fromDir, files[ i ] );
expandFile( file, dest );
}
}
}
}
/*
* This method is to be overridden by extending unarchival tasks.
*/
protected void expandFile( File srcF, File dir )
throws TaskException
{
ZipInputStream zis = null;
try
{
// code from WarExpand
zis = new ZipInputStream( new FileInputStream( srcF ) );
ZipEntry ze = null;
while( ( ze = zis.getNextEntry() ) != null )
{
extractFile( srcF, dir, zis,
ze.getName(),
new Date( ze.getTime() ),
ze.isDirectory() );
}
getLogger().debug( "expand complete" );
}
catch( IOException ioe )
{
throw new TaskException( "Error while expanding " +
srcF.getPath(), ioe );
}
finally
{
if( zis != null )
{
try
{
zis.close();
}
catch( IOException e )
{
}
}
}
}
protected void extractFile( File srcF, File dir,
InputStream compressedInputStream,
String entryName,
Date entryDate, boolean isDirectory )
throws IOException, TaskException
{
if( patternsets != null && patternsets.size() > 0 )
{
String name = entryName;
boolean included = false;
for( int v = 0; v < patternsets.size(); v++ )
{
PatternSet p = (PatternSet)patternsets.get( v );
final TaskContext context = getContext();
String[] incls = PatternUtil.getIncludePatterns( p, context );
if( incls != null )
{
for( int w = 0; w < incls.length; w++ )
{
boolean isIncl = ScannerUtil.match( incls[ w ], name
);
if( isIncl )
{
included = true;
break;
}
}
}
final TaskContext context1 = getContext();
String[] excls = PatternUtil.getExcludePatterns( p, context1
);
if( excls != null )
{
for( int w = 0; w < excls.length; w++ )
{
boolean isExcl = ScannerUtil.match( excls[ w ], name
);
if( isExcl )
{
included = false;
break;
}
}
}
}
if( !included )
{
//Do not process this file
return;
}
}
File f = FileUtil.resolveFile( dir, entryName );
try
{
if( !overwrite && f.exists()
&& f.lastModified() >= entryDate.getTime() )
{
getLogger().debug( "Skipping " + f + " as it is up-to-date" );
return;
}
getLogger().debug( "expanding " + entryName + " to " + f );
// create intermediary directories - sometimes zip don't add them
File dirF = f.getParentFile();
dirF.mkdirs();
if( isDirectory )
{
f.mkdirs();
}
else
{
byte[] buffer = new byte[ 1024 ];
int length = 0;
FileOutputStream fos = null;
try
{
fos = new FileOutputStream( f );
while( ( length =
compressedInputStream.read( buffer ) ) >= 0 )
{
fos.write( buffer, 0, length );
}
fos.close();
fos = null;
}
finally
{
if( fos != null )
{
try
{
fos.close();
}
catch( IOException e )
{
}
}
}
}
f.setLastModified( entryDate.getTime() );
}
catch( FileNotFoundException ex )
{
getLogger().warn( "Unable to expand to file " + f.getPath() );
}
}
}
1.1
jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/archive/Ear.java
Index: Ear.java
===================================================================
/*
* 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.archive;
import java.io.File;
import java.io.IOException;
import org.apache.myrmidon.api.TaskException;
import org.apache.aut.zip.ZipOutputStream;
/**
* Creates a EAR archive. Based on WAR task
*
* @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Les Hughes</a>
*/
public class Ear
extends Jar
{
private File m_appxml;
private boolean m_descriptorAdded;
public Ear()
{
m_archiveType = "ear";
m_emptyBehavior = "create";
}
public void setAppxml( final File appxml )
throws TaskException
{
m_appxml = appxml;
if( !m_appxml.exists() )
{
final String message = "Deployment descriptor: " +
m_appxml + " does not exist.";
throw new TaskException( message );
}
addFileAs( m_appxml, "META-INF/application.xml" );
}
public void addArchives( ZipFileSet fs )
{
// We just set the prefix for this fileset, and pass it up.
// Do we need to do this? LH
getLogger().debug( "addArchives called" );
fs.setPrefix( "/" );
super.addFileset( fs );
}
protected void initZipOutputStream( final ZipOutputStream zOut )
throws IOException, TaskException
{
if( m_appxml == null && !isInUpdateMode() )
{
final String message = "appxml attribute is required";
throw new TaskException( message );
}
super.initZipOutputStream( zOut );
}
protected void zipFile( File file, ZipOutputStream zOut, String vPath )
throws IOException, TaskException
{
// If the file being added is WEB-INF/web.xml, we warn if it's not the
// one specified in the "webxml" attribute - or if it's being added
twice,
// meaning the same file is specified by the "webxml" attribute and in
// a <fileset> element.
if( vPath.equalsIgnoreCase( "META-INF/aplication.xml" ) )
{
if( m_appxml == null ||
!m_appxml.equals( file ) ||
m_descriptorAdded )
{
final String message = "Warning: selected " + m_archiveType +
" files include a META-INF/application.xml which will be
ignored " +
"(please use appxml attribute to " + m_archiveType + "
task)";
getLogger().warn( message );
}
else
{
super.zipFile( file, zOut, vPath );
m_descriptorAdded = true;
}
}
else
{
super.zipFile( file, zOut, vPath );
}
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>