You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by um...@apache.org on 2002/03/03 07:52:07 UTC

cvs commit: jakarta-ant/src/testcases/org/apache/tools/ant/taskdefs ZipTest.java

umagesh     02/03/02 22:52:07

  Modified:    .        WHATSNEW
               docs/manual/CoreTasks jar.html zip.html
               docs/manual/OptionalTasks jlink.html
               src/etc/testcases/taskdefs zip.xml
               src/main/org/apache/tools/ant/taskdefs Jar.java
                        Manifest.java Zip.java
               src/testcases/org/apache/tools/ant/taskdefs ZipTest.java
  Added:       src/etc/testcases/taskdefs/zip zipgroupfileset1.zip
                        zipgroupfileset2.zip zipgroupfileset3.zip
  Log:
  Zip task
  
  duplicate (attribute): behavior when a duplicate file is found.  Valid values are add, preserve, and fail. The default value is add.
  
  zipgroupfileset (nested fileset): allows for multiple zip files to be merged into the archive. Each file found in this fileset is added to the archive the same way that "zipfileset src" files are added.
  
  Jar task
  
  duplicate/zipgroupfileset: same as in Zip task
  
  filesetmanifest (attribute): behavior when a Manifest is found in a zipfileset or zipgroupfileset file is found.  Valid values are skip, merge, and mergewithoutmain.  mergewill merge all of manifests together, and merge this into any other specified manifests  mergewithoutmain merges everything but the Main section of the manifests.  Default value is skip
  
  manifest (existing attribute): this attribute now also accepts the name of a jar added through a fileset.  If its the name of an added jar, the task expects the manifest to be in the jar at META-INF/Manifest.mf
  
  Submitted by: Brian Deitte <bd...@macromedia.com>
  
  PR: 5667, 5036
  
  Revision  Changes    Path
  1.221     +7 -0      jakarta-ant/WHATSNEW
  
  Index: WHATSNEW
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/WHATSNEW,v
  retrieving revision 1.220
  retrieving revision 1.221
  diff -u -r1.220 -r1.221
  --- WHATSNEW	3 Mar 2002 01:30:03 -0000	1.220
  +++ WHATSNEW	3 Mar 2002 06:52:07 -0000	1.221
  @@ -77,6 +77,13 @@
   
   Other changes:
   --------------
  +* Users can control what <zip> and <jar> must do when duplicate files 
  +  are found.  A new element <zipgroupfileset> allows for multiple zip 
  +  files to be merged into the archive.  In addition, <jar> also has 
  +  another new attribute: filesetmanifest.  The existing manifest
  +  attribute of <jar> now also accepts the name of a jar added through 
  +  a fileset.
  +
   * gzip now checks that the zipfile is older than the source file
     before rebuilding the zipfile. 
   
  
  
  
  1.16      +26 -4     jakarta-ant/docs/manual/CoreTasks/jar.html
  
  Index: jar.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/CoreTasks/jar.html,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- jar.html	3 Feb 2002 22:00:42 -0000	1.15
  +++ jar.html	3 Mar 2002 06:52:07 -0000	1.16
  @@ -28,11 +28,12 @@
   <code>&lt;patternset&gt;</code> elements.</p>
   <p>You can also use nested file sets for more flexibility, and specify
   multiple ones to merge together different trees of files into one JAR.
  -The extended fileset attributes from the zip task are also available
  -in the jar task.
  +The extended fileset and groupfileset attributes from the zip task are
  +also available in the jar task.
   See the <a href="zip.html">Zip</a> task for more details and examples.</p>
   <p>If the manifest is omitted, a simple one will be supplied by Ant.
  -You should not include <samp>META-INF/MANIFEST.MF</samp> in your set of files.</p>
  +If there is a manifest or manifests in your set of files, these manifests can
  +be used if <i>filesetmanifests</i> is set to <i>merge</i> or <i>mergewithoutmain</i>.</p>
   <p>The <code>update</code> parameter controls what happens if the
   JAR file already exists. When set to <code>yes</code>, the JAR file is
   updated with the files specified. When set to <code>no</code> (the
  @@ -117,13 +118,34 @@
     </tr>
     <tr>
       <td valign="top">manifest</td>
  -    <td valign="top">the manifest file to use.</td>
  +    <td valign="top">the manifest file to use.  This can be either the location of a manifest, or the name of a jar added through a fileset.  If its the name of an added jar, the task expects the manifest to be in the jar at META-INF/MANIFEST.MF</td>
  +    <td valign="top" align="center">No</td>
  +  </tr>
  +  <tr>
  +    <td valign="top">filesetmanifest</td>
  +    <td valign="top">behavior when a Manifest is found in a zipfileset or zipgroupfileset file is found.  Valid values are &quot;skip&quot;, &quot;merge&quot;, and &quot;mergewithoutmain&quot;.  &quot;merge&quot; will merge all of manifests together, and merge this into any other specified manifests.  &quot;mergewithoutmain&quot; merges everything but the Main section of the manifests.  Default value is &quot;skip&quot;.
  +    </td>
       <td valign="top" align="center">No</td>
     </tr>
     <tr>
       <td valign="top">update</td>
       <td valign="top">indicates whether to update or overwrite
         the destination file if it already exists.</td>
  +    <td valign="top" align="center">No</td>
  +  </tr>
  +  <tr>
  +    <td valign="top">whenempty</td>
  +    <td valign="top">behavior when no files match.  Valid values are &quot;fail&quot;, &quot;skip&quot;, and &quot;create&quot;.  Default is &quot;skip&quot;.</td>
  +    <td valign="top" align="center">No</td>
  +  </tr>
  +  <tr>
  +    <td valign="top">duplicate</td>
  +    <td valign="top">behavior when a duplicate file is found.  Valid values are &quot;add&quot;, &quot;preserve&quot;, and &quot;fail&quot;.  The default value is &quot;add&quot;.  </td>
  +    <td valign="top" align="center">No</td>
  +  </tr>
  +  <tr>
  +    <td valign="top">index</td>
  +    <td valign="top">whether to create an <A HREF="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index">index list</A> to speed up classloading.  This is a JDK 1.3+ specific feature.  Defaults to false. </td>
       <td valign="top" align="center">No</td>
     </tr>
   </table>
  
  
  
  1.12      +25 -2     jakarta-ant/docs/manual/CoreTasks/zip.html
  
  Index: zip.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/CoreTasks/zip.html,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- zip.html	3 Feb 2002 22:00:42 -0000	1.11
  +++ zip.html	3 Mar 2002 06:52:07 -0000	1.12
  @@ -2,7 +2,7 @@
   
   <head>
   <meta http-equiv="Content-Language" content="en-us">
  -<title>AZip Task</title>
  +<title>Zip Task</title>
   </head>
   
   <body>
  @@ -33,6 +33,9 @@
   and optional subelements like <code>&lt;include&gt;</code>); explicit nested
   <code>&lt;fileset&gt;</code> elements so long as at least one fileset total is specified. The ZIP file will
   only reflect the relative paths of files <i>within</i> each fileset. The Zip task and its derivatives know a special form of a fileset named zipfileset that has additional attributes (described below). </p>
  +<p>The Zip task also supports the merging of multiple zip files into the zip file. 
  +This is possible through either the <i>src</i> attribute of any nested filesets 
  +or by using the special nested fileset <i>zipgroupfileset</i>.</p>
   <p>The <code>update</code> parameter controls what happens if the
   ZIP file already exists. When set to <code>yes</code>, the ZIP file is
   updated with the files specified. (New files are added; old files are
  @@ -122,7 +125,12 @@
     </tr>
     <tr>
       <td valign="top">whenempty</td>
  -    <td valign="top">Behavior when no files match.</td>
  +    <td valign="top">behavior when no files match.  Valid values are &quot;fail&quot;, &quot;skip&quot;, and &quot;create&quot;.  Default is &quot;skip&quot;.</td>
  +    <td valign="top" align="center">No</td>
  +  </tr>
  +  <tr>
  +    <td valign="top">duplicate</td>
  +    <td valign="top">behavior when a duplicate file is found.  Valid values are &quot;add&quot;, &quot;preserve&quot;, and &quot;fail&quot;. The default value is &quot;add&quot;.  </td>
       <td valign="top" align="center">No</td>
     </tr>
   </table>
  @@ -140,6 +148,11 @@
   may be used in place of the <i>dir</i> attribute to specify a zip file whose
   contents will be extracted and included in the archive.  As with directories, include and exclude patterns may be used to specify a subset of the zip file
   for inclusion in the archive.</p>
  +<h4>zipgroupfileset</h4>
  +<p>A <code>&lt;zipgroupfileset&gt;</code> allows for multiple zip files to be 
  +merged into the archive. Each file found in this fileset is added to the archive 
  +the same way that <i>zipfileset src</i> files are added.</p>
  +
   
   <h3>Examples</h3>
   <pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;
  @@ -188,6 +201,16 @@
       docs/ChangeLog.txt
       docs/examples/index.html
   </code></pre>
  +<p>
  +The code
  +<pre>
  +  &lt;zip destfile=&quot;${dist}/manual.zip&quot;&gt;
  +    &lt;zipfileset dir=&quot;htdocs/manual&quot; prefix=&quot;docs/user-guide&quot;/&gt;
  +    &lt;zipgroupfileset dir=&quot;.&quot; includes=&quot;examples*.zip&quot;/&gt;
  +  &lt;/zip&gt;</pre>
  +</pre>
  +<p>
  +<p>zips all files in the <code>htdocs/manual</code> directory into the <code>docs/user-guide</code> directory in the archive and includes all the files in any file that maches <code>examples*.zip</code>, such as all files within <code>examples1.zip</code> or <code>examples_for_brian.zip</code>.
   <hr>
   <p align="center">Copyright &copy; 2001-2002 Apache Software Foundation. All rights
   Reserved.</p>
  
  
  
  1.5       +3 -0      jakarta-ant/docs/manual/OptionalTasks/jlink.html
  
  Index: jlink.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/manual/OptionalTasks/jlink.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- jlink.html	3 Feb 2002 22:09:09 -0000	1.4
  +++ jlink.html	3 Mar 2002 06:52:07 -0000	1.5
  @@ -5,6 +5,9 @@
   <body>
   
   <h2><a name="jlink">Jlink</a></h2>
  +<h3><i>Deprecated</i></h3>
  +<p><i>This task has been deprecated. Use the zipfileset and zipgroupfileset attributes of the <a href="../CoreTasks/jar.html">Jar task</a> or <a href="../CoreTasks/zip.html">Zip task</a> instead.</i></p>
  +
   <h3><b>Description:</b></h3>
   <p>Links entries from sub-builds and libraries.</p>
   
  
  
  
  1.8       +20 -2     jakarta-ant/src/etc/testcases/taskdefs/zip.xml
  
  Index: zip.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/etc/testcases/taskdefs/zip.xml,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- zip.xml	8 Jan 2002 09:46:26 -0000	1.7
  +++ zip.xml	3 Mar 2002 06:52:07 -0000	1.8
  @@ -49,7 +49,7 @@
     </target>
   
     <target name="feather">
  -    <zip destFile="asf-logo.gif.zip" 
  +    <zip destFile="asf-logo.gif.zip"
            basedir=".."
            includes="asf-logo.gif" />
     </target>
  @@ -60,7 +60,24 @@
         <exclude name="test8.zip" />
       </zip>
     </target>
  -  
  +
  +  <target name="testZipgroupfileset">
  +
  +    <zip zipfile="zipgroupfileset.zip" basedir=".">
  +      <zipgroupfileset dir="zip" 
  +        includes="zipgroupfileset*.zip" 
  +        excludes="zipgroupfileset3.zip" />
  +      <include name="zip/zipgroupfileset3.zip" />
  +    </zip>
  +  </target>
  +
  +  <target name="testDuplicateFail">
  +
  +    <zip zipfile="duplicateFail.zip" basedir="." duplicate="fail">
  +      <zipgroupfileset dir="duplicate" includes="duplicate*.zip" />
  +    </zip>
  +  </target>
  +
     <target name="cleanup">
       <delete file="test3.zip"/>
       <delete file="test4.zip"/>
  @@ -70,5 +87,6 @@
       <delete file="test7.zip"/>
       <delete file="test8.zip"/>
       <delete file="asf-logo.gif.zip"/>
  +    <delete file="zipgroupfileset.zip"/>
     </target>
   </project>
  
  
  
  1.1                  jakarta-ant/src/etc/testcases/taskdefs/zip/zipgroupfileset1.zip
  
  	<<Binary file>>
  
  
  1.1                  jakarta-ant/src/etc/testcases/taskdefs/zip/zipgroupfileset2.zip
  
  	<<Binary file>>
  
  
  1.1                  jakarta-ant/src/etc/testcases/taskdefs/zip/zipgroupfileset3.zip
  
  	<<Binary file>>
  
  
  1.38      +176 -90   jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Jar.java
  
  Index: Jar.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Jar.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- Jar.java	3 Mar 2002 01:46:20 -0000	1.37
  +++ Jar.java	3 Mar 2002 06:52:07 -0000	1.38
  @@ -1,7 +1,7 @@
   /*
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights 
  + * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -9,7 +9,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -17,15 +17,15 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:  
  - *       "This product includes software developed by the 
  + *    any, must include the following acknowlegement:
  + *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
    *    Alternately, this acknowlegement may appear in the software itself,
    *    if and wherever such third-party acknowlegements normally appear.
    *
    * 4. The names "The Jakarta Project", "Ant", and "Apache Software
    *    Foundation" must not be used to endorse or promote products derived
  - *    from this software without prior written permission. For written 
  + *    from this software without prior written permission. For written
    *    permission, please contact apache@apache.org.
    *
    * 5. Products derived from this software may not be called "Apache"
  @@ -58,6 +58,7 @@
   import org.apache.tools.ant.FileScanner;
   import org.apache.tools.ant.Project;
   import org.apache.tools.ant.types.ZipFileSet;
  +import org.apache.tools.ant.types.EnumeratedAttribute;
   import org.apache.tools.zip.ZipOutputStream;
   
   import java.io.IOException;
  @@ -75,8 +76,9 @@
   
   /**
    * Creates a JAR archive.
  - * 
  + *
    * @author James Davidson <a href="mailto:duncan@x180.com">duncan@x180.com</a>
  + * @author Brian Deitte <a href="mailto:bdeitte@macromedia.com">bdeitte@macromedia.com</a>
    *
    * @ant.task category="packaging"
    */
  @@ -84,12 +86,33 @@
       /** The index file name. */
       private final static String INDEX_NAME = "META-INF/INDEX.LIST";
   
  -    private File manifestFile;
  +    /** merged manifests added through addConfiguredManifest */
  +    private Manifest configuredManifest;
  +
  +    /**  merged manifests added through filesets */
  +    private Manifest filesetManifest;
  +
  +    /**
  +     *  whether to merge fileset manifests;
  +     *  value is true if filesetmanifest is 'merge' or 'mergewithoutmain'
  +     */
  +    private boolean mergeManifests = false;
  +
  +    /**
  +     * whether to merge the main section of fileset manifests;
  +     * value is true if filesetmanifest is 'merge'
  +     */
  +    private boolean mergeManifestsMain = false;
  +
  +    /** the manifest specified by the 'manifest' attribute **/
       private Manifest manifest;
  -    private Manifest execManifest;  
  -    
  -    /** true if a manifest has been specified in the task */
  -    private boolean buildFileManifest = false;
  +
  +    /**
  +     * The file found from the 'manifest' attribute.  This can be either the location of a manifest,
  +     * or the name of a jar added through a fileset.  If its the name of an added jar, the manifest is
  +     * looked for in META-INF/MANIFEST.MF
  +     */
  +    private File manifestFile;
   
       /** jar index is JDK 1.3+ only */
       private boolean index = false;
  @@ -124,33 +147,30 @@
       }
   
       public void addConfiguredManifest(Manifest newManifest) throws ManifestException {
  -        if (manifest == null) {
  -            manifest = Manifest.getDefaultManifest();
  +        if (configuredManifest == null) {
  +            configuredManifest = newManifest;
  +        }
  +        else {
  +            configuredManifest.merge(newManifest);
           }
  -        manifest.merge(newManifest);
  -        buildFileManifest = true;
       }
  -    
  +
       public void setManifest(File manifestFile) {
           if (!manifestFile.exists()) {
  -            throw new BuildException("Manifest file: " + manifestFile + " does not exist.", 
  +            throw new BuildException("Manifest file: " + manifestFile + " does not exist.",
                                        getLocation());
           }
   
           this.manifestFile = manifestFile;
  -        
  +    }
  +
  +    private Manifest getManifest(File manifestFile) {
  +
  +        Manifest newManifest = null;
           Reader r = null;
           try {
               r = new FileReader(manifestFile);
  -            Manifest newManifest = new Manifest(r);
  -            if (manifest == null) {
  -                manifest = Manifest.getDefaultManifest();
  -            }
  -            manifest.merge(newManifest);
  -        }
  -        catch (ManifestException e) {
  -            log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  -            throw new BuildException("Invalid Manifest: " + manifestFile, e, getLocation());
  +            newManifest = getManifest(r);
           }
           catch (IOException e) {
               throw new BuildException("Unable to read manifest file: " + manifestFile, e);
  @@ -165,6 +185,29 @@
                   }
               }
           }
  +        return newManifest;
  +    }
  +
  +    private Manifest getManifest(Reader r) {
  +
  +        Manifest newManifest = null;
  +        try {
  +            newManifest = new Manifest(r);
  +        }
  +        catch (ManifestException e) {
  +            log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  +            throw new BuildException("Invalid Manifest: " + manifestFile, e, getLocation());
  +        }
  +        catch (IOException e) {
  +            throw new BuildException("Unable to read manifest file", e);
  +        }
  +        return newManifest;
  +    }
  +
  +    public void setFilesetmanifest(FilesetManifestConfig config) {
  +        String filesetManifestConfig = config.getValue();
  +        mergeManifests = ! "skip".equals(filesetManifestConfig);
  +        mergeManifestsMain = "merge".equals(filesetManifestConfig);
       }
   
       public void addMetainf(ZipFileSet fs) {
  @@ -176,31 +219,60 @@
       protected void initZipOutputStream(ZipOutputStream zOut)
           throws IOException, BuildException
       {
  +        String ls = System.getProperty("line.separator");
           try {
  -            execManifest = Manifest.getDefaultManifest();
  +            Manifest finalManifest = Manifest.getDefaultManifest();
   
  -            if (manifest != null) {
  -                execManifest.merge(manifest);
  +            if (manifest == null) {
  +                if (manifestFile != null) {
  +                    // if we haven't got the manifest yet, attempt to get it now and
  +                    // have manifest be the final merge
  +                    manifest = getManifest(manifestFile);
  +                    finalManifest.merge(filesetManifest);
  +                    finalManifest.merge(configuredManifest);
  +                    finalManifest.merge(manifest, ! mergeManifestsMain);
  +                }
  +                else if (configuredManifest != null) {
  +                    // configuredManifest is the final merge
  +                    finalManifest.merge(filesetManifest);
  +                    finalManifest.merge(configuredManifest, ! mergeManifestsMain);
  +                }
  +                else if (filesetManifest != null) {
  +                    // filesetManifest is the final (and only) merge
  +                    finalManifest.merge(filesetManifest, ! mergeManifestsMain);
  +                }
  +            } else {
  +                // manifest is the final merge
  +                finalManifest.merge(filesetManifest);
  +                finalManifest.merge(configuredManifest);
  +                finalManifest.merge(manifest, ! mergeManifestsMain);
               }
  -            for (Enumeration e = execManifest.getWarnings(); e.hasMoreElements(); ) {
  +
  +            for (Enumeration e = finalManifest.getWarnings(); e.hasMoreElements(); ) {
                   log("Manifest warning: " + (String)e.nextElement(), Project.MSG_WARN);
               }
  -        
  +
  +            // need to set the line.separator as \r\n due to a bug with the jar verifier
  +            System.setProperty("line.separator", "\r\n");
  +
               zipDir(null, zOut, "META-INF/");
               // time to write the manifest
               ByteArrayOutputStream baos = new ByteArrayOutputStream();
               PrintWriter writer = new PrintWriter(baos);
  -            execManifest.write(writer);
  +            finalManifest.write(writer);
               writer.flush();
  -        
  +
               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  -            super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis());
  +            super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis(), null);
               super.initZipOutputStream(zOut);
           }
           catch (ManifestException e) {
               log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
               throw new BuildException("Invalid Manifest", e, getLocation());
           }
  +        finally {
  +            System.setProperty("line.separator", ls);
  +        }
       }
   
       protected void finalizeZipOutputStream(ZipOutputStream zOut)
  @@ -212,14 +284,11 @@
   
       /**
        * Create the index list to speed up classloading.
  -     * This is a JDK 1.3+ specific feature and is enabled by default. See
  -     * <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR+Index">the
  -     * JAR index specification</a> for more details.
  -     * 
  +     * This is a JDK 1.3+ specific feature and is disabled 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 {
           ByteArrayOutputStream baos = new ByteArrayOutputStream();
  @@ -260,70 +329,73 @@
   
           writer.flush();
           ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  -        super.zipFile(bais, zOut, INDEX_NAME, System.currentTimeMillis());
  +        super.zipFile(bais, zOut, INDEX_NAME, System.currentTimeMillis(), null);
       }
   
  -
  -
  -
       /**
  -     * 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
  +     * Overriden from Zip class to deal with manifests
        */
  -    private void zipManifestEntry(InputStream is) throws IOException {
  -        try {
  -            if (execManifest == null) {
  -                execManifest = new Manifest(new InputStreamReader(is));
  -            }
  -            else if (isAddingNewFiles()) {
  -                execManifest.merge(new Manifest(new InputStreamReader(is)));
  -            }
  -        }
  -        catch (ManifestException e) {
  -            log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
  -            throw new BuildException("Invalid Manifest", e, getLocation());
  -        }
  -    }
  -    
       protected void zipFile(File file, ZipOutputStream zOut, String vPath)
           throws IOException
       {
  -        // 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"))  {
  -            log("Warning: selected "+archiveType+" files include a META-INF/MANIFEST.MF which will be ignored " +
  -                "(please use manifest attribute to "+archiveType+" task)", Project.MSG_WARN);
  +            filesetManifest(file, null);
           } else {
               super.zipFile(file, zOut, vPath);
           }
  -
       }
   
  -    protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, long lastModified)
  +    /**
  +     * Overriden from Zip class to deal with manifests
  +     */
  +    protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, long lastModified, File file)
           throws IOException
       {
  -        // 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);
  +            filesetManifest(file, is);
  +        } else {
  +            super.zipFile(is, zOut, vPath, lastModified, null);
  +        }
  +    }
  +
  +    private void filesetManifest(File file, InputStream is) {
  +        if (manifestFile.equals(file)) {
  +            // If this is the same name specified in 'manifest', this is the manifest to use
  +            log("Found manifest " + file, Project.MSG_VERBOSE);
  +            if (is != null) {
  +                manifest = getManifest(new InputStreamReader(is));
               }
  -            catch (IOException e) {
  -                throw new BuildException("Unable to read manifest file: ", e);
  +            else {
  +                manifest = getManifest(file);
  +            }
  +        }
  +        else if (mergeManifests) {
  +            // we add this to our group of fileset manifests
  +            log("Found manifest to merge in file " + file, Project.MSG_VERBOSE);
  +
  +            try
  +            {
  +                Manifest newManifest = getManifest(new InputStreamReader(is));
  +                if (filesetManifest == null) {
  +                    filesetManifest = newManifest;
  +                } else {
  +                    filesetManifest.merge(newManifest);
  +                }
  +            }
  +            catch (ManifestException e) {
  +                log("Manifest in file " + file + " is invalid: " + e.getMessage(), Project.MSG_ERR);
  +                throw new BuildException("Invalid Manifest", e, getLocation());
               }
  -        } else {
  -            super.zipFile(is, zOut, vPath, lastModified);
  +        }
  +        else {
  +            // assuming 'skip' otherwise
  +            log("File " + file + " includes a META-INF/MANIFEST.MF which will be ignored. " +
  +                "To include this file, set filesetManifest to a value other than 'skip'.", Project.MSG_WARN);
           }
       }
   
       /**
  -     * Check whether the archive is up-to-date; 
  +     * 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
  @@ -332,7 +404,7 @@
        */
       protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException {
           // need to handle manifest as a special check
  -        if (buildFileManifest || manifestFile == null) {
  +        if (configuredManifest != null || manifestFile == null) {
               java.util.zip.ZipFile theZipFile = null;
               try {
                   theZipFile = new java.util.zip.ZipFile(zipFile);
  @@ -342,17 +414,17 @@
                       return false;
                   }
                   Manifest currentManifest = new Manifest(new InputStreamReader(theZipFile.getInputStream(entry)));
  -                if (manifest == null) {
  -                    manifest = Manifest.getDefaultManifest();
  +                if (configuredManifest == null) {
  +                     configuredManifest = Manifest.getDefaultManifest();
                   }
  -                if (!currentManifest.equals(manifest)) {
  +                if (!currentManifest.equals(configuredManifest)) {
                       log("Updating jar since jar manifest has changed", Project.MSG_VERBOSE);
                       return false;
                   }
               }
               catch (Exception e) {
                   // any problems and we will rebuild
  -                log("Updating jar since cannot read current jar manifest: " + e.getClass().getName() + e.getMessage(), 
  +                log("Updating jar since cannot read current jar manifest: " + e.getClass().getName() + e.getMessage(),
                       Project.MSG_VERBOSE);
                   return false;
               }
  @@ -372,17 +444,31 @@
           }
           return super.isUpToDate(scanners, zipFile);
       }
  -        
  +
       protected boolean createEmptyZip(File zipFile) {
  -        // Jar files always contain a manifest and can never be empty        
  +        // Jar files always contain a manifest and can never be empty
           return true;
       }
  -    
  +
       /**
        * Make sure we don't think we already have a MANIFEST next time this task
        * gets executed.
        */
       protected void cleanUp() {
           super.cleanUp();
  +
  +        configuredManifest = null;
  +        filesetManifest = null;
  +        mergeManifests = false;
  +        mergeManifestsMain = false;
  +        manifest = null;
  +        manifestFile = null;
  +        index = false;
  +    }
  +
  +    public static class FilesetManifestConfig extends EnumeratedAttribute {
  +        public String[] getValues() {
  +            return new String[] {"skip", "merge", "mergewithoutmain"};
  +        }
       }
   }
  
  
  
  1.21      +48 -25    jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Manifest.java
  
  Index: Manifest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Manifest.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- Manifest.java	3 Mar 2002 01:46:20 -0000	1.20
  +++ Manifest.java	3 Mar 2002 06:52:07 -0000	1.21
  @@ -397,14 +397,14 @@
            * Get a attribute of the section
            *
            * @param attributeName the name of the attribute
  -         * @return a Manifest.Attribute instance if the attribute is 
  -         *         single-valued, otherwise a Vector of Manifest.Attribute 
  +         * @return a Manifest.Attribute instance if the attribute is
  +         *         single-valued, otherwise a Vector of Manifest.Attribute
            *         instances.
            */
           public Object getAttribute(String attributeName) {
               return attributes.get(attributeName.toLowerCase());
           }
  -        
  +
           /**
            * Get the value of the attribute with the name given.
            *
  @@ -511,8 +511,8 @@
               for (Enumeration e = attributes.keys(); e.hasMoreElements();) {
                   String attributeName = (String)e.nextElement();
                   Object attributeValue  = attributes.get(attributeName);
  -                Object rhsAttributeValue = rhsSection.attributes.get(attributeName);
  -                if (!attributeValue.equals(rhsAttributeValue)) {
  +                Object rshAttributeValue = rhsSection.attributes.get(attributeName);
  +                if (!attributeValue.equals(rshAttributeValue)) {
                       return false;
                   }
               }
  @@ -629,22 +629,45 @@
        *         to the Manifest spec.
        */
       public void merge(Manifest other) throws ManifestException {
  -        if (other.manifestVersion != null) {
  -            manifestVersion = other.manifestVersion;
  -        }
  -        mainSection.merge(other.mainSection);
  -        for (Enumeration e = other.sections.keys(); e.hasMoreElements();) {
  -            String sectionName = (String)e.nextElement();
  -            Section ourSection = (Section)sections.get(sectionName);
  -            Section otherSection = (Section)other.sections.get(sectionName);
  -            if (ourSection == null) {
  -                sections.put(sectionName, otherSection);
  -            }
  -            else {
  -                ourSection.merge(otherSection);
  -            }
  -        }
  +        merge(other, false);
  +    }
   
  +    /**
  +     * Merge the contents of the given manifest into this manifest
  +     *
  +     * @param other the Manifest to be merged with this one.
  +     * @param overwriteMain whether to overwrite the main section of the current manifest
  +     *
  +     * @throws ManifestException if there is a problem merging the manfest according
  +     *         to the Manifest spec.
  +     */
  +    public void merge(Manifest other, boolean overwriteMain) throws ManifestException {
  +        if (other != null) {
  +             if (overwriteMain) {
  +                 mainSection = other.mainSection;
  +             }
  +             else {
  +                 mainSection.merge(other.mainSection);
  +             }
  +
  +             if (other.manifestVersion != null) {
  +                 manifestVersion = other.manifestVersion;
  +             }
  +
  +             for (Enumeration e = other.sections.keys(); e.hasMoreElements();) {
  +                 String sectionName = (String)e.nextElement();
  +                 Section ourSection = (Section)sections.get(sectionName);
  +                 Section otherSection = (Section)other.sections.get(sectionName);
  +                 if (ourSection == null) {
  +                     if (otherSection != null) {
  +                         sections.put(sectionName.toLowerCase(), otherSection);
  +                     }
  +                 }
  +                 else {
  +                     ourSection.merge(otherSection);
  +                 }
  +             }
  +         }
       }
   
       /**
  @@ -774,7 +797,7 @@
       public String getManifestVersion() {
           return manifestVersion;
       }
  -    
  +
       /**
        * Get the main section of the manifest
        *
  @@ -788,13 +811,13 @@
        * Get a particular section from the manifest
        *
        * @param name the name of the section desired.
  -     * @return the specified section or null if that section 
  +     * @return the specified section or null if that section
        * does not exist in the manifest
        */
       public Section getSection(String name) {
           return (Section)sections.get(name);
       }
  -    
  +
       /**
        * Get the section names in this manifest.
        *
  @@ -803,7 +826,7 @@
       public Enumeration getSectionNames() {
           return sections.keys();
       }
  -    
  +
       /**
        * Create or update the Manifest when used as a task.
        */
  @@ -833,7 +856,7 @@
                   }
               }
           }
  -        
  +
           try {
               toWrite.merge(this);
           } catch (ManifestException m) {
  
  
  
  1.69      +92 -16    jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Zip.java
  
  Index: Zip.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Zip.java,v
  retrieving revision 1.68
  retrieving revision 1.69
  diff -u -r1.68 -r1.69
  --- Zip.java	3 Mar 2002 01:46:20 -0000	1.68
  +++ Zip.java	3 Mar 2002 06:52:07 -0000	1.69
  @@ -61,8 +61,6 @@
   import java.io.OutputStream;
   import java.io.ByteArrayOutputStream;
   import java.io.ByteArrayInputStream;
  -
  -import java.util.Calendar;
   import java.util.Hashtable;
   import java.util.Stack;
   import java.util.Vector;
  @@ -96,6 +94,9 @@
   
       protected File zipFile;
       private File baseDir;
  +    protected Hashtable entries = new Hashtable();
  +    private Vector groupfilesets = new Vector();
  +    protected String duplicate = "add";
       private boolean doCompress = true;
       private boolean doUpdate = false;
       private boolean doFilesonly = false;
  @@ -112,7 +113,6 @@
           adding back the unchanged files */
       private boolean addingNewFiles;
   
  -
       /**
        * Encoding to use for filenames, defaults to the platform's
        * default encoding.
  @@ -152,7 +152,7 @@
          this.zipFile = destFile;
       }
   
  -        
  +
       /**
        * This is the base directory to look in for
        * things to zip.
  @@ -205,6 +205,24 @@
           filesets.addElement(set);
       }
   
  +    /**
  +     * Adds a group of zip files (a group of nested filesets).
  +     */
  +    public void addZipGroupFileset(FileSet set) {
  +        groupfilesets.addElement(set);
  +    }
  +
  +    /**
  +     * Sets behavior for when a duplicate file is about to be added
  +     * Possible values are: <code>keep</code> (keep both
  +     * of the files); <code>skip</code> (keep the first version
  +     * of the file found); <code>overwrite</code> overwrite the file
  +     * with the new file
  +     * Default for zip tasks is <code>keep</code>
  +     */
  +    public void setDuplicate(Duplicate df) {
  +        duplicate = df.getValue();
  +    }
   
       /** Possible behaviors when there are no matching files for the task. */
       public static class WhenEmpty extends EnumeratedAttribute {
  @@ -238,7 +256,8 @@
       }
   
       public void execute() throws BuildException {
  -        if (baseDir == null && filesets.size() == 0 && "zip".equals(archiveType)) {
  +        if (baseDir == null && filesets.size() == 0
  +                && groupfilesets.size() == 0 && "zip".equals(archiveType)) {
               throw new BuildException( "basedir attribute must be set, or at least " +
                                         "one fileset must be given!" );
           }
  @@ -272,6 +291,23 @@
               }
           }
   
  +        // Add the files found in groupfileset to fileset
  +        for (int i=0; i<groupfilesets.size(); i++) {
  +
  +            log("Processing groupfileset ", Project.MSG_VERBOSE);
  +            FileSet fs = (FileSet) groupfilesets.elementAt(i);
  +            FileScanner scanner = fs.getDirectoryScanner(project);
  +            String[] files = scanner.getIncludedFiles();
  +            File basedir = scanner.getBasedir();
  +            for (int j=0; j<files.length; j++) {
  +
  +                log("Adding file " + files[j] + " to fileset", Project.MSG_VERBOSE);
  +                ZipFileSet zf = new ZipFileSet();
  +                zf.setSrc(new File(basedir, files[j]));
  +                filesets.add(zf);
  +            }
  +        }
  +
           // Create the scanners to pass to isUpToDate().
           Vector dss = new Vector ();
           if (baseDir != null) {
  @@ -333,7 +369,7 @@
                       addFiles(tmp, zOut);
                   }
                   finalizeZipOutputStream(zOut);
  -                
  +
                   // If we've been successful on an update, delete the temporary file
                   if (doUpdate) {
                       if (!renamedFile.delete()) {
  @@ -360,8 +396,8 @@
                       }
                   }
               }
  -        } catch (Throwable t) {
  -            String msg = "Problem creating " + archiveType + ": " + t.getMessage();
  +        } catch (IOException ioe) {
  +            String msg = "Problem creating " + archiveType + ": " + ioe.getMessage();
   
               // delete a bogus ZIP file
               if (!zipFile.delete()) {
  @@ -375,7 +411,7 @@
                   }
               }
   
  -            throw new BuildException(msg, t, location);
  +            throw new BuildException(msg, ioe, location);
           } finally {
               cleanUp();
           }
  @@ -446,6 +482,8 @@
                                    ZipOutputStream zOut, String prefix, String fullpath)
           throws IOException
       {
  +        log("adding zip entries: " + fullpath, Project.MSG_VERBOSE);
  +
           if (prefix.length() > 0 && fullpath.length() > 0) {
               throw new BuildException("Both prefix and fullpath attributes may not be set on the same fileset.");
           }
  @@ -465,11 +503,11 @@
                   if (zipScanner.match(vPath)) {
                       if (fullpath.length() > 0) {
                           addParentDirs(null, fullpath, zOut, "");
  -                        zipFile(in, zOut, fullpath, entry.getTime());
  +                        zipFile(in, zOut, fullpath, entry.getTime(), zipSrc);
                       } else {
                           addParentDirs(null, vPath, zOut, prefix);
                           if (! entry.isDirectory()) {
  -                            zipFile(in, zOut, prefix+vPath, entry.getTime());
  +                            zipFile(in, zOut, prefix+vPath, entry.getTime(), zipSrc);
                           }
                       }
                   }
  @@ -608,6 +646,8 @@
               // no warning if we try, it is harmless in and of itself
               return;
           }
  +
  +        log("adding directory " + vPath, Project.MSG_VERBOSE);
           addedDirs.put(vPath, vPath);
   
           ZipEntry ze = new ZipEntry (vPath);
  @@ -628,9 +668,33 @@
       }
   
       protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath,
  -                           long lastModified)
  +                           long lastModified, File file)
           throws IOException
       {
  +        if (entries.contains(vPath)) {
  +
  +            if (duplicate.equals("preserve"))
  +            {
  +                log(vPath + " already added, skipping", Project.MSG_INFO);
  +                return;
  +            }
  +            else if (duplicate.equals("fail"))
  +            {
  +                throw new BuildException("Duplicate file " + vPath + " was found and the duplicate attribute is 'fail'.");
  +            }
  +            else
  +            {
  +                // duplicate equal to add, so we continue
  +                log("duplicate file " + vPath + " found, adding.", Project.MSG_VERBOSE);
  +            }
  +        }
  +        else
  +        {
  +            log("adding entry " + vPath, Project.MSG_VERBOSE);
  +        }
  +
  +        entries.put(vPath, vPath);
  +
           ZipEntry ze = new ZipEntry(vPath);
           ze.setTime(lastModified);
   
  @@ -698,7 +762,7 @@
   
           FileInputStream fIn = new FileInputStream(file);
           try {
  -            zipFile(fIn, zOut, vPath, file.lastModified());
  +            zipFile(fIn, zOut, vPath, file.lastModified(), null);
           } finally {
               fIn.close();
           }
  @@ -787,15 +851,27 @@
        * need to do is to reset some globals.</p>
        */
       protected void cleanUp() {
  -        addedDirs = new Hashtable();
  -        addedFiles = new Vector();
  -        filesets = new Vector();
  +        addedDirs.clear();
  +        addedFiles.clear();
  +        filesets.clear();
           zipFile = null;
           baseDir = null;
  +        entries.clear();
  +        groupfilesets.clear();
  +        duplicate = "add";
  +        archiveType = "zip";
           doCompress = true;
  +        emptyBehavior = "skip";
           doUpdate = false;
           doFilesonly = false;
           addingNewFiles = false;
           encoding = null;
  +    }
  +
  +    /** Possible behaviors when a duplicate file is added. */
  +    public static class Duplicate extends EnumeratedAttribute {
  +        public String[] getValues() {
  +            return new String[] {"add", "preserve", "fail"};
  +        }
       }
   }
  
  
  
  1.8       +40 -20    jakarta-ant/src/testcases/org/apache/tools/ant/taskdefs/ZipTest.java
  
  Index: ZipTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/testcases/org/apache/tools/ant/taskdefs/ZipTest.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ZipTest.java	10 Jan 2002 10:13:12 -0000	1.7
  +++ ZipTest.java	3 Mar 2002 06:52:07 -0000	1.8
  @@ -55,54 +55,74 @@
   package org.apache.tools.ant.taskdefs;
   import org.apache.tools.ant.BuildFileTest;
   
  +import java.io.File;
  +import java.io.IOException;
  +import java.util.zip.ZipFile;
  +import java.util.Enumeration;
  +
   /**
  - * @author Nico Seessle <ni...@seessle.de> 
  + * @author Nico Seessle <ni...@seessle.de>
    */
  -public class ZipTest extends BuildFileTest { 
  -    
  -    public ZipTest(String name) { 
  +public class ZipTest extends BuildFileTest {
  +
  +    public ZipTest(String name) {
           super(name);
  -    }    
  -    
  -    public void setUp() { 
  +    }
  +
  +    public void setUp() {
           configureProject("src/etc/testcases/taskdefs/zip.xml");
       }
  -    
  -    public void test1() { 
  +
  +    public void test1() {
           expectBuildException("test1", "required argument not specified");
       }
   
  -    public void test2() { 
  +    public void test2() {
           expectBuildException("test2", "required argument not specified");
       }
  -    
  -    public void test3() { 
  +
  +    public void test3() {
           expectBuildException("test3", "zip cannot include itself");
       }
   
  -    public void test4() { 
  +    public void test4() {
           expectBuildException("test4", "zip cannot include itself");
       }
  -    
  +
       public void tearDown() {
           executeTarget("cleanup");
       }
  -    
  -    public void test5() { 
  +
  +    public void test5() {
           executeTarget("test5");
       }
   
   
  -    public void test6() { 
  +    public void test6() {
           executeTarget("test6");
       }
   
   
  -    public void test7() { 
  +    public void test7() {
           executeTarget("test7");
       }
   
  -    public void test8() { 
  +    public void test8() {
           executeTarget("test8");
  -    }    
  +    }
  +
  +    public void testZipgroupfileset() throws IOException {
  +        executeTarget("testZipgroupfileset");
  +
  +        ZipFile zipFile = new ZipFile(new File(getProjectDir(), "zipgroupfileset.zip"));
  +
  +        assert(zipFile.getEntry("ant.xml") != null);
  +        assert(zipFile.getEntry("optional/jspc.xml") != null);
  +        assert(zipFile.getEntry("zip/zipgroupfileset3.zip") != null);
  +
  +        assert(zipFile.getEntry("test6.mf") == null);
  +        assert(zipFile.getEntry("test7.mf") == null);
  +
  +        zipFile.close();
  +    }
   }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>