git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267998 13f79535-47bb-0310-9956-ffa450edef68master
@@ -25,7 +25,7 @@ | |||
<li>Dave Walend (<a href="mailto:dwalend@cs.tufts.edu">dwalend@cs.tufts.edu</a>)</li> | |||
</ul> | |||
<p>Version 1.2 - 2000/09/14</p> | |||
<p>Version 1.2 - 2000/09/15</p> | |||
<hr> | |||
<h2>Table of Contents</h2> | |||
@@ -870,7 +870,9 @@ same patterns as the example before.</p> | |||
<li><a href="#tstamp">Tstamp</a></li> | |||
<li><a href="#unzip">Unjar</a></li> | |||
<li><a href="#untar">Untar</a></li> | |||
<li><a href="#unzip">Unwar</a></li> | |||
<li><a href="#unzip">Unzip</a></li> | |||
<li><a href="#war">War</a></li> | |||
<li><a href="#zip">Zip</a></li> | |||
</ul> | |||
<hr> | |||
@@ -3700,9 +3702,9 @@ initialization target.</p> | |||
<h3>Examples</h3> | |||
<pre> <tstamp/></pre> | |||
<hr> | |||
<h2><a name="unzip">Unjar/Unzip</a></h2> | |||
<h2><a name="unzip">Unjar/Unwar/Unzip</a></h2> | |||
<h3>Description</h3> | |||
<p>Unzips a zip- or jarfile.</p> | |||
<p>Unzips a zip-, war- or jarfile.</p> | |||
<p>For JDK 1.1 "last modified time" field is set to current time instead of being | |||
carried from zipfile.</p> | |||
<p>File permissions will not be restored on extracted files.</a> | |||
@@ -3762,6 +3764,129 @@ carried from tarfile.</p> | |||
</code></p> | |||
</blockquote> | |||
<hr> | |||
<h2><a name="war">War</a></h2> | |||
<h3>Description</h3> | |||
<p>An extension of the <a name="#jar">Jar</a> task with special | |||
treatment for files that should end up in the <code>lib</code>, | |||
<code>classes</code> or <code>WEB-INF</code> directories of the Web | |||
Application Archive.</p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">warfile</td> | |||
<td valign="top">the war-file to create.</td> | |||
<td valign="top" align="center">Yes</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">webxml</td> | |||
<td valign="top">The deployment descriptor to use (WEB-INF/web.xml).</td> | |||
<td valign="top" align="center">Yes</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">basedir</td> | |||
<td valign="top">the directory from which to jar the files.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">compress</td> | |||
<td valign="top">Not only store data but also compress them, defaults to true</td> | |||
<td align="center" valign="top">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">includes</td> | |||
<td valign="top">comma separated list of patterns of files that must be | |||
included. All files are included when omitted.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">includesfile</td> | |||
<td valign="top">the name of a file. Each line of this file is | |||
taken to be an include pattern</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">excludes</td> | |||
<td valign="top">comma separated list of patterns of files that must be | |||
excluded. No files (except default excludes) are excluded when omitted.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">excludesfile</td> | |||
<td valign="top">the name of a file. Each line of this file is | |||
taken to be an exclude pattern</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">defaultexcludes</td> | |||
<td valign="top">indicates whether default excludes should be used or not | |||
("yes"/"no"). Default excludes are used when omitted.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">manifest</td> | |||
<td valign="top">the manifest file to use.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">whenempty</td> | |||
<td valign="top">Behavior to use if no files match.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
</table> | |||
<h3>Nested elements</h3> | |||
<h4>lib</h4> | |||
<p>The nested <code>lib</code> element specifies a <a | |||
href="#fileset">FileSet</a>. All files included in this fileset will | |||
end up in the <code>lib</code> directory of the war file.</p> | |||
<h4>classes</h4> | |||
<p>The nested <code>classes</code> element specifies a <a | |||
href="#fileset">FileSet</a>. All files included in this fileset will | |||
end up in the <code>classes</code> directory of the war file.</p> | |||
<h4>webinf</h4> | |||
<p>The nested <code>webinf</code> element specifies a <a | |||
href="#fileset">FileSet</a>. All files included in this fileset will | |||
end up in the <code>WEB-INF</code> directory of the war file. If this | |||
fileset includes a file named <code>web.xml</code>, the file is | |||
ignored and you will get a warning.</p> | |||
<h3>Examples</h3> | |||
<p>Assume the following structure in the project's base directory: | |||
<pre> | |||
thirdparty/libs/jdbc1.jar | |||
thirdparty/libs/jdbc2.jar | |||
build/main/com/myco/myapp/Servlet.class | |||
src/metadata/myapp.xml | |||
src/html/myapp/index.html | |||
src/jsp/myapp/front.jsp | |||
</pre> | |||
then the war file <code>myapp.war</code> created with | |||
<pre> | |||
<war warfile="myapp.war" webxml="src/metadata/myapp.xml"> | |||
<fileset dir="src/html/myapp" /> | |||
<fileset dir="src/jsp/myapp" /> | |||
<lib dir="thirdparty/libs"> | |||
<exclude name="jdbc1.jar" /> | |||
</lib> | |||
<classes dir="build/main" /> | |||
</war> | |||
</pre> | |||
will consist of | |||
<pre> | |||
WEB-INF/web.xml | |||
lib/jdbc2.jar | |||
classes/com/myco/myapp/Servlet.class | |||
META-INF/MANIFEST.MF | |||
index.html | |||
front.jsp | |||
</pre> | |||
using Ant's default manifest file. The content of | |||
<code>WEB-INF/web.xml</code> is identical to | |||
<code>src/metadata/myapp.xml</code>.</p> | |||
<hr> | |||
<h2><a name="zip">Zip</a></h2> | |||
<h3>Description</h3> | |||
<p>Creates a zipfile.</p> | |||
@@ -69,13 +69,18 @@ public class Jar extends Zip { | |||
private File manifest; | |||
public void setJarfile(String jarFilename) { | |||
super.setZipfile(jarFilename); | |||
super.archiveType = "jar"; | |||
public Jar() { | |||
super(); | |||
archiveType = "jar"; | |||
emptyBehavior = "create"; | |||
} | |||
public void setJarfile(File jarFile) { | |||
super.setZipfile(jarFile); | |||
} | |||
public void setManifest(String manifestFilename) { | |||
manifest = project.resolveFile(manifestFilename); | |||
public void setManifest(File manifestFile) { | |||
manifest = manifestFile; | |||
} | |||
protected void initZipOutputStream(ZipOutputStream zOut) | |||
@@ -83,59 +88,51 @@ public class Jar extends Zip { | |||
{ | |||
// add manifest first | |||
if (manifest != null) { | |||
super.zipDir(new File(manifest.getParent()), zOut, "META-INF/"); | |||
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/"); | |||
zipDir(null, zOut, "META-INF/"); | |||
zipFile(in, zOut, "META-INF/MANIFEST.MF", System.currentTimeMillis()); | |||
} | |||
} | |||
protected boolean isUpToDate(FileScanner[] scanners, File zipFile) | |||
protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException | |||
{ | |||
File[] files = grabFiles(scanners); | |||
if (emptyBehavior == null) emptyBehavior = "create"; | |||
if (files.length == 0) { | |||
if (emptyBehavior.equals("skip")) { | |||
log("Warning: skipping JAR archive " + zipFile + | |||
" because no files were included.", Project.MSG_WARN); | |||
return true; | |||
} else if (emptyBehavior.equals("fail")) { | |||
throw new BuildException("Cannot create JAR archive " + zipFile + | |||
": no files were included.", location); | |||
} else { | |||
// create | |||
if (!zipFile.exists() || | |||
(manifest != null && | |||
manifest.lastModified() > zipFile.lastModified())) | |||
log("Note: creating empty JAR archive " + zipFile, Project.MSG_INFO); | |||
// and continue below... | |||
} | |||
} | |||
if (!zipFile.exists()) return false; | |||
if (manifest != null && manifest.lastModified() > zipFile.lastModified()) | |||
return false; | |||
for (int i=0; i<files.length; i++) { | |||
if (files[i].lastModified() > zipFile.lastModified()) { | |||
return false; | |||
if (manifest != null) { | |||
// just add the manifest file to the mix | |||
DirectoryScanner ds = new DirectoryScanner(); | |||
ds.setBasedir(new File(manifest.getParent())); | |||
ds.setIncludes(new String[] {manifest.getName()}); | |||
ds.scan(); | |||
FileScanner[] myScanners = new FileScanner[scanners.length+1]; | |||
System.arraycopy(scanners, 0, myScanners, 0, scanners.length); | |||
myScanners[scanners.length] = ds; | |||
boolean retval = super.isUpToDate(myScanners, zipFile); | |||
if (!retval && files.length == 0) { | |||
log("Note: creating empty "+archiveType+" archive " + zipFile, | |||
Project.MSG_INFO); | |||
} | |||
} | |||
return true; | |||
} | |||
return retval; | |||
protected void zipDir(File dir, ZipOutputStream zOut, String vPath) | |||
throws IOException | |||
{ | |||
// First add directory to zip entry | |||
if(!vPath.equalsIgnoreCase("META-INF/")) { | |||
// we already added a META-INF | |||
super.zipDir(dir, zOut, vPath); | |||
} else if (emptyBehavior.equals("create") && files.length == 0) { | |||
log("Note: creating empty "+archiveType+" archive " + zipFile, | |||
Project.MSG_INFO); | |||
return false; | |||
} else { | |||
// all other cases are handled correctly by Zip's method | |||
return super.isUpToDate(scanners, zipFile); | |||
} | |||
// no warning if not, it is harmless in and of itself | |||
} | |||
protected void zipFile(File file, ZipOutputStream zOut, String vPath) | |||
@@ -145,8 +142,9 @@ public class Jar extends Zip { | |||
if (!vPath.equalsIgnoreCase("META-INF/MANIFEST.MF")) { | |||
super.zipFile(file, zOut, vPath); | |||
} else { | |||
log("Warning: selected JAR files include a META-INF/MANIFEST.MF which will be ignored " + | |||
"(please use manifest attribute to jar task)", Project.MSG_WARN); | |||
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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,194 @@ | |||
/* | |||
* The Apache Software License, Version 1.1 | |||
* | |||
* Copyright (c) 2000 The Apache Software Foundation. All rights | |||
* reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions | |||
* are met: | |||
* | |||
* 1. Redistributions of source code must retain the above copyright | |||
* 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 | |||
* the documentation and/or other materials provided with the | |||
* distribution. | |||
* | |||
* 3. The end-user documentation included with the redistribution, if | |||
* 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", "Tomcat", and "Apache Software | |||
* Foundation" must not be used to endorse or promote products derived | |||
* 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" | |||
* nor may "Apache" appear in their names without prior written | |||
* permission of the Apache Group. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
* SUCH DAMAGE. | |||
* ==================================================================== | |||
* | |||
* This software consists of voluntary contributions made by many | |||
* individuals on behalf of the Apache Software Foundation. For more | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
import org.apache.tools.ant.*; | |||
import org.apache.tools.ant.types.FileSet; | |||
import java.io.*; | |||
import java.util.Vector; | |||
import java.util.zip.*; | |||
/** | |||
* Creates a WAR archive. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | |||
*/ | |||
public class War extends Jar { | |||
private File deploymentDescriptor; | |||
private Vector libFileSets = new Vector(); | |||
private Vector classesFileSets = new Vector(); | |||
private Vector webInfFileSets = new Vector(); | |||
public War() { | |||
super(); | |||
archiveType = "war"; | |||
emptyBehavior = "create"; | |||
} | |||
public void setWarfile(File warFile) { | |||
super.setZipfile(warFile); | |||
} | |||
public void setWebxml(File descr) { | |||
deploymentDescriptor = descr; | |||
} | |||
public void addLib(FileSet fs) { | |||
libFileSets.addElement(fs); | |||
} | |||
public void addClasses(FileSet fs) { | |||
classesFileSets.addElement(fs); | |||
} | |||
public void addWebinf(FileSet fs) { | |||
webInfFileSets.addElement(fs); | |||
} | |||
/** | |||
* Add the deployment descriptor as well as all files added the | |||
* special way of nested lib, classes or webinf filesets. | |||
*/ | |||
protected void initZipOutputStream(ZipOutputStream zOut) | |||
throws IOException, BuildException | |||
{ | |||
// add deployment descriptor first | |||
if (deploymentDescriptor != null) { | |||
zipDir(new File(deploymentDescriptor.getParent()), zOut, | |||
"WEB-INF/"); | |||
super.zipFile(deploymentDescriptor, zOut, "WEB-INF/web.xml"); | |||
} else { | |||
throw new BuildException("webxml attribute is required", location); | |||
} | |||
addFiles(libFileSets, zOut, "lib/"); | |||
addFiles(classesFileSets, zOut, "classes/"); | |||
addFiles(webInfFileSets, zOut, "WEB-INF/"); | |||
super.initZipOutputStream(zOut); | |||
} | |||
protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException | |||
{ | |||
if (deploymentDescriptor == null) { | |||
throw new BuildException("webxml attribute is required", location); | |||
} | |||
// just add some Scanners for our filesets and web.xml and let | |||
// Jar/Zip do the rest of the work | |||
FileScanner[] myScanners = new FileScanner[scanners.length | |||
+ 1 // web.xml | |||
+ libFileSets.size() | |||
+ classesFileSets.size() | |||
+ webInfFileSets.size()]; | |||
System.arraycopy(scanners, 0, myScanners, 0, scanners.length); | |||
DirectoryScanner ds = new DirectoryScanner(); | |||
ds.setBasedir(new File(deploymentDescriptor.getParent())); | |||
ds.setIncludes(new String[] {deploymentDescriptor.getName()}); | |||
ds.scan(); | |||
myScanners[scanners.length] = ds; | |||
addScanners(myScanners, scanners.length+1, libFileSets); | |||
addScanners(myScanners, scanners.length+1+libFileSets.size(), | |||
classesFileSets); | |||
addScanners(myScanners, scanners.length+1+libFileSets.size()+classesFileSets.size(), | |||
webInfFileSets); | |||
return super.isUpToDate(myScanners, zipFile); | |||
} | |||
protected void zipFile(File file, ZipOutputStream zOut, String vPath) | |||
throws IOException | |||
{ | |||
// We already added a WEB-INF/web.xml | |||
if (!vPath.equalsIgnoreCase("WEB-INF/web.xml")) { | |||
super.zipFile(file, zOut, vPath); | |||
} else { | |||
log("Warning: selected "+archiveType+" files include a WEB-INF/web.xml which will be ignored " + | |||
"(please use webxml attribute to "+archiveType+" task)", Project.MSG_WARN); | |||
} | |||
} | |||
/** | |||
* Add a DirectoryScanner for each FileSet included in fileSets to scanners | |||
* starting with index startIndex. | |||
*/ | |||
protected void addScanners(FileScanner[] scanners, int startIndex, | |||
Vector fileSets) { | |||
for (int i=0; i<fileSets.size(); i++) { | |||
FileSet fs = (FileSet) fileSets.elementAt(i); | |||
scanners[startIndex+i] = fs.getDirectoryScanner(project); | |||
} | |||
} | |||
/** | |||
* Iterate over the given Vector of filesets and add all files to the | |||
* ZipOutputStream using the given prefix. | |||
*/ | |||
protected void addFiles(Vector v, ZipOutputStream zOut, String prefix) | |||
throws IOException { | |||
for (int i=0; i<v.size(); i++) { | |||
FileSet fs = (FileSet) v.elementAt(i); | |||
DirectoryScanner ds = fs.getDirectoryScanner(project); | |||
addFiles(ds, zOut, prefix); | |||
} | |||
} | |||
} |
@@ -60,6 +60,7 @@ import org.apache.tools.ant.types.*; | |||
import java.io.*; | |||
import java.util.Enumeration; | |||
import java.util.Hashtable; | |||
import java.util.Stack; | |||
import java.util.StringTokenizer; | |||
import java.util.Vector; | |||
import java.util.zip.*; | |||
@@ -79,15 +80,16 @@ public class Zip extends MatchingTask { | |||
protected String archiveType = "zip"; | |||
// For directories: | |||
private static long emptyCrc = new CRC32 ().getValue (); | |||
protected String emptyBehavior = null; | |||
protected String emptyBehavior = "skip"; | |||
private Vector filesets = new Vector (); | |||
private Hashtable addedDirs = new Hashtable(); | |||
/** | |||
* This is the name/location of where to | |||
* create the .zip file. | |||
*/ | |||
public void setZipfile(String zipFilename) { | |||
zipFile = project.resolveFile(zipFilename); | |||
public void setZipfile(File zipFile) { | |||
this.zipFile = zipFile; | |||
} | |||
/** | |||
@@ -158,28 +160,9 @@ public class Zip extends MatchingTask { | |||
zOut.setMethod(ZipOutputStream.STORED); | |||
} | |||
initZipOutputStream(zOut); | |||
// XXX ideally would also enter includedDirectories to the archive | |||
Hashtable parentDirs = new Hashtable(); | |||
for (int j = 0; j < scanners.length; j++) { | |||
String[] files = scanners[j].getIncludedFiles(); | |||
File thisBaseDir = scanners[j].getBasedir(); | |||
for (int i = 0; i < files.length; i++) { | |||
File f = new File(thisBaseDir,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(thisBaseDir, dir.replace('/', File.separatorChar)), | |||
zOut, dir + '/'); | |||
} | |||
} | |||
zipFile(f, zOut, name); | |||
} | |||
addFiles(scanners[j], zOut, ""); | |||
} | |||
} finally { | |||
zOut.close (); | |||
@@ -196,6 +179,36 @@ public class Zip extends MatchingTask { | |||
} | |||
} | |||
/** | |||
* 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. | |||
*/ | |||
protected void addFiles(FileScanner scanner, ZipOutputStream zOut, | |||
String prefix) throws IOException { | |||
File thisBaseDir = scanner.getBasedir(); | |||
// directories that matched include patterns | |||
String[] dirs = scanner.getIncludedDirectories(); | |||
for (int i = 0; i < dirs.length; i++) { | |||
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(); | |||
for (int i = 0; i < files.length; i++) { | |||
File f = new File(thisBaseDir, files[i]); | |||
String name = files[i].replace(File.separatorChar,'/'); | |||
addParentDirs(thisBaseDir, name, zOut, prefix); | |||
zipFile(f, zOut, prefix+name); | |||
} | |||
} | |||
protected void initZipOutputStream(ZipOutputStream zOut) | |||
throws IOException, BuildException | |||
{ | |||
@@ -211,15 +224,14 @@ public class Zip extends MatchingTask { | |||
*/ | |||
protected boolean isUpToDate(FileScanner[] scanners, File zipFile) throws BuildException | |||
{ | |||
if (emptyBehavior == null) emptyBehavior = "skip"; | |||
File[] files = grabFiles(scanners); | |||
if (files.length == 0) { | |||
if (emptyBehavior.equals("skip")) { | |||
log("Warning: skipping ZIP archive " + zipFile + | |||
log("Warning: skipping "+archiveType+" archive " + zipFile + | |||
" because no files were included.", Project.MSG_WARN); | |||
return true; | |||
} else if (emptyBehavior.equals("fail")) { | |||
throw new BuildException("Cannot create ZIP archive " + zipFile + | |||
throw new BuildException("Cannot create "+archiveType+" archive " + zipFile + | |||
": no files were included.", location); | |||
} else { | |||
// Create. | |||
@@ -227,7 +239,7 @@ public class Zip extends MatchingTask { | |||
// In this case using java.util.zip will not work | |||
// because it does not permit a zero-entry archive. | |||
// Must create it manually. | |||
log("Note: creating empty ZIP archive " + zipFile, Project.MSG_INFO); | |||
log("Note: creating empty "+archiveType+" archive " + zipFile, Project.MSG_INFO); | |||
try { | |||
OutputStream os = new FileOutputStream(zipFile); | |||
try { | |||
@@ -275,6 +287,13 @@ public class Zip extends MatchingTask { | |||
protected void zipDir(File dir, ZipOutputStream zOut, String vPath) | |||
throws IOException | |||
{ | |||
if (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; | |||
} | |||
addedDirs.put(vPath, vPath); | |||
ZipEntry ze = new ZipEntry (vPath); | |||
if (dir != null) ze.setTime (dir.lastModified ()); | |||
ze.setSize (0); | |||
@@ -353,4 +372,29 @@ public class Zip extends MatchingTask { | |||
fIn.close(); | |||
} | |||
} | |||
/** | |||
* Ensure all parent dirs of a given entry have been added. | |||
*/ | |||
protected void addParentDirs(File baseDir, String entry, | |||
ZipOutputStream zOut, String prefix) | |||
throws IOException { | |||
Stack directories = new Stack(); | |||
int slashPos = entry.length(); | |||
while ((slashPos = entry.lastIndexOf((int)'/', slashPos-1)) != -1) { | |||
String dir = entry.substring(0, slashPos+1); | |||
if (addedDirs.get(prefix+dir) != null) { | |||
break; | |||
} | |||
directories.push(dir); | |||
} | |||
while (!directories.isEmpty()) { | |||
String dir = (String) directories.pop(); | |||
File f = new File(baseDir, dir); | |||
zipDir(f, zOut, prefix+dir); | |||
} | |||
} | |||
} |
@@ -12,6 +12,7 @@ cvs=org.apache.tools.ant.taskdefs.Cvs | |||
get=org.apache.tools.ant.taskdefs.Get | |||
unzip=org.apache.tools.ant.taskdefs.Expand | |||
unjar=org.apache.tools.ant.taskdefs.Expand | |||
unwar=org.apache.tools.ant.taskdefs.Expand | |||
echo=org.apache.tools.ant.taskdefs.Echo | |||
javadoc=org.apache.tools.ant.taskdefs.Javadoc | |||
zip=org.apache.tools.ant.taskdefs.Zip | |||
@@ -42,6 +43,7 @@ antcall=org.apache.tools.ant.taskdefs.CallTarget | |||
sql=org.apache.tools.ant.taskdefs.SQLExec | |||
mail=org.apache.tools.ant.taskdefs.SendEmail | |||
fail=org.apache.tools.ant.taskdefs.Exit | |||
war=org.apache.tools.ant.taskdefs.War | |||
# optional tasks | |||
script=org.apache.tools.ant.taskdefs.optional.Script | |||
@@ -107,18 +107,12 @@ public class FileSet extends DataType { | |||
throw tooManyAttributes(); | |||
} | |||
/* | |||
* XXX cannot check as long as tasks get configured at parse time. | |||
* | |||
* the build process might create the directory. | |||
*/ | |||
// if (!dir.exists()) { | |||
// throw new BuildException(dir.getAbsolutePath()+" not found."); | |||
// } | |||
// if (!dir.isDirectory()) { | |||
// throw new BuildException(dir.getAbsolutePath()+" is not a directory."); | |||
// } | |||
if (!dir.exists()) { | |||
throw new BuildException(dir.getAbsolutePath()+" not found."); | |||
} | |||
if (!dir.isDirectory()) { | |||
throw new BuildException(dir.getAbsolutePath()+" is not a directory."); | |||
} | |||
this.dir = dir; | |||
} | |||
@@ -239,17 +233,6 @@ public class FileSet extends DataType { | |||
throw new BuildException("No directory specified for fileset."); | |||
} | |||
/* | |||
* XXX remove the check here and enable the one in setDir as soon | |||
* as we configure tasks at execution time. | |||
*/ | |||
if (!dir.exists()) { | |||
throw new BuildException(dir.getAbsolutePath()+" not found."); | |||
} | |||
if (!dir.isDirectory()) { | |||
throw new BuildException(dir.getAbsolutePath()+" is not a directory."); | |||
} | |||
DirectoryScanner ds = new DirectoryScanner(); | |||
setupDirectoryScanner(ds, p); | |||
ds.scan(); | |||