From 20a1e91d17753399f8d18a5123f8e5e35e0409da Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Fri, 15 Sep 2000 11:41:19 +0000 Subject: [PATCH] New tasks and . git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267998 13f79535-47bb-0310-9956-ffa450edef68 --- docs/index.html | 131 +++++++++++- .../org/apache/tools/ant/taskdefs/Jar.java | 88 ++++---- .../org/apache/tools/ant/taskdefs/War.java | 194 ++++++++++++++++++ .../org/apache/tools/ant/taskdefs/Zip.java | 100 ++++++--- .../tools/ant/taskdefs/defaults.properties | 2 + .../org/apache/tools/ant/types/FileSet.java | 29 +-- 6 files changed, 445 insertions(+), 99 deletions(-) create mode 100644 src/main/org/apache/tools/ant/taskdefs/War.java diff --git a/docs/index.html b/docs/index.html index 13cecbfa3..e6697a6ed 100644 --- a/docs/index.html +++ b/docs/index.html @@ -25,7 +25,7 @@
  • Dave Walend (dwalend@cs.tufts.edu)
  • -

    Version 1.2 - 2000/09/14

    +

    Version 1.2 - 2000/09/15


    Table of Contents

    @@ -870,7 +870,9 @@ same patterns as the example before.

  • Tstamp
  • Unjar
  • Untar
  • +
  • Unwar
  • Unzip
  • +
  • War
  • Zip

  • @@ -3700,9 +3702,9 @@ initialization target.

    Examples

      <tstamp/>

    -

    Unjar/Unzip

    +

    Unjar/Unwar/Unzip

    Description

    -

    Unzips a zip- or jarfile.

    +

    Unzips a zip-, war- or jarfile.

    For JDK 1.1 "last modified time" field is set to current time instead of being carried from zipfile.

    File permissions will not be restored on extracted files. @@ -3762,6 +3764,129 @@ carried from tarfile.


    +

    War

    +

    Description

    +

    An extension of the Jar task with special +treatment for files that should end up in the lib, +classes or WEB-INF directories of the Web +Application Archive.

    +

    Parameters

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeDescriptionRequired
    warfilethe war-file to create.Yes
    webxmlThe deployment descriptor to use (WEB-INF/web.xml).Yes
    basedirthe directory from which to jar the files.No
    compressNot only store data but also compress them, defaults to trueNo
    includescomma separated list of patterns of files that must be + included. All files are included when omitted.No
    includesfilethe name of a file. Each line of this file is + taken to be an include patternNo
    excludescomma separated list of patterns of files that must be + excluded. No files (except default excludes) are excluded when omitted.No
    excludesfilethe name of a file. Each line of this file is + taken to be an exclude patternNo
    defaultexcludesindicates whether default excludes should be used or not + ("yes"/"no"). Default excludes are used when omitted.No
    manifestthe manifest file to use.No
    whenemptyBehavior to use if no files match.No
    +

    Nested elements

    +

    lib

    +

    The nested lib element specifies a FileSet. All files included in this fileset will +end up in the lib directory of the war file.

    +

    classes

    +

    The nested classes element specifies a FileSet. All files included in this fileset will +end up in the classes directory of the war file.

    +

    webinf

    +

    The nested webinf element specifies a FileSet. All files included in this fileset will +end up in the WEB-INF directory of the war file. If this +fileset includes a file named web.xml, the file is +ignored and you will get a warning.

    +

    Examples

    +

    Assume the following structure in the project's base directory: +

    +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
    +
    +then the war file myapp.war created with +
    +<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>
    +
    +will consist of +
    +WEB-INF/web.xml
    +lib/jdbc2.jar
    +classes/com/myco/myapp/Servlet.class
    +META-INF/MANIFEST.MF
    +index.html
    +front.jsp
    +
    +using Ant's default manifest file. The content of +WEB-INF/web.xml is identical to +src/metadata/myapp.xml.

    +

    Zip

    Description

    Creates a zipfile.

    diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java index 7351b2ec3..29fdd7314 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Jar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java @@ -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 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); } } + } diff --git a/src/main/org/apache/tools/ant/taskdefs/War.java b/src/main/org/apache/tools/ant/taskdefs/War.java new file mode 100644 index 000000000..953057965 --- /dev/null +++ b/src/main/org/apache/tools/ant/taskdefs/War.java @@ -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 + * . + */ + +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 Stefan Bodewig + */ +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; iEnsure 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); + } + } } diff --git a/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/src/main/org/apache/tools/ant/taskdefs/defaults.properties index a8f381a52..dca236bf8 100644 --- a/src/main/org/apache/tools/ant/taskdefs/defaults.properties +++ b/src/main/org/apache/tools/ant/taskdefs/defaults.properties @@ -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 diff --git a/src/main/org/apache/tools/ant/types/FileSet.java b/src/main/org/apache/tools/ant/types/FileSet.java index e2461646e..716cfd09f 100644 --- a/src/main/org/apache/tools/ant/types/FileSet.java +++ b/src/main/org/apache/tools/ant/types/FileSet.java @@ -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();