@@ -66,6 +66,7 @@ import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;
import java.util.zip.CRC32;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import org.apache.tools.ant.BuildException;
@@ -127,6 +128,7 @@ public class Zip extends MatchingTask {
protected boolean doubleFilePass = false;
protected boolean skipWriting = false;
private static FileUtils fileUtils = FileUtils.newFileUtils();
/**
* true when we are adding new files into the Zip file, as opposed
@@ -338,35 +340,31 @@ public class Zip extends MatchingTask {
}
}
// Create the scanners to pass to isUpToDate().
Vector dss = new Vector();
// collect filesets to pass them to getResourcesToAdd
Vector vfss = new Vector();
if (baseDir != null) {
dss.addElement(getDirectoryScanner(baseDir));
FileSet fs = new FileSet();
FileSet fs = (FileSet) getImplicitFileSet().clone();
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();
ResourceScanner[] scanners = new ResourceScanner[dssSize];
dss.copyInto(scanners);
FileSet [] fss = new FileSet[dssSize];
FileSet[] fss = new FileSet[vfss.size()];
vfss.copyInto(fss);
boolean success = false;
try {
Resource[][] addThem = getResourcesToAdd(fss, zipFile, false);
// quick exit if the target is up to date
// can also handle empty archives
if (isUpToDate(scanners, fss, zipFile )) {
if (isEmpty(addThem )) {
return;
}
if (doUpdate) {
FileUtils fileUtils = FileUtils.newFileUtils();
renamedFile =
fileUtils.createTempFile("zip", ".tmp",
fileUtils.getParentFile(zipFile));
@@ -401,14 +399,13 @@ public class Zip extends MatchingTask {
}
initZipOutputStream(zOut);
// Add the implicit fileset to the archive.
if (baseDir != null) {
addFiles(getDirectoryScanner(baseDir), zOut, "", "",
ZipFileSet.DEFAULT_DIR_MODE,
ZipFileSet.DEFAULT_FILE_MODE);
}
// Add the explicit filesets to the archive.
addFiles(filesets, zOut);
for (int i = 0; i < fss.length; i++) {
if (addThem[i].length != 0) {
addResources(fss[i], addThem[i], zOut);
}
}
if (doUpdate) {
addingNewFiles = false;
ZipFileSet oldFiles = new ZipFileSet();
@@ -418,9 +415,10 @@ public class Zip extends MatchingTask {
PatternSet.NameEntry ne = oldFiles.createExclude();
ne.setName((String) addedFiles.elementAt(i));
}
Vector tmp = new Vector(1);
tmp.addElement(oldFiles);
addFiles(tmp, zOut);
addResources(oldFiles,
oldFiles.getDirectoryScanner(getProject())
.getIncludedFileResources(),
zOut);
}
finalizeZipOutputStream(zOut);
@@ -481,127 +479,101 @@ public class Zip extends MatchingTask {
* Indicates if the task is adding new files into the archive as opposed to
* copying back unchanged files from the backup copy
*/
protected boolean isAddingNewFiles() {
protected final boolean isAddingNewFiles() {
return addingNewFiles;
}
/**
* 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.
*
* @deprecated use six-arg version instead.
*/
protected void addFiles(FileScanner scanner, ZipOutputStream zOut,
String prefix, String fullpath)
throws IOException {
addFiles(scanner, zOut, prefix, fullpath, ZipFileSet.DEFAULT_DIR_MODE,
ZipFileSet.DEFAULT_FILE_MODE);
}
/**
* Add all files of the given FileScanner to the ZipOutputStream
* prependig the given prefix to each filename.
* Add the given resources.
*
* <p>Ensure parent directories have been added as well.
* @param fileset may give additional information like fullpath or
* permissions.
* @param resources the resources to add
* @param zOut the stream to write to
*
* @since Ant 1.6
*/
protected void addFiles(FileScanner scanner, ZipOutputStream zOut,
String prefix, String fullpath, int dirMode,
int fileMode)
protected final void addResources(FileSet fileset, Resource[] resources,
ZipOutputStream zOut)
throws IOException {
String prefix = "";
String fullpath = "";
int dirMode = ZipFileSet.DEFAULT_DIR_MODE;
int fileMode = ZipFileSet.DEFAULT_FILE_MODE;
ZipFileSet zfs = null;
if (fileset instanceof ZipFileSet) {
zfs = (ZipFileSet) fileset;
prefix = zfs.getPrefix();
fullpath = zfs.getFullpath();
dirMode = zfs.getDirMode();
fileMode = zfs.getDirMode();
}
if (prefix.length() > 0 && fullpath.length() > 0) {
throw new BuildException("Both prefix and fullpath attributes must"
+ " not be set on the same fileset.");
}
File thisBaseDir = scanner.getBasedir();
// directories that matched include patterns
String[] dirs = scanner.getIncludedDirectories();
if (dirs.length > 0 && fullpath.length() > 0) {
if (resources.length != 1 && fullpath.length() > 0) {
throw new BuildException("fullpath attribute may only be specified"
+ " for filesets that specify a single"
+ " file.");
}
for (int i = 0; i < dirs.length; i++) {
if ("".equals(dirs[i])) {
continue;
}
String name = dirs[i].replace(File.separatorChar, '/');
if (!name.endsWith("/")) {
name += "/";
}
addParentDirs(thisBaseDir, name, zOut, prefix, dirMode);
}
// files that matched include patterns
String[] files = scanner.getIncludedFiles();
if (files.length > 1 && fullpath.length() > 0) {
throw new BuildException("fullpath attribute may only be specified"
+ " for filesets that specify a single"
+ "file.");
}
for (int i = 0; i < files.length; i++) {
File f = new File(thisBaseDir, files[i]);
if (fullpath.length() > 0) {
// Add this file at the specified location.
addParentDirs(null, fullpath, zOut, "", dirMode);
zipFile(f, zOut, fullpath, fileMode);
} else {
// Add this file with the specified prefix.
String name = files[i].replace(File.separatorChar, '/');
addParentDirs(thisBaseDir, name, zOut, prefix, dirMode);
zipFile(f, zOut, prefix + name, fileMode);
}
if (prefix.length() > 0
&& !prefix.endsWith("/")
&& !prefix.endsWith("\\")) {
prefix += "/";
}
}
protected void addZipEntries(ZipFileSet fs, DirectoryScanner ds,
ZipOutputStream zOut, String prefix,
String fullpath)
throws IOException {
log("adding zip entries: " + fullpath, Project.MSG_VERBOSE);
if (prefix.length() > 0 && fullpath.length() > 0) {
throw new BuildException("Both prefix and fullpath attributes must"
+ " not be set on the same fileset.");
}
ZipScanner zipScanner = (ZipScanner) ds;
File zipSrc = fs.getSrc();
ZipEntry entry;
java.util.zip.ZipEntry origEntry;
ZipInputStream in = null;
ZipFile zf = null;
try {
in = new ZipInputStream(new FileInputStream(zipSrc));
while ((origEntry = in.getNextEntry()) != null) {
entry = new ZipEntry(origEntry);
String vPath = entry.getName();
if (zipScanner.match(vPath)) {
if (fullpath.length() > 0) {
addParentDirs(null, fullpath, zOut, "",
fs.getDirMode());
zipFile(in, zOut, fullpath, entry.getTime(), zipSrc,
fs.getFileMode());
} else {
addParentDirs(null, vPath, zOut, prefix,
fs.getDirMode());
if (!entry.isDirectory()) {
zipFile(in, zOut, prefix + vPath, entry.getTime(),
zipSrc, fs.getFileMode());
}
boolean dealingWithFiles = false;
File base = null;
if (zfs == null || zfs.getSrc() == null) {
dealingWithFiles = true;
base = fileset.getDir(getProject());
} else {
zf = new ZipFile(zfs.getSrc());
}
for (int i = 0; i < resources.length; i++) {
String name = null;
if (fullpath.length() > 0) {
name = fullpath;
} else {
name = resources[i].getName();
}
name = name.replace(File.separatorChar, '/');
if ("".equals(name)) {
continue;
}
if (resources[i].isDirectory() && ! name.endsWith("/")) {
name = name + "/";
}
addParentDirs(base, name, zOut, prefix, dirMode);
if (!resources[i].isDirectory() && dealingWithFiles) {
File f = fileUtils.resolveFile(base,
resources[i].getName());
zipFile(f, zOut, prefix + name, fileMode);
} else if (!resources[i].isDirectory()) {
java.util.zip.ZipEntry ze =
zf.getEntry(resources[i].getName());
if (ze != null) {
zipFile(zf.getInputStream(ze), zOut, prefix + name,
ze.getTime(), zfs.getSrc(), fileMode);
}
}
}
} finally {
if (in != null) {
in.close();
if (zf != null) {
zf .close();
}
}
}
@@ -623,7 +595,7 @@ public class Zip extends MatchingTask {
/**
* Create an empty zip file
*
* @return true if the file is then considered up to date.
* @return true for historic reasons
*/
protected boolean createEmptyZip(File zipFile) {
// In this case using java.util.zip will not work
@@ -657,9 +629,12 @@ public class Zip extends MatchingTask {
return true;
}
/**
* @since Ant 1.6
*/
private synchronized ZipScanner getZipScanner() {
if (zs == null) {
zs=new ZipScanner();
zs = new ZipScanner();
// set the task of the zip scanner so that it can log properly
zs.setTask(this);
zs.setSrc(zipFile);
@@ -668,144 +643,149 @@ public class Zip extends MatchingTask {
}
/**
* Check whether the archive is up-to-date; and handle behavior
* for empty archives.
* @param scanners list of prepared scanners containing files to archive
* Collect the resources that are newer than the corresponding
* entries (or missing) in the original archive.
*
* <p>If we are going to recreate the archive instead of updating
* it, all resources should be considered as new, if a single one
* is. Because of this, subclasses overriding this method must
* call <code>super.getResourcesToAdd</code> and indicate with the
* third arg if they already know that the archive is
* out-of-date.</p>
*
* @param filesets The filesets to grab resources from
* @param zipFile intended archive file (may or may not exist)
* @return true if nothing need be done (may have done something
* already); false if archive creation should proceed
* @param needsUpdate whether we already know that the archive is
* out-of-date. Subclasses overriding this method are supposed to
* set this value correctly in their call to
* super.getResourcesToAdd.
* @return an array of resources to add for each fileset passed in.
*
* @exception BuildException if it likes
*/
protected boolean isUpToDate(ResourceScanner[] scanners,
FileSet[] fss, File zipFile)
protected Resource[][] getResourcesToAdd(FileSet[] filesets,
File zipFile,
boolean needsUpdate)
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) {
Resource[][] initialResources = grabResources(filesets);
if (isEmpty(initialResources)) {
if (emptyBehavior.equals("skip")) {
log("Warning: skipping " + archiveType + " archive " + zipFile +
" because no files were included.", Project.MSG_WARN);
return true ;
log("Warning: skipping " + archiveType + " archive "
+ zipFile + " because no files were included.",
Project.MSG_WARN);
} else if (emptyBehavior.equals("fail")) {
throw new BuildException("Cannot create " + archiveType
+ " archive " + zipFile +
": no files were included.", getLocation());
": no files were included.",
getLocation());
} else {
// Create.
return createEmptyZip(zipFile);
}
} else {
for (int i = 0; i < files.length; ++i) {
if (files[i].equals(zipFile)) {
throw new BuildException("A zip file cannot include "
+ "itself", getLocation());
}
createEmptyZip(zipFile);
}
return initialResources;
}
if (!zipFile.exists()) {
return false;
}
if (!zipFile.exists()) {
return initialResources;
}
if (needsUpdate && !doUpdate) {
// we are recreating the archive, need all resources
return initialResources;
}
for (int i = 0; i < scanners.length; i++) {
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[][] newerResources = new Resource[filesets.length][];
for (int i = 0; i < filesets.length; i++) {
if (!(fileset instanceof ZipFileSet)
|| ((ZipFileSet) fileset).getSrc() == null) {
File base = filesets[i].getDir(getProject());
for (int j = 0; j < initialResources[i].length; j++) {
File resourceAsFile =
fileUtils.resolveFile(base,
initialResources[i][j].getName());
if (resourceAsFile.equals(zipFile)) {
throw new BuildException("A zip file cannot include "
+ "itself", getLocation());
}
}
Resource[] newerSources =
SourceSelector.selectOutOfDateSources(this,
resourceNames[i],
myMapper,
getZipScanner());
result = (newerSources.length == 0);
if (!result) {
return result;
}
}
}
return true;
}
protected static File[] grabFiles(FileScanner[] scanners) {
return grabFiles(scanners, grabFileNames(scanners));
}
protected static File[] grabFiles(FileScanner[] scanners,
String[][] fileNames) {
Vector files = new Vector();
for (int i = 0; i < fileNames.length; i++) {
File thisBaseDir = scanners[i].getBasedir();
for (int j = 0; j < fileNames[i].length; j++) {
files.addElement(new File(thisBaseDir, fileNames[i][j]));
for (int i = 0; i < filesets.length; i++) {
if (initialResources[i].length == 0) {
continue;
}
FileNameMapper myMapper = new IdentityMapper();
if (filesets[i] instanceof ZipFileSet) {
ZipFileSet zfs = (ZipFileSet) filesets[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("*");
String prefix = zfs.getPrefix();
if (!prefix.endsWith("/") && !prefix.endsWith("\\")) {
prefix += "/";
}
gm.setTo(prefix + "*");
myMapper = gm;
}
}
newerResources[i] =
SourceSelector.selectOutOfDateSources(this,
initialResources[i],
myMapper,
getZipScanner());
needsUpdate = needsUpdate || (newerResources[i].length > 0);
if (needsUpdate && !doUpdate) {
// we will return initialResources anyway, no reason
// to scan further.
break;
}
}
File[] toret = new File[files.size()];
files.copyInto(toret);
return toret;
}
protected static String[][] grabFileNames(FileScanner[] scanners) {
String[][] result = new String[scanners.length][];
for (int i = 0; i < scanners.length; i++) {
String[] files = scanners[i].getIncludedFiles();
String[] dirs = scanners[i].getIncludedDirectories();
result[i] = new String[files.length + dirs.length];
System.arraycopy(files, 0, result[i], 0, files.length);
System.arraycopy(dirs, 0, result[i], files.length, dirs.length);
if (needsUpdate && !doUpdate) {
// we are recreating the archive, need all resources
return initialResources;
}
return result;
return newerResources;
}
/**
* Fetch all included and not excluded resources from the sets.
*
* <p>Included directories will preceede included files.</p>
*
* @param scanners here are expected ResourceScanner arguments
* @return double dimensional array of resources
* @since Ant 1.6
*/
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();
protected Resource[][] grabResources(FileSet[] fileset s) {
Resource[][] result = new Resource[fileset s.length][];
for (int i = 0; i < fileset s.length; i++) {
ResourceScanner rs = filesets[i].getDirectoryScanner(getProject() );
Resource[] files = rs.getIncludedFileResources();
Resource[] directories = rs .getIncludedDirectoryResources();
result[i] = new Resource[files.length + directories.length];
System.arraycopy(files, 0, result[i], 0, fil es.length);
System.arraycopy(directories, 0, result[i], fil es.length,
directori es.length);
System.arraycopy(directories, 0, result[i], 0, directori es.length);
System.arraycopy(files, 0, result[i], directori es.length,
fil es.length);
}
return result;
}
/**
* @deprecated use four-arg version instead.
*/
protected void zipDir(File dir, ZipOutputStream zOut, String vPath)
throws IOException {
zipDir(dir, zOut, vPath, ZipFileSet.DEFAULT_DIR_MODE);
}
/**
* @since Ant 1.6
*/
@@ -841,20 +821,20 @@ public class Zip extends MatchingTask {
}
/**
* @deprecated use six-arg version instead .
*/
protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath,
long lastModified, File file)
throws IOException {
zipFile(in, zOut, vPath, lastModified, file,
ZipFileSet.DEFAULT_FILE_MODE);
}
/* *
* Adds a new entry to the archive, takes care of duplicates as well .
*
* @param in the stream to read data for the entry from.
* @param zOut the stream to write to.
* @param vPath the name this entry shall have in the archive.
* @param lastModified last modification time for the entry.
* @param fromArchive the original archive we are copying this
* entry from, will be null if we are not copying from an archive.
* @param mode the Unix permissions to set.
*
* @since Ant 1.6
*/
protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath,
long lastModified, File fil e, int mode)
long lastModified, File fromArchiv e, int mode)
throws IOException {
if (entries.contains(vPath)) {
@@ -939,17 +919,18 @@ public class Zip extends MatchingTask {
}
/**
* @deprecated use six-arg version instead.
*/
protected void zipFile(File file, ZipOutputStream zOut, String vPath)
throws IOException {
zipFile(file, zOut, vPath, ZipFileSet.DEFAULT_FILE_MODE);
}
/**
* Method that gets called when adding from java.io.File instances.
*
* <p>This implementation delegates to the six-arg version.</p>
*
* @param file the file to add to the archive
* @param zOut the stream to write to
* @param vPath the name this entry shall have in the archive
* @param mode the Unix permissions to set.
*
* @since Ant 1.6
*/
protected void zipFile(File file, ZipOutputStream zOut, String vPath,
protected void zipFile(File file, ZipOutputStream zOut, String vPath,
int mode)
throws IOException {
if (file.equals(zipFile)) {
@@ -966,24 +947,14 @@ public class Zip extends MatchingTask {
}
}
/**
* @deprecated use five-arg version instead.
*/
protected void addParentDirs(File baseDir, String entry,
ZipOutputStream zOut, String prefix)
throws IOException {
addParentDirs(baseDir, entry, zOut, prefix,
ZipFileSet.DEFAULT_DIR_MODE);
}
/**
* Ensure all parent dirs of a given entry have been added.
*
* @since Ant 1.6
*/
protected void addParentDirs(File baseDir, String entry,
ZipOutputStream zOut, String prefix,
int dirMode)
protected final void addParentDirs(File baseDir, String entry,
ZipOutputStream zOut, String prefix,
int dirMode)
throws IOException {
if (!doFilesonly) {
Stack directories = new Stack();
@@ -1010,55 +981,6 @@ public class Zip extends MatchingTask {
}
}
/**
* Iterate over the given Vector of (zip)filesets and add
* all files to the ZipOutputStream using the given prefix
* or fullpath.
*/
protected void addFiles(Vector filesets, ZipOutputStream zOut)
throws IOException {
// Add each fileset in the Vector.
for (int i = 0; i < filesets.size(); i++) {
FileSet fs = (FileSet) filesets.elementAt(i);
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
String prefix = "";
String fullpath = "";
int fileMode = ZipFileSet.DEFAULT_FILE_MODE;
int dirMode = ZipFileSet.DEFAULT_DIR_MODE;
if (fs instanceof ZipFileSet) {
ZipFileSet zfs = (ZipFileSet) fs;
prefix = zfs.getPrefix();
fullpath = zfs.getFullpath();
fileMode = zfs.getFileMode();
dirMode = zfs.getDirMode();
}
if (prefix.length() > 0
&& !prefix.endsWith("/")
&& !prefix.endsWith("\\")) {
prefix += "/";
}
// Need to manually add either fullpath's parent directory, or
// the prefix directory, to the archive.
if (prefix.length() > 0) {
addParentDirs(null, prefix, zOut, "", dirMode);
zipDir(null, zOut, prefix, dirMode);
} else if (fullpath.length() > 0) {
addParentDirs(null, fullpath, zOut, "", dirMode);
}
if (fs instanceof ZipFileSet
&& ((ZipFileSet) fs).getSrc() != null) {
addZipEntries((ZipFileSet) fs, ds, zOut, prefix, fullpath);
} else {
// Add the fileset.
addFiles(ds, zOut, prefix, fullpath, dirMode, fileMode);
}
}
}
/**
* Do any clean up necessary to allow this instance to be used again.
*
@@ -1109,6 +1031,20 @@ public class Zip extends MatchingTask {
encoding = null;
}
/**
* @return true if all individual arrays are empty
*
* @since Ant 1.6
*/
protected final static boolean isEmpty(Resource[][] r) {
for (int i = 0; i < r.length; i++) {
if (r[i].length > 0) {
return false;
}
}
return true;
}
/**
* Possible behaviors when a duplicate file is added:
* "add", "preserve" or "fail"