add a flatten to unzip. I actually only patched in the mapper nested element support; with that the flatten attribute can only introduce inconsistency (what if you spec a mapper and flatten=true). And the patch was modified to keep the attributes private, with a getMapper() operation for subclasses (like untar) to get when needed. Did a bit of cleanup -especially of the unzip tests- while at it. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276981 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -15,9 +15,12 @@ carried from the archive file.</p> | |||
| <p><a href="../CoreTypes/patternset.html">PatternSet</a>s are used to select files to extract | |||
| <I>from</I> the archive. If no patternset is used, all files are extracted. | |||
| </p> | |||
| <p><a href="../CoreTypes/fileset.html">FileSet</a>s may be used used to select archived files | |||
| <p><a href="../CoreTypes/fileset.html">FileSet</a>s may be used to select archived files | |||
| to perform unarchival upon. | |||
| </p> | |||
| <p>You can define filename transformations by using a nested <a href="../CoreTypes/mapper.html">mapper</a> element. The default mapper is the | |||
| <a href="../CoreTypes/mapper.html#identity-mapper">identity mapper</a>. | |||
| </p> | |||
| <p>File permissions will not be restored on extracted files.</p> | |||
| <p>The untar task recognizes the long pathname entries used by GNU tar.<p> | |||
| <h3>Parameters</h3> | |||
| @@ -102,6 +105,16 @@ to perform unarchival upon. | |||
| </unzip> | |||
| </pre></p> | |||
| </blockquote> | |||
| <blockquote> | |||
| <p><pre> | |||
| <unzip src="apache-ant-bin.zip" dest="${tools.home}"> | |||
| <patternset> | |||
| <include name="apache-ant/lib/ant.jar"/> | |||
| </patternset> | |||
| <mapper type="flatten"/> | |||
| </unzip> | |||
| </pre></p> | |||
| </blockquote> | |||
| <hr> | |||
| <p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | |||
| Reserved.</p> | |||
| @@ -93,4 +93,33 @@ | |||
| <unzip src="unziptest.zip" dest="unziptestout" encoding="UnicodeBig"/> | |||
| </target> | |||
| <!-- Bugzilla Report 21996 --> | |||
| <target name="testFlattenMapper" depends="prepareTestZip"> | |||
| <unzip dest="unziptestout" src="unziptest.zip"> | |||
| <patternset> | |||
| <include name="1/**"/> | |||
| </patternset> | |||
| <mapper type="flatten"/> | |||
| </unzip> | |||
| </target> | |||
| <!-- Bugzilla Report 21996 --> | |||
| <target name="testGlobMapper" depends="prepareTestZip"> | |||
| <unzip dest="unziptestout" src="unziptest.zip"> | |||
| <patternset> | |||
| <include name="1/**"/> | |||
| </patternset> | |||
| <mapper type="glob" from="*" to="*.txt"/> | |||
| </unzip> | |||
| </target> | |||
| <target name="testTwoMappers" depends="prepareTestZip"> | |||
| <unzip dest="unziptestout" src="unziptest.zip"> | |||
| <patternset> | |||
| <include name="1/**"/> | |||
| </patternset> | |||
| <mapper type="glob" from="*" to="*.txt"/> | |||
| <mapper type="flatten"/> | |||
| </unzip> | |||
| </target> | |||
| </project> | |||
| @@ -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. | |||
| * | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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 | |||
| @@ -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); | |||
| } | |||
| } | |||