diff --git a/WHATSNEW b/WHATSNEW index ef122b737..cdb7d58dc 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -19,6 +19,9 @@ Changes that could break older environments: * will no longer fail if the file to be loaded doesn't exist. +* ZipScanner#getIncludedFiles will now return the names of the ZipEntries + that have been matched instead of the name of the archive. + Fixed bugs: ----------- * was not ignoring comment lines. diff --git a/src/main/org/apache/tools/ant/DirectoryScanner.java b/src/main/org/apache/tools/ant/DirectoryScanner.java index cc3046530..b46c850b2 100644 --- a/src/main/org/apache/tools/ant/DirectoryScanner.java +++ b/src/main/org/apache/tools/ant/DirectoryScanner.java @@ -57,6 +57,7 @@ package org.apache.tools.ant; import java.io.File; import java.io.IOException; import java.util.Vector; +import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.selectors.FileSelector; import org.apache.tools.ant.types.selectors.SelectorScanner; import org.apache.tools.ant.types.selectors.SelectorUtils; @@ -149,7 +150,7 @@ import org.apache.tools.ant.util.FileUtils; * @author Magesh Umasankar * @author Bruce Atherton */ -public class DirectoryScanner implements FileScanner, SelectorScanner { +public class DirectoryScanner implements ResourceScanner, SelectorScanner { /** * Patterns which should be excluded by default. @@ -201,6 +202,11 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { */ protected Vector filesIncluded; + /** + * the same as filesIncluded, but in terms of Resource + */ + private Vector filesIncludedR; + /** The files which did not match any includes or selectors. */ protected Vector filesNotIncluded; @@ -214,6 +220,10 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { * and were selected. */ protected Vector dirsIncluded; + /** The directories which matched at least one include and no excludes + * and were selected, as resources + */ + private Vector dirsIncludedR; /** The directories which were found and did not match any includes. */ protected Vector dirsNotIncluded; @@ -545,10 +555,12 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { } filesIncluded = new Vector(); + filesIncludedR = new Vector(); filesNotIncluded = new Vector(); filesExcluded = new Vector(); filesDeselected = new Vector(); dirsIncluded = new Vector(); + dirsIncludedR = new Vector(); dirsNotIncluded = new Vector(); dirsExcluded = new Vector(); dirsDeselected = new Vector(); @@ -557,6 +569,10 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { if (!isExcluded("")) { if (isSelected("",basedir)) { dirsIncluded.addElement(""); + dirsIncludedR.addElement(new Resource("", true, + basedir + .lastModified(), + true)); } else { dirsDeselected.addElement(""); } @@ -675,6 +691,11 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { if (!isExcluded(name)) { if (isSelected(name,file)) { dirsIncluded.addElement(name); + dirsIncludedR.addElement(new Resource(name, + true, + file + .lastModified(), + true)); if (fast) { scandir(file, name + File.separator, fast); } @@ -708,6 +729,11 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { if (!isExcluded(name)) { if (isSelected(name,file)) { filesIncluded.addElement(name); + filesIncludedR.addElement(new Resource(name, + true, + file + .lastModified(), + false)); } else { everythingIncluded = false; filesDeselected.addElement(name); @@ -810,6 +836,26 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { } return files; } + /** + * Returns the resources of the files which matched at least one + * of the include patterns and none of the exclude patterns. The + * names are relative to the base directory. + * + * @return resource information for the files which matched at + * least one of the include patterns and none of the exclude + * patterns. + * + * @since Ant 1.5.2 + */ + public Resource[] getIncludedFileResources() { + int count = filesIncludedR.size(); + Resource[] resources = new Resource[count]; + for (int i = 0; i < count; i++) { + resources[i] = + (Resource) ((Resource) filesIncludedR.elementAt(i)).clone(); + } + return resources; + } /** * Returns the names of the files which matched none of the include @@ -890,6 +936,25 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { return directories; } + /** + * Returns the resource object for the directories which matched + * at least one of the include patterns and none of the exclude + * patterns. The names are relative to the base directory. + * + * @return the names of the directories which matched at least one of the + * include patterns and none of the exclude patterns. + * + * @since Ant 1.5.2 + */ + public Resource[] getIncludedDirectoryResources() { + int count = dirsIncludedR.size(); + Resource[] directories = new Resource[count]; + for (int i = 0; i < count; i++) { + directories[i] = + (Resource) ((Resource) dirsIncludedR.elementAt(i)).clone(); + } + return directories; + } /** * Returns the names of the directories which matched none of the include * patterns. The names are relative to the base directory. This involves @@ -968,4 +1033,21 @@ public class DirectoryScanner implements FileScanner, SelectorScanner { } excludes = newExcludes; } + + /** + * @param name path name of the file relative to the dir attribute. + * + * @since Ant 1.5.2 + */ + public Resource getResource(String name) { + File f = null; + if (basedir != null) { + f = new File(basedir, name); + } else { + f = new File(name); + } + return new Resource(name, f.exists(), f.lastModified(), + f.isDirectory()); + } + } diff --git a/src/main/org/apache/tools/ant/ResourceScanner.java b/src/main/org/apache/tools/ant/ResourceScanner.java new file mode 100644 index 000000000..4dd281882 --- /dev/null +++ b/src/main/org/apache/tools/ant/ResourceScanner.java @@ -0,0 +1,85 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 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", "Ant", 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; + +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceFactory; + +/** + * Extends the FileScanner concept to {@link + * org.apache.tools.ant.types.Resource Resources}. + * + * @since Ant 1.5.2 + */ +public interface ResourceScanner extends FileScanner, ResourceFactory { + + /** + * Returns resources for the directories which matched at least + * one of the include patterns and none of the exclude patterns. + * + * @return resources for the directories which matched at least + * one of the include patterns and none of the exclude patterns. + */ + Resource[] getIncludedDirectoryResources(); + + /** + * Returns resources for the files which matched at least one of + * the include patterns and none of the exclude patterns. + * + * @return the names of the files which matched at least one of the + * include patterns and none of the exclude patterns. + */ + Resource[] getIncludedFileResources(); + +} diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java index 869fafaaa..463d19f8c 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Jar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java @@ -68,9 +68,10 @@ import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.FileScanner; import org.apache.tools.ant.Project; +import org.apache.tools.ant.ResourceScanner; import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.ZipFileSet; import org.apache.tools.zip.ZipOutputStream; @@ -521,7 +522,8 @@ public class Jar extends Zip { * already); false if archive creation should proceed * @exception BuildException if it likes */ - protected boolean isUpToDate(FileScanner[] scanners, File zipFile) + protected boolean isUpToDate(ResourceScanner[] scanners, + FileSet[] fss, File zipFile) throws BuildException { // need to handle manifest as a special check if (configuredManifest != null || manifestFile == null) { @@ -562,7 +564,7 @@ public class Jar extends Zip { } else if (manifestFile.lastModified() > zipFile.lastModified()) { return false; } - return super.isUpToDate(scanners, zipFile); + return super.isUpToDate(scanners, fss, zipFile); } protected boolean createEmptyZip(File zipFile) { @@ -585,6 +587,7 @@ public class Jar extends Zip { manifest = null; configuredManifest = savedConfiguredManifest; filesetManifest = null; + originalManifest = null; } } diff --git a/src/main/org/apache/tools/ant/taskdefs/Zip.java b/src/main/org/apache/tools/ant/taskdefs/Zip.java index 76b51e2ae..c5999fe1a 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Zip.java +++ b/src/main/org/apache/tools/ant/taskdefs/Zip.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,18 +67,25 @@ import java.util.Stack; import java.util.Vector; import java.util.zip.CRC32; import java.util.zip.ZipInputStream; + import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.FileScanner; import org.apache.tools.ant.Project; +import org.apache.tools.ant.ResourceScanner; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.PatternSet; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceFactory; import org.apache.tools.ant.types.ZipFileSet; import org.apache.tools.ant.types.ZipScanner; +import org.apache.tools.ant.util.FileNameMapper; import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.GlobPatternMapper; +import org.apache.tools.ant.util.IdentityMapper; import org.apache.tools.ant.util.MergingMapper; -import org.apache.tools.ant.util.SourceFileScanner; +import org.apache.tools.ant.util.SourceSelector; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipOutputStream; @@ -93,9 +100,11 @@ import org.apache.tools.zip.ZipOutputStream; * * @ant.task category="packaging" */ -public class Zip extends MatchingTask { +public class Zip extends MatchingTask implements ResourceFactory { protected File zipFile; + // use to scan own archive + private ZipScanner zs; private File baseDir; protected Hashtable entries = new Hashtable(); private Vector groupfilesets = new Vector(); @@ -117,6 +126,7 @@ public class Zip extends MatchingTask { protected boolean doubleFilePass = false; protected boolean skipWriting = false; + private FileUtils fileUtils; /** @@ -331,22 +341,28 @@ public class Zip extends MatchingTask { // Create the scanners to pass to isUpToDate(). Vector dss = new Vector(); + Vector vfss = new Vector(); if (baseDir != null) { dss.addElement(getDirectoryScanner(baseDir)); + FileSet fs = new FileSet(); + fs.setDir(baseDir); + vfss.addElement(fs); } for (int i = 0; i < filesets.size(); i++) { FileSet fs = (FileSet) filesets.elementAt(i); dss.addElement (fs.getDirectoryScanner(getProject())); + vfss.addElement(fs); } int dssSize = dss.size(); - FileScanner[] scanners = new FileScanner[dssSize]; + ResourceScanner[] scanners = new ResourceScanner[dssSize]; dss.copyInto(scanners); - + FileSet [] fss = new FileSet[dssSize]; + vfss.copyInto(fss); boolean success = false; try { // quick exit if the target is up to date // can also handle empty archives - if (isUpToDate(scanners, zipFile)) { + if (isUpToDate(scanners, fss, zipFile)) { return; } @@ -642,6 +658,15 @@ public class Zip extends MatchingTask { return true; } + public Resource getResource(String name) { + if (zs==null) { + zs=new ZipScanner(); + // set the task of the zip scanner so that it can log properly + zs.setTask(this); + zs.setSrc(zipFile); + } + return zs.getResource(name); + } /** * Check whether the archive is up-to-date; and handle behavior @@ -652,8 +677,17 @@ public class Zip extends MatchingTask { * already); false if archive creation should proceed * @exception BuildException if it likes */ - protected boolean isUpToDate(FileScanner[] scanners, File zipFile) + protected boolean isUpToDate(ResourceScanner[] scanners, + FileSet[] fss, File zipFile) throws BuildException { + Resource[][] resourceNames = grabResources(scanners); + for (int counter = 0;counter < scanners.length; counter++){ + for (int j=0; j < resourceNames[counter].length;j++) { + log("resource from scanner " + counter + " " + j + " name : " + + resourceNames[counter][j].getName(), Project.MSG_DEBUG); + } + } + String[][] fileNames = grabFileNames(scanners); File[] files = grabFiles(scanners, fileNames); if (files.length == 0) { @@ -681,17 +715,39 @@ public class Zip extends MatchingTask { return false; } - SourceFileScanner sfs = new SourceFileScanner(this); - MergingMapper mm = new MergingMapper(); - mm.setTo(zipFile.getAbsolutePath()); for (int i = 0; i < scanners.length; i++) { - if (sfs.restrict(fileNames[i], scanners[i].getBasedir(), null, - mm).length > 0) { - return false; + boolean result=false; + FileNameMapper myMapper = new IdentityMapper(); + if (fss[i] instanceof ZipFileSet) { + ZipFileSet zfs = (ZipFileSet) fss[i]; + if (zfs.getFullpath() != null + && !zfs.getFullpath().equals("") ) { + // in this case all files from origin map to + // the fullPath attribute of the zipfileset at + // destination + MergingMapper fm = new MergingMapper(); + fm.setTo(zfs.getFullpath()); + myMapper = fm; + + } else if (zfs.getPrefix() != null + && !zfs.getPrefix().equals("")) { + GlobPatternMapper gm=new GlobPatternMapper(); + gm.setFrom("*"); + gm.setTo(zfs.getPrefix() + "*"); + myMapper = gm; + } + } + Resource[] newerSources = + SourceSelector.selectOutOfDateSources(this, + resourceNames[i], + myMapper, this); + result = (newerSources.length == 0); + if (!result) { + return result; } } - return true; } + return true; } protected static File[] grabFiles(FileScanner[] scanners) { @@ -723,6 +779,24 @@ public class Zip extends MatchingTask { } return result; } + /** + * + * @param scanners here are expected ResourceScanner arguments + * @return double dimensional array of resources + */ + protected static Resource[][] grabResources(ResourceScanner[] scanners) { + Resource[][] result = new Resource[scanners.length][]; + for (int i = 0; i < scanners.length; i++) { + Resource[] files = scanners[i].getIncludedFileResources(); + Resource[] directories = + scanners[i].getIncludedDirectoryResources(); + result[i] = new Resource[files.length + directories.length]; + System.arraycopy(files, 0, result[i], 0, files.length); + System.arraycopy(directories, 0, result[i], files.length, + directories.length); + } + return result; + } /** * @deprecated use four-arg version instead. diff --git a/src/main/org/apache/tools/ant/types/Resource.java b/src/main/org/apache/tools/ant/types/Resource.java new file mode 100644 index 000000000..e1eb705fc --- /dev/null +++ b/src/main/org/apache/tools/ant/types/Resource.java @@ -0,0 +1,165 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 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", "Ant", 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.types; + +/** + * describes a File or a ZipEntry + * + * this class is meant to be used by classes needing to record path + * and date/time information about a file, a zip entry or some similar + * resource (URL, archive in a version control repository, ...) + * + * @since Ant 1.5.2 + */ +public class Resource implements Cloneable { + private String name = null; + private boolean exists = true; + private long lastmodified = 0; + private boolean directory = false; + + /** + * default constructor + */ + public Resource() { + } + + /** + * only sets the name. + * + *

