The attached patch should fix several things with the Zip and Jar tasks:

1. Directories are now included in the archive as needed (all parent
dirs for specified files). These are stored in STORED mode like other
zip and jar tools do. I'm not sure if officially directories are
required or not, but anyway everyone else stores them and sometimes code
assumes they are there.

2. Jar task will now rebuild the JAR if it is out of date with respect
to the manifest (assuming you specified a manifest).

3. Zip task will now try to create a ZIP archive when no files matched.
In fact, this will cause a BuildException, stating that you are trying
to make an empty ZIP (I don't know if this should be possible, but
anyway java.util.zip.* currently won't let you). Previously the task
would quietly fail to do anything at all, which seemed confusing and
inconsistent to me at least and probably did not benefit anyone (but if
you disagree it should be easy to revert this). For JARs, since a
manifest is always included, it does not matter whether any files match
or not; the JAR will always be created anyway. (If someone wants to
revert Zip to create nothing if no files match, please ensure this does
not apply to Jar since empty JARs can be useful occasionally--I needed
it recently.)

4. Problems occurring during archive creation were not reliably
reported; there were logic flaws in the error handling. I think I have
cleaned this up. For example, re. #3, when creating an empty ZIP (after
fixing dependency code to not treat the missing file as up-to-date) a
ZipException is thrown when the stream is closed; the previous code
silently swallowed it. It is now correctly propagated into a
BuildException.

5. Just for fun, the default JAR manifest now says it was created by Ant
(and gives the version).

Tested only on Linux with 1.3, your mileage may vary.

-Jesse

-- 
Jesse Glick   <mailto:[EMAIL PROTECTED]>
NetBeans, Open APIs  <http://www.netbeans.org/>
tel (+4202) 3300-9161 Sun Micro x49161 Praha CR
Index: build.xml
===================================================================
RCS file: /home/cvspublic/jakarta-ant/build.xml,v
retrieving revision 1.61
diff -c -r1.61 build.xml
*** build.xml   2000/08/09 13:12:11     1.61
--- build.xml   2000/08/16 10:02:16
***************
*** 88,94 ****
      </javac>
   
      <copydir src="${src.dir}" dest="${build.classes}">
-       <include name="**/defaultManifest.mf" />
        <include name="**/*.properties" />
      </copydir>
  
--- 88,93 ----
***************
*** 100,105 ****
--- 99,105 ----
               forceoverwrite="true"
               filtering="on">
        <include name="**/version.txt" />
+       <include name="**/defaultManifest.mf" />
      </copydir>
    </target>
  
Index: src/main/org/apache/tools/ant/defaultManifest.mf
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/defaultManifest.mf,v
retrieving revision 1.1
diff -c -r1.1 defaultManifest.mf
*** src/main/org/apache/tools/ant/defaultManifest.mf    2000/01/13 10:41:40     
1.1
--- src/main/org/apache/tools/ant/defaultManifest.mf    2000/08/16 10:02:24
***************
*** 1 ****
--- 1,3 ----
  Manifest-Version: 1.0
+ Created-By: Ant @VERSION@
+ 
Index: src/main/org/apache/tools/ant/taskdefs/Jar.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Jar.java,v
retrieving revision 1.5
diff -c -r1.5 Jar.java
*** src/main/org/apache/tools/ant/taskdefs/Jar.java     2000/06/27 11:12:11     
1.5
--- src/main/org/apache/tools/ant/taskdefs/Jar.java     2000/08/16 10:02:24
***************
*** 83,106 ****
      {
        // add manifest first
        if (manifest != null) {
!             super.zipDir(new File(manifest.getParent()), zOut, "META-INF/");
            super.zipFile(manifest, zOut, "META-INF/MANIFEST.MF");
        } else {
-             /*
-              * We don't store directories at all and this one will cause a lot
-              * of problems with STORED Zip-Mode.
-              *
-              * That's why i've removed it -- Stefan Bodewig
-              */
-             //            ZipEntry ze = new ZipEntry("META-INF/");
-             //            zOut.putNextEntry(ze);
            String s = "/org/apache/tools/ant/defaultManifest.mf";
            InputStream in = this.getClass().getResourceAsStream(s);
              if ( in == null )
                throw new BuildException ( "Could not find: " + s );
            zipFile(in, zOut, "META-INF/MANIFEST.MF", 
System.currentTimeMillis());
        }
       }
  
      protected void zipDir(File dir, ZipOutputStream zOut, String vPath)
          throws IOException
--- 83,107 ----
      {
        // add manifest first
        if (manifest != null) {
!           super.zipDir(new File(manifest.getParent()), zOut, "META-INF/");
            super.zipFile(manifest, zOut, "META-INF/MANIFEST.MF");
        } else {
            String s = "/org/apache/tools/ant/defaultManifest.mf";
            InputStream in = this.getClass().getResourceAsStream(s);
              if ( in == null )
                throw new BuildException ( "Could not find: " + s );
+           super.zipDir(null, zOut, "META-INF/");
            zipFile(in, zOut, "META-INF/MANIFEST.MF", 
System.currentTimeMillis());
        }
       }
+ 
+     protected boolean isUpToDate(File baseDir, String[] files, File zipFile)
+     {
+       if (manifest != null && manifest.lastModified() > 
zipFile.lastModified())
+           return false;
+       else
+           return super.isUpToDate(baseDir, files, zipFile);
+     }
  
      protected void zipDir(File dir, ZipOutputStream zOut, String vPath)
          throws IOException
