ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dona...@apache.org
Subject cvs commit: jakarta-ant/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
Date Sun, 27 Jan 2002 10:07:16 GMT
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:peter@apache.org">Peter Donald</a>
    * @author Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
    * @author <a href="mailto:umagesh@rediffmail.com">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:don@bea.com">don@bea.com</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:don@bea.com">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:duncan@x180.com">duncan@x180.com</a>
   * @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a>
   * @author <a href="mailto:stefan.bodewig@epost.de">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:stefan.bodewig@epost.de">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:stefan.bodewig@epost.de">Stefan Bodewig</a>
   * @author <a href="mailto:umagesh@rediffmail.com">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:umagesh@apache.org">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:stefano@apache.org">
   *      stefano@apache.org</a>
   * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
   * @author <a href="mailto:umagesh@apache.org">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:duncan@x180.com">duncan@x180.com</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. {@link
       * 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 costin@dnt.ro
   * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
   * @author <a href="mailto:umagesh@rediffmail.com">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:stefan.bodewig@epost.de">Stefan Bodewig</a>
   * @author <a href="mailto:leslie.hughes@rubus.com">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:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message