This is a dummy, used for not existing resources.

+ */ + public Resource(String name) { + this(name, false, 0, false); + } + + /** + * sets the name, lastmodified flag, and exists flag + */ + public Resource(String name, boolean exists, long lastmodified) { + this(name, exists, lastmodified, false); + } + + public Resource(String name, boolean exists, long lastmodified, + boolean directory) { + this.name = name; + this.exists = exists; + this.lastmodified = lastmodified; + this.directory = directory; + } + + /** + * name attribute will contain the path of a file relative to the + * root directory of its fileset or the recorded path of a zip + * entry. + * + *

example for a file with fullpath /var/opt/adm/resource.txt + * in a file set with root dir /var/opt it will be + * adm/resource.txt.

+ */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + /** + * the exists attribute tells whether a file exists + */ + public boolean isExists() { + return exists; + } + + public void setExists(boolean exists) { + this.exists = exists; + } + + /** + * tells the modification time in milliseconds since 01.01.1970 of + * + * @return 0 if the resource does not exist to mirror the behavior + * of {@link java.io.File File}. + */ + public long getLastModified() { + return !exists || lastmodified < 0 ? 0 : lastmodified; + } + + public void setLastModified(long lastmodified) { + this.lastmodified = lastmodified; + } + /** + * tells if the resource is a directory + * @return boolean flag indicating if the resource is a directory + */ + public boolean isDirectory() { + return directory; + } + + public void setDirectory(boolean directory) { + this.directory = directory; + } + + /** + * @return copy of this + */ + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new Error("CloneNotSupportedException for a " + + "Clonable Resource caught?"); + } + } + +} diff --git a/src/main/org/apache/tools/ant/types/ResourceFactory.java b/src/main/org/apache/tools/ant/types/ResourceFactory.java new file mode 100644 index 000000000..ae9f7ab2c --- /dev/null +++ b/src/main/org/apache/tools/ant/types/ResourceFactory.java @@ -0,0 +1,73 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 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", "Ant", 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.types; + +/** + * this interface should be implemented by classes (Scanners) needing + * to deliver information about resources. + * + * @since Ant 1.5.2 + */ +public interface ResourceFactory { + + /** + * Query a resource (file, zipentry, ...) by name + * + * @param Name relative path of the resource about which + * information is sought + * @return instance of Resource; the exists attribute of Resource + * will tell whether the sought resource exists + */ + Resource getResource(String name); +} diff --git a/src/main/org/apache/tools/ant/types/ZipScanner.java b/src/main/org/apache/tools/ant/types/ZipScanner.java index 8f04b8811..dd02a7387 100644 --- a/src/main/org/apache/tools/ant/types/ZipScanner.java +++ b/src/main/org/apache/tools/ant/types/ZipScanner.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2001-2002 The Apache Software Foundation. All rights + * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,18 +55,24 @@ package org.apache.tools.ant.types; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Vector; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; + import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; /** * ZipScanner accesses the pattern matching algorithm in DirectoryScanner, * which are protected methods that can only be accessed by subclassing. * * This implementation of FileScanner defines getIncludedFiles to return - * only the Zip File which is being scanned, not the matching Zip entries. - * Arguably, it should return the matching entries, however this would - * complicate existing code which assumes that FileScanners return a - * set of file system files that can be accessed directly. - * + * the matching Zip entries. + * * @author Don Ferguson don@bea.com */ public class ZipScanner extends DirectoryScanner { @@ -75,35 +81,84 @@ public class ZipScanner extends DirectoryScanner { * The zip file which should be scanned. */ protected File srcFile; + /** + * The current task, used to report errors, ... + */ + private Task task; + /** + * to record the last scanned zip file with its modification date + */ + private Resource lastScannedResource; + /** + * record list of all zip entries + */ + private Vector myentries; /** - * Sets the srcFile for scanning. This is the jar or zip file that is scanned - * for matching entries. + * Sets the srcFile for scanning. This is the jar or zip file that + * is scanned for matching entries. * * @param srcFile the (non-null) zip file name for scanning */ public void setSrc(File srcFile) { this.srcFile = srcFile; } + /** + * Sets the current task. This is used to provide proper logging + * for exceptions + * + * @param task the current task + * + * @since Ant 1.5.2 + */ + public void setTask(Task task) { + this.task = task; + } /** - * Returns the zip file itself, not the matching entries within the zip file. - * This keeps the uptodate test in the Zip task simple; otherwise we'd need - * to treat zip filesets specially. + * Returns the names of the files which matched at least one of the + * include patterns and none of the exclude patterns. + * The names are relative to the base directory. * - * @return the source file from which entries will be extracted. + * @return the names of the files which matched at least one of the + * include patterns and none of the exclude patterns. */ public String[] getIncludedFiles() { - String[] result = new String[1]; - result[0] = srcFile.getAbsolutePath(); - return result; + Vector myvector = new Vector(); + // first check if the archive needs to be scanned again + scanme(); + for (int counter = 0; counter < myentries.size(); counter++) { + Resource myresource= (Resource) myentries.elementAt(counter); + if (!myresource.isDirectory() && match(myresource.getName())) { + myvector.addElement(myresource.getName()); + } + } + String[] files = new String[myvector.size()]; + myvector.copyInto(files); + return files; } /** - * Returns an empty list of directories to create. + * Returns the names of the directories which matched at least one of the + * include patterns and none of the exclude patterns. + * The names are relative to the base directory. + * + * @return the names of the directories which matched at least one of the + * include patterns and none of the exclude patterns. */ public String[] getIncludedDirectories() { - return new String[0]; + Vector myvector=new Vector(); + // first check if the archive needs to be scanned again + scanme(); + for (int counter = 0; counter < myentries.size(); counter++) { + Resource myresource = (Resource) myentries.elementAt(counter); + if (myresource.isDirectory() && match(myresource.getName())) { + myvector.addElement(myresource.getName()); + } + } + String[] files = new String[myvector.size()]; + myvector.copyInto(files); + return files; } /** @@ -135,4 +190,164 @@ public class ZipScanner extends DirectoryScanner { return isIncluded(vpath) && !isExcluded(vpath); } + /** + * Returns the resources of the files which matched at least one of the + * include patterns and none of the exclude patterns. + * The names are relative to the base directory. + * + * @return resource information for the files which matched at + * least one of the include patterns and none of the exclude + * patterns. + * + * @since Ant 1.5.2 + */ + public Resource[] getIncludedFileResources() { + Vector myvector = new Vector(); + // first check if the archive needs to be scanned again + scanme(); + for (int counter = 0; counter < myentries.size(); counter++) { + Resource myresource = (Resource) myentries.elementAt(counter); + if (!myresource.isDirectory() && match(myresource.getName())) { + myvector.addElement(myresource.clone()); + } + } + Resource[] resources = new Resource[myvector.size()]; + myvector.copyInto(resources); + return resources; + } + + /** + * Returns the resources of the files which matched at least one of the + * include patterns and none of the exclude patterns. + * The names are relative to the base directory. + * + * @return resource information for the files which matched at + * least one of the include patterns and none of the exclude + * patterns. + * + * @since Ant 1.5.2 + */ + public Resource[] getIncludedDirectoryResources() { + Vector myvector = new Vector(); + // first check if the archive needs to be scanned again + scanme(); + for (int counter = 0; counter < myentries.size(); counter++) { + Resource myresource = (Resource) myentries.elementAt(counter); + if (myresource.isDirectory() && match(myresource.getName())) { + myvector.add(myresource.clone()); + } + } + Resource[] resources = new Resource[myvector.size()]; + myvector.copyInto(resources); + return resources; + } + + /** + * @param name path name of the file sought in the archive + * + * @since Ant 1.5.2 + */ + public Resource getResource(String name) { + // first check if the archive needs to be scanned again + scanme(); + for (int counter = 0; counter < myentries.size(); counter++) { + Resource myresource=(Resource)myentries.elementAt(counter); + if (myresource.getName().equals(name)) { + return myresource; + } + } + return new Resource(name); + } + + /** + * if the datetime of the archive did not change since + * lastScannedResource was initialized returns immediately else if + * the archive has not been scanned yet, then all the zip entries + * are put into the vector myentries as a vector of the resource + * type + */ + private void scanme() { + Resource thisresource = new Resource(srcFile.getAbsolutePath(), + srcFile.exists(), + srcFile.lastModified()); + + // spare scanning again and again + if (lastScannedResource != null + && lastScannedResource.getName().equals(thisresource.getName()) + && lastScannedResource.getLastModified() + == thisresource.getLastModified()) { + return; + } + + Vector vResult = new Vector(); + if (task != null) { + task.log("checking zip entries: " + srcFile, Project.MSG_VERBOSE); + } + + ZipEntry entry = null; + ZipInputStream in = null; + myentries = new Vector(); + try { + try { + in = new ZipInputStream(new FileInputStream(srcFile)); + if (task != null) { + task.log("opening input stream from " + srcFile, + Project.MSG_DEBUG); + } + } catch (IOException ex) { + // XXX - throw a BuildException instead ?? + if (task != null) { + task.log("problem opening "+srcFile,Project.MSG_ERR); + } + } + + while (true) { + try { + entry = in.getNextEntry(); + if (entry == null) { + break; + } + myentries.add(new Resource(entry.getName(), + true, + entry.getTime(), + entry.isDirectory())); + if (task != null) { + task.log("adding entry " + entry.getName() + " from " + + srcFile, Project.MSG_DEBUG); + } + + } catch (ZipException ex) { + // XXX - throw a BuildException instead ?? + if (task != null ) { + task.log("problem reading " + srcFile, + Project.MSG_ERR); + } + + } catch (IOException e) { + // XXX - throw a BuildException instead ?? + if (task != null) { + task.log("problem reading zip entry from " + srcFile, + Project.MSG_ERR); + } + } + } + } finally { + if (in != null) { + try { + in.close(); + if (task != null) { + task.log("closing input stream from " + srcFile, + Project.MSG_DEBUG); + } + } catch (IOException ex) { + if (task != null) { + task.log("problem closing input stream from " + + srcFile, Project.MSG_ERR); + } + } + } + } + // record data about the last scanned resource + lastScannedResource = thisresource; + } } diff --git a/src/main/org/apache/tools/ant/util/SourceFileScanner.java b/src/main/org/apache/tools/ant/util/SourceFileScanner.java index d25a3d0ab..b8914a434 100644 --- a/src/main/org/apache/tools/ant/util/SourceFileScanner.java +++ b/src/main/org/apache/tools/ant/util/SourceFileScanner.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,6 +58,8 @@ import java.io.File; import java.util.Vector; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.ResourceFactory; +import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.taskdefs.condition.Os; /** @@ -70,11 +72,12 @@ import org.apache.tools.ant.taskdefs.condition.Os; * * @author Stefan Bodewig */ -public class SourceFileScanner { +public class SourceFileScanner implements ResourceFactory { protected Task task; private FileUtils fileUtils; + private File destDir; // base directory of the fileset /** * @param task The task we should log messages through @@ -97,71 +100,26 @@ public class SourceFileScanner { */ public String[] restrict(String[] files, File srcDir, File destDir, FileNameMapper mapper) { - - long now = (new java.util.Date()).getTime(); - StringBuffer targetList = new StringBuffer(); - - /* - If we're on Windows, we have to munge the time up to 2 secs to - be able to check file modification times. - (Windows has a max resolution of two secs for modification times) - Actually this is a feature of the FAT file system, NTFS does - not have it, so if we could reliably passively test for an NTFS - file systems we could turn this off... - */ - if (Os.isFamily("windows")) { - now += 2000; - } - + // record destdir for later use in getResource + this.destDir = destDir; Vector v = new Vector(); for (int i = 0; i < files.length; i++) { - - String[] targets = mapper.mapFileName(files[i]); - if (targets == null || targets.length == 0) { - task.log(files[i] + " skipped - don\'t know how to handle it", - Project.MSG_VERBOSE); - continue; - } - File src = fileUtils.resolveFile(srcDir, files[i]); - - if (src.lastModified() > now) { - task.log("Warning: " + files[i] + " modified in the future.", - Project.MSG_WARN); - } - - boolean added = false; - targetList.setLength(0); - for (int j = 0; !added && j < targets.length; j++) { - File dest = fileUtils.resolveFile(destDir, targets[j]); - - if (!dest.exists()) { - task.log(files[i] + " added as " + dest.getAbsolutePath() - + " doesn\'t exist.", Project.MSG_VERBOSE); - v.addElement(files[i]); - added = true; - } else if (src.lastModified() > dest.lastModified()) { - task.log(files[i] + " added as " + dest.getAbsolutePath() - + " is outdated.", Project.MSG_VERBOSE); - v.addElement(files[i]); - added = true; - } else { - if (targetList.length() > 0) { - targetList.append(", "); - } - targetList.append(dest.getAbsolutePath()); - } - } - - if (!added) { - task.log(files[i] + " omitted as " + targetList.toString() - + (targets.length == 1 ? " is" : " are ") - + " up to date.", Project.MSG_VERBOSE); - } - + v.addElement(new Resource(files[i], src.exists(), + src.lastModified(), src.isDirectory())); + } + Resource[] sourceresources= new Resource[v.size()]; + v.copyInto(sourceresources); + + // build the list of sources which are out of date with + // respect to the target + Resource[] outofdate = + SourceSelector.selectOutOfDateSources(task, sourceresources, + mapper, this); + String[] result = new String[outofdate.length]; + for (int counter=0; counter < outofdate.length; counter++) { + result[counter] = outofdate[counter].getName(); } - String[] result = new String[v.size()]; - v.copyInto(result); return result; } @@ -179,4 +137,18 @@ public class SourceFileScanner { } return result; } + + /** + * returns resource information for a file at destination + * @param name relative path of file at destination + * @return data concerning a file whose relative path to destDir is name + * + * @since Ant 1.5.2 + */ + public Resource getResource(String name) { + File src = fileUtils.resolveFile(destDir, name); + return new Resource(name, src.exists(), src.lastModified(), + src.isDirectory()); + } } + diff --git a/src/main/org/apache/tools/ant/util/SourceSelector.java b/src/main/org/apache/tools/ant/util/SourceSelector.java new file mode 100644 index 000000000..e3ece3bca --- /dev/null +++ b/src/main/org/apache/tools/ant/util/SourceSelector.java @@ -0,0 +1,160 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 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", "Ant", 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.util; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceFactory; + +import java.util.Vector; + +/** + * this class provides utilily methods to process resources + * + * @since Ant 1.5.2 + */ +public class SourceSelector { + + /** { + * tells which source files should be reprocessed based on the + * last modification date of target files + * @param logTo where to send (more or less) interesting output + * @param source array of resources bearing relative path and last + * modification date + * @param mapper filename mapper indicating how to find the target + * files + * @param targets object able to map as a resource a relative path + * at destination + * @return array containing the source files which need to be + * copied or processed, because the targets are out of date or do + * not exist + */ + public static Resource[] selectOutOfDateSources(ProjectComponent logTo, + Resource[] source, + FileNameMapper mapper, + ResourceFactory targets) { + long now = (new java.util.Date()).getTime(); + StringBuffer targetList = new StringBuffer(); + + /* + If we're on Windows, we have to munge the time up to 2 secs to + be able to check file modification times. + (Windows has a max resolution of two secs for modification times) + Actually this is a feature of the FAT file system, NTFS does + not have it, so if we could reliably passively test for an NTFS + file systems we could turn this off... + */ + if (Os.isFamily("windows")) { + now += 2000; + } + + Vector vresult = new Vector(); + for (int counter = 0; counter < source.length; counter++) { + if (source[counter].getLastModified() > now) { + logTo.log("Warning: " + source[counter].getName() + + " modified in the future.", + Project.MSG_WARN); + } + + String[] targetnames = + mapper.mapFileName(source[counter].getName()); + if (targetnames != null) { + boolean added = false; + targetList.setLength(0); + for (int ctarget = 0; ctarget < targetnames.length; ctarget++) { + Resource atarget = + targets.getResource(targetnames[ctarget]); + // if the target does not exist, or exists and + // is older than the source, then we want to + // add the resource to what needs to be copied + if (!atarget.isExists()) { + logTo.log(source[counter].getName() + " added as " + + atarget.getName() + + " doesn\'t exist.", Project.MSG_VERBOSE); + vresult.addElement(source[counter]); + added = true; + } else if (atarget.getLastModified() + < source[counter].getLastModified()) { + logTo.log(source[counter].getName() + " added as " + + atarget.getName() + + " is outdated.", Project.MSG_VERBOSE); + vresult.addElement(source[counter]); + added = true; + } else { + if (targetList.length() > 0) { + targetList.append(", "); + } + targetList.append(atarget.getName()); + } + } + + if (!added) { + logTo.log(source[counter].getName() + + " omitted as " + targetList.toString() + + (targetnames.length == 1 ? " is" : " are ") + + " up to date.", Project.MSG_VERBOSE); + } + } else { + logTo.log(source[counter].getName() + + " skipped - don\'t know how to handle it", + Project.MSG_VERBOSE); + } + } + Resource[] result= new Resource[vresult.size()]; + vresult.copyInto(result); + return result; + } +} diff --git a/src/main/org/apache/tools/zip/ZipOutputStream.java b/src/main/org/apache/tools/zip/ZipOutputStream.java index e406822df..8fb263372 100644 --- a/src/main/org/apache/tools/zip/ZipOutputStream.java +++ b/src/main/org/apache/tools/zip/ZipOutputStream.java @@ -653,7 +653,7 @@ public class ZipOutputStream extends DeflaterOutputStream { | (time.getDate() << 16) | (time.getHours() << 11) | (time.getMinutes() << 5) - | (time.getSeconds() >> 1); + | ((time.getSeconds() + 2) >> 1); byte[] result = new byte[4]; result[0] = (byte) ((value & 0xFF)); diff --git a/src/testcases/org/apache/tools/ant/taskdefs/JarTest.java b/src/testcases/org/apache/tools/ant/taskdefs/JarTest.java index e4c6ff106..cf8643ae9 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/JarTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/JarTest.java @@ -119,20 +119,20 @@ public class JarTest extends BuildFileTest { jarModifiedDate, jarFile.lastModified()); } - public void XtestRecreateWithoutUpdateAdditionalFiles() { + public void testRecreateWithoutUpdateAdditionalFiles() { testRecreate("test4", "testRecreateWithoutUpdateAdditionalFiles"); } - public void XtestRecreateWithUpdateAdditionalFiles() { + public void testRecreateWithUpdateAdditionalFiles() { testRecreate("test4", "testRecreateWithUpdateAdditionalFiles"); } - public void XtestRecreateWithoutUpdateNewerFile() { + public void testRecreateWithoutUpdateNewerFile() { testRecreate("testRecreateNewerFileSetup", "testRecreateWithoutUpdateNewerFile"); } - public void XtestRecreateWithUpdateNewerFile() { + public void testRecreateWithUpdateNewerFile() { testRecreate("testRecreateNewerFileSetup", "testRecreateWithUpdateNewerFile"); }