Index: src/main/org/apache/tools/ant/taskdefs/Zip.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Zip.java,v
retrieving revision 1.10
diff -c -r1.10 Zip.java
*** src/main/org/apache/tools/ant/taskdefs/Zip.java     2000/08/03 09:13:18     
1.10
--- src/main/org/apache/tools/ant/taskdefs/Zip.java     2000/08/16 10:02:24
***************
*** 58,63 ****
--- 58,64 ----
  
  import java.io.*;
  import java.util.Enumeration;
+ import java.util.Hashtable;
  import java.util.StringTokenizer;
  import java.util.Vector;
  import java.util.zip.*;
***************
*** 75,80 ****
--- 76,83 ----
      private File baseDir;
      private boolean doCompress = true;
      protected String archiveType = "zip";
+     // For directories:
+     private static long emptyCrc = new CRC32 ().getValue ();
      
      /**
       * This is the name/location of where to 
***************
*** 110,171 ****
          DirectoryScanner ds = super.getDirectoryScanner(baseDir);
  
          String[] files = ds.getIncludedFiles();
-         String[] dirs  = ds.getIncludedDirectories();
  
          // quick exit if the target is up to date
!         boolean upToDate = true;
!         for (int i=0; i<files.length && upToDate; i++)
!             if (new File(baseDir,files[i]).lastModified() > 
!                 zipFile.lastModified())
!                 upToDate = false;
!         if (upToDate) return;
  
          log("Building "+ archiveType +": "+ zipFile.getAbsolutePath());
  
!         ZipOutputStream zOut = null;
!         try {
!             zOut = new ZipOutputStream(new FileOutputStream(zipFile));
!             if (doCompress) {
!                 zOut.setMethod(ZipOutputStream.DEFLATED);
!             } else {
!                 zOut.setMethod(ZipOutputStream.STORED);
!             }
!             initZipOutputStream(zOut);
! 
!             for (int i = 0; i < dirs.length; i++) {
!                 File f = new File(baseDir,dirs[i]);
!                 String name = dirs[i].replace(File.separatorChar,'/')+"/";
!                 zipDir(f, zOut, name);
!             }
! 
!             for (int i = 0; i < files.length; i++) {
!                 File f = new File(baseDir,files[i]);
!                 String name = files[i].replace(File.separatorChar,'/');
!                 zipFile(f, zOut, name);
!             }
!         } catch (IOException ioe) {
!             String msg = "Problem creating " + archiveType + " " + 
ioe.getMessage();
  
              // delete a bogus ZIP file
!           if (zOut != null) {
!               try {
!                   zOut.close();
!                     zOut = null;
!               } catch (IOException e) {}
!                 if (!zipFile.delete()) {
!                     msg = zipFile + " is probably corrupt but I could not 
delete it";
!                 }
!             }
  
              throw new BuildException(msg, ioe, location);
-       } finally {
-           if (zOut != null) {
-               try {
-                     // close up
-                   zOut.close();
-               }
-               catch (IOException e) {}
-           }
          }
      }
  
--- 113,163 ----
          DirectoryScanner ds = super.getDirectoryScanner(baseDir);
  
          String[] files = ds.getIncludedFiles();
  
          // quick exit if the target is up to date
!         if (isUpToDate(baseDir, files, zipFile)) return;
  
          log("Building "+ archiveType +": "+ zipFile.getAbsolutePath());
  
!       try {
!           ZipOutputStream zOut = new ZipOutputStream(new 
FileOutputStream(zipFile));
!           try {
!               if (doCompress) {
!                   zOut.setMethod(ZipOutputStream.DEFLATED);
!               } else {
!                   zOut.setMethod(ZipOutputStream.STORED);
!               }
!               initZipOutputStream(zOut);
! 
!               Hashtable parentDirs = new Hashtable();
! 
!               for (int i = 0; i < files.length; i++) {
!                   File f = new File(baseDir,files[i]);
!                   String name = files[i].replace(File.separatorChar,'/');
!                   // Look for & create parent dirs as needed.
!                   int slashPos = -1;
!                   while ((slashPos = name.indexOf((int)'/', slashPos + 1)) != 
-1) {
!                       String dir = name.substring(0, slashPos);
!                       if (!parentDirs.contains(dir)) {
!                           parentDirs.put(dir, dir);
!                           zipDir(new File(baseDir, dir.replace('/', 
File.separatorChar)),
!                                  zOut, dir + '/');
!                       }
!                   }
!                   zipFile(f, zOut, name);
!               }
!           } finally {
!               zOut.close ();
!           }
!       } catch (IOException ioe) {
!           String msg = "Problem creating " + archiveType + ": " + 
ioe.getMessage();
  
              // delete a bogus ZIP file
!           if (!zipFile.delete()) {
!               msg += " (and the archive is probably corrupt but I could not 
delete it)";
!           }
  
              throw new BuildException(msg, ioe, location);
          }
      }
  
***************
*** 174,182 ****
--- 166,195 ----
      {
      }
  
+     protected boolean isUpToDate(File baseDir, String[] files, File zipFile)
+     {
+       if (files.length == 0 && !zipFile.exists())
+           // Otherwise would never try to create it at all.
+           return false;
+         for (int i=0; i<files.length; i++) {
+             if (new File(baseDir,files[i]).lastModified() > 
+                 zipFile.lastModified()) {
+               return false;
+           }
+       }
+       return true;
+     }
+ 
      protected void zipDir(File dir, ZipOutputStream zOut, String vPath)
          throws IOException
      {
+       ZipEntry ze = new ZipEntry (vPath);
+       if (dir != null) ze.setTime (dir.lastModified ());
+       ze.setSize (0);
+       ze.setMethod (ZipEntry.STORED);
+       // This is faintly ridiculous:
+       ze.setCrc (emptyCrc);
+       zOut.putNextEntry (ze);
      }
  
      protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath,

Reply via email to