diff --git a/docs/manual/CoreTasks/unzip.html b/docs/manual/CoreTasks/unzip.html
index 5e578404b..8f9bbfe9a 100644
--- a/docs/manual/CoreTasks/unzip.html
+++ b/docs/manual/CoreTasks/unzip.html
@@ -15,9 +15,12 @@ carried from the archive file.
PatternSets are used to select files to extract
from the archive. If no patternset is used, all files are extracted.
-FileSets may be used used to select archived files
+
FileSets may be used to select archived files
to perform unarchival upon.
+You can define filename transformations by using a nested mapper element. The default mapper is the
+identity mapper.
+
File permissions will not be restored on extracted files.
The untar task recognizes the long pathname entries used by GNU tar.
Parameters
@@ -102,6 +105,16 @@ to perform unarchival upon.
</unzip>
+
+
+<unzip src="apache-ant-bin.zip" dest="${tools.home}">
+ <patternset>
+ <include name="apache-ant/lib/ant.jar"/>
+ </patternset>
+ <mapper type="flatten"/>
+</unzip>
+
+
Copyright © 2000-2004 The Apache Software Foundation. All rights
Reserved.
diff --git a/src/etc/testcases/taskdefs/unzip.xml b/src/etc/testcases/taskdefs/unzip.xml
index 80f902b17..18d2345da 100644
--- a/src/etc/testcases/taskdefs/unzip.xml
+++ b/src/etc/testcases/taskdefs/unzip.xml
@@ -93,4 +93,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/apache/tools/ant/taskdefs/Expand.java b/src/main/org/apache/tools/ant/taskdefs/Expand.java
index 3af5a1264..b4f547814 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Expand.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Expand.java
@@ -30,9 +30,13 @@ import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
import org.apache.tools.ant.types.PatternSet;
import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.FlatFileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
@@ -50,12 +54,14 @@ public class Expand extends Task {
private File dest; //req
private File source; // req
private boolean overwrite = true;
+ private Mapper mapperElement = null;
private Vector patternsets = new Vector();
private Vector filesets = new Vector();
private static final String NATIVE_ENCODING = "native-encoding";
private String encoding = "UTF8";
+ public static final String ERROR_MULTIPLE_MAPPERS = "Cannot define more than one mapper";
/**
* Do the work.
@@ -106,12 +112,17 @@ public class Expand extends Task {
}
}
- /*
+ /**
* This method is to be overridden by extending unarchival tasks.
+ *
+ * @param fileUtils
+ * @param srcF
+ * @param dir
*/
protected void expandFile(FileUtils fileUtils, File srcF, File dir) {
log("Expanding: " + srcF + " into " + dir, Project.MSG_INFO);
ZipFile zf = null;
+ FileNameMapper mapper = getMapper();
try {
zf = new ZipFile(srcF, encoding);
Enumeration e = zf.getEntries();
@@ -119,7 +130,7 @@ public class Expand extends Task {
ZipEntry ze = (ZipEntry) e.nextElement();
extractFile(fileUtils, srcF, dir, zf.getInputStream(ze),
ze.getName(), new Date(ze.getTime()),
- ze.isDirectory());
+ ze.isDirectory(), mapper);
}
log("expand complete", Project.MSG_VERBOSE);
@@ -127,20 +138,40 @@ public class Expand extends Task {
throw new BuildException("Error while expanding " + srcF.getPath(),
ioe);
} finally {
- if (zf != null) {
- try {
- zf.close();
- } catch (IOException e) {
- //ignore
- }
- }
+ ZipFile.closeQuietly(zf);
+ }
+ }
+
+ /**
+ * get a mapper for a file
+ * @return
+ */
+ protected FileNameMapper getMapper() {
+ FileNameMapper mapper = null;
+ if (mapperElement != null) {
+ mapper = mapperElement.getImplementation();
+ } else {
+ mapper = new IdentityMapper();
}
+ return mapper;
}
+ /**
+ * extract a file to a directory
+ * @param fileUtils
+ * @param srcF
+ * @param dir
+ * @param compressedInputStream
+ * @param entryName
+ * @param entryDate
+ * @param isDirectory
+ * @param mapper
+ * @throws IOException
+ */
protected void extractFile(FileUtils fileUtils, File srcF, File dir,
InputStream compressedInputStream,
- String entryName,
- Date entryDate, boolean isDirectory)
+ String entryName, Date entryDate,
+ boolean isDirectory, FileNameMapper mapper)
throws IOException {
if (patternsets != null && patternsets.size() > 0) {
@@ -194,7 +225,11 @@ public class Expand extends Task {
return;
}
}
- File f = fileUtils.resolveFile(dir, entryName);
+ String[] mappedNames = mapper.mapFileName(entryName);
+ if (mappedNames == null || mappedNames.length == 0) {
+ mappedNames = new String[] { entryName };
+ }
+ File f = fileUtils.resolveFile(dir, mappedNames[0]);
try {
if (!overwrite && f.exists()
&& f.lastModified() >= entryDate.getTime()) {
@@ -286,6 +321,21 @@ public class Expand extends Task {
filesets.addElement(set);
}
+ /**
+ * Defines the mapper to map source entries to destination files.
+ * @return a mapper to be configured
+ * @exception BuildException if more than one mapper is defined
+ * @since Ant1.7
+ */
+ public Mapper createMapper() throws BuildException {
+ if (mapperElement != null) {
+ throw new BuildException(ERROR_MULTIPLE_MAPPERS,
+ getLocation());
+ }
+ mapperElement = new Mapper(getProject());
+ return mapperElement;
+ }
+
/**
* Sets the encoding to assume for file names and comments.
*
diff --git a/src/main/org/apache/tools/ant/taskdefs/Untar.java b/src/main/org/apache/tools/ant/taskdefs/Untar.java
index 06f6b401e..fce05146e 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Untar.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Untar.java
@@ -26,7 +26,10 @@ import java.util.zip.GZIPInputStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.FlatFileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
import org.apache.tools.bzip2.CBZip2InputStream;
import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
@@ -92,10 +95,11 @@ public class Untar extends Expand {
new BufferedInputStream(
new FileInputStream(srcF))));
TarEntry te = null;
-
+ FileNameMapper mapper = getMapper();
while ((te = tis.getNextEntry()) != null) {
extractFile(fileUtils, srcF, dir, tis,
- te.getName(), te.getModTime(), te.isDirectory());
+ te.getName(), te.getModTime(),
+ te.isDirectory(), mapper);
}
log("expand complete", Project.MSG_VERBOSE);
@@ -103,13 +107,7 @@ public class Untar extends Expand {
throw new BuildException("Error while expanding " + srcF.getPath(),
ioe, getLocation());
} finally {
- if (tis != null) {
- try {
- tis.close();
- } catch (IOException e) {
- // ignore
- }
- }
+ FileUtils.close(tis);
}
}
diff --git a/src/main/org/apache/tools/zip/ZipFile.java b/src/main/org/apache/tools/zip/ZipFile.java
index 6afa720dd..6710c7412 100644
--- a/src/main/org/apache/tools/zip/ZipFile.java
+++ b/src/main/org/apache/tools/zip/ZipFile.java
@@ -160,6 +160,21 @@ public class ZipFile {
archive.close();
}
+ /**
+ * close a zipfile quietly; throw no io fault, do nothing
+ * on a null parameter
+ * @param zipfile file to close, can be null
+ */
+ public static void closeQuietly(ZipFile zipfile) {
+ if (zipfile != null) {
+ try {
+ zipfile.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
/**
* Returns all entries.
* @return all entries as {@link ZipEntry} instances
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/UnzipTest.java b/src/testcases/org/apache/tools/ant/taskdefs/UnzipTest.java
index 5326bcb9f..9b7010f42 100644
--- a/src/testcases/org/apache/tools/ant/taskdefs/UnzipTest.java
+++ b/src/testcases/org/apache/tools/ant/taskdefs/UnzipTest.java
@@ -19,6 +19,8 @@ package org.apache.tools.ant.taskdefs;
import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.util.FileUtils;
+import java.io.IOException;
+
/**
*/
public class UnzipTest extends BuildFileTest {
@@ -49,24 +51,28 @@ public class UnzipTest extends BuildFileTest {
public void testRealTest() throws java.io.IOException {
- FileUtils fileUtils = FileUtils.newFileUtils();
executeTarget("realTest");
+ assertLogoUncorrupted();
+ }
+
+ /**
+ * test that the logo gif file has not been corrupted
+ * @throws IOException
+ */
+ private void assertLogoUncorrupted() throws IOException {
+ FileUtils fileUtils = FileUtils.newFileUtils();
assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"),
project.resolveFile("asf-logo.gif")));
}
public void testTestZipTask() throws java.io.IOException {
- FileUtils fileUtils = FileUtils.newFileUtils();
executeTarget("testZipTask");
- assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"),
- project.resolveFile("asf-logo.gif")));
+ assertLogoUncorrupted();
}
public void testTestUncompressedZipTask() throws java.io.IOException {
- FileUtils fileUtils = FileUtils.newFileUtils();
executeTarget("testUncompressedZipTask");
- assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"),
- project.resolveFile("asf-logo.gif")));
+ assertLogoUncorrupted();
}
/*
@@ -74,10 +80,8 @@ public class UnzipTest extends BuildFileTest {
*/
public void testPatternSetExcludeOnly() {
executeTarget("testPatternSetExcludeOnly");
- assertTrue("1/foo is excluded",
- !getProject().resolveFile("unziptestout/1/foo").exists());
- assertTrue("2/bar is not excluded",
- getProject().resolveFile("unziptestout/2/bar").exists());
+ assertFileMissing("1/foo is excluded", "unziptestout/1/foo");
+ assertFileExists("2/bar is not excluded", "unziptestout/2/bar");
}
/*
@@ -85,10 +89,8 @@ public class UnzipTest extends BuildFileTest {
*/
public void testPatternSetIncludeOnly() {
executeTarget("testPatternSetIncludeOnly");
- assertTrue("1/foo is not included",
- !getProject().resolveFile("unziptestout/1/foo").exists());
- assertTrue("2/bar is included",
- getProject().resolveFile("unziptestout/2/bar").exists());
+ assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+ assertFileExists("2/bar is included", "unziptestout/2/bar");
}
/*
@@ -96,10 +98,8 @@ public class UnzipTest extends BuildFileTest {
*/
public void testPatternSetIncludeAndExclude() {
executeTarget("testPatternSetIncludeAndExclude");
- assertTrue("1/foo is not included",
- !getProject().resolveFile("unziptestout/1/foo").exists());
- assertTrue("2/bar is excluded",
- !getProject().resolveFile("unziptestout/2/bar").exists());
+ assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+ assertFileMissing("2/bar is excluded", "unziptestout/2/bar");
}
/*
@@ -115,19 +115,60 @@ public class UnzipTest extends BuildFileTest {
*/
public void testPatternSetSlashOnly() {
executeTarget("testPatternSetSlashOnly");
- assertTrue("1/foo is not included",
- !getProject().resolveFile("unziptestout/1/foo").exists());
- assertTrue("2/bar is included",
- getProject().resolveFile("unziptestout/2/bar").exists());
+ assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+ assertFileExists("\"2/bar is included", "unziptestout/2/bar");
}
+
/*
* PR 10504
*/
public void testEncoding() {
executeTarget("encodingTest");
- assertTrue("foo has been properly named",
- getProject().resolveFile("unziptestout/foo").exists());
+ assertFileExists("foo has been properly named", "unziptestout/foo");
+ }
+
+ /*
+ * PR 21996
+ */
+ public void testFlattenMapper() {
+ executeTarget("testFlattenMapper");
+ assertFileMissing("1/foo is not flattened", "unziptestout/1/foo");
+ assertFileExists("foo is flattened", "unziptestout/foo");
+ }
+
+ /**
+ * assert that a file exists, relative to the project
+ * @param message message if there is no mpatch
+ * @param filename filename to resolve against the project
+ */
+ private void assertFileExists(String message, String filename) {
+ assertTrue(message,
+ getProject().resolveFile(filename).exists());
+ }
+
+ /**
+ * assert that a file doesnt exist, relative to the project
+ *
+ * @param message message if there is no mpatch
+ * @param filename filename to resolve against the project
+ */
+ private void assertFileMissing(String message, String filename) {
+ assertTrue(message,
+ !getProject().resolveFile(filename).exists());
+ }
+
+ /**
+ * PR 21996
+ */
+ public void testGlobMapper() {
+ executeTarget("testGlobMapper");
+ assertFileMissing("1/foo is not mapped", "unziptestout/1/foo");
+ assertFileExists("1/foo is mapped", "unziptestout/1/foo.txt");
+ }
+
+ public void testTwoMappers() {
+ expectBuildException("testTwoMappers",Expand.ERROR_MULTIPLE_MAPPERS);
}
}