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 | <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. | <I>from</I> the archive. If no patternset is used, all files are extracted. | ||||
| </p> | </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. | to perform unarchival upon. | ||||
| </p> | </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>File permissions will not be restored on extracted files.</p> | ||||
| <p>The untar task recognizes the long pathname entries used by GNU tar.<p> | <p>The untar task recognizes the long pathname entries used by GNU tar.<p> | ||||
| <h3>Parameters</h3> | <h3>Parameters</h3> | ||||
| @@ -102,6 +105,16 @@ to perform unarchival upon. | |||||
| </unzip> | </unzip> | ||||
| </pre></p> | </pre></p> | ||||
| </blockquote> | </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> | <hr> | ||||
| <p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | <p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -93,4 +93,33 @@ | |||||
| <unzip src="unziptest.zip" dest="unziptestout" encoding="UnicodeBig"/> | <unzip src="unziptest.zip" dest="unziptestout" encoding="UnicodeBig"/> | ||||
| </target> | </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> | </project> | ||||
| @@ -30,9 +30,13 @@ import org.apache.tools.ant.DirectoryScanner; | |||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
| import org.apache.tools.ant.types.FileSet; | 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.PatternSet; | ||||
| import org.apache.tools.ant.types.selectors.SelectorUtils; | 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.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.ZipEntry; | ||||
| import org.apache.tools.zip.ZipFile; | import org.apache.tools.zip.ZipFile; | ||||
| @@ -50,12 +54,14 @@ public class Expand extends Task { | |||||
| private File dest; //req | private File dest; //req | ||||
| private File source; // req | private File source; // req | ||||
| private boolean overwrite = true; | private boolean overwrite = true; | ||||
| private Mapper mapperElement = null; | |||||
| private Vector patternsets = new Vector(); | private Vector patternsets = new Vector(); | ||||
| private Vector filesets = new Vector(); | private Vector filesets = new Vector(); | ||||
| private static final String NATIVE_ENCODING = "native-encoding"; | private static final String NATIVE_ENCODING = "native-encoding"; | ||||
| private String encoding = "UTF8"; | private String encoding = "UTF8"; | ||||
| public static final String ERROR_MULTIPLE_MAPPERS = "Cannot define more than one mapper"; | |||||
| /** | /** | ||||
| * Do the work. | * Do the work. | ||||
| @@ -106,12 +112,17 @@ public class Expand extends Task { | |||||
| } | } | ||||
| } | } | ||||
| /* | |||||
| /** | |||||
| * This method is to be overridden by extending unarchival tasks. | * 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) { | protected void expandFile(FileUtils fileUtils, File srcF, File dir) { | ||||
| log("Expanding: " + srcF + " into " + dir, Project.MSG_INFO); | log("Expanding: " + srcF + " into " + dir, Project.MSG_INFO); | ||||
| ZipFile zf = null; | ZipFile zf = null; | ||||
| FileNameMapper mapper = getMapper(); | |||||
| try { | try { | ||||
| zf = new ZipFile(srcF, encoding); | zf = new ZipFile(srcF, encoding); | ||||
| Enumeration e = zf.getEntries(); | Enumeration e = zf.getEntries(); | ||||
| @@ -119,7 +130,7 @@ public class Expand extends Task { | |||||
| ZipEntry ze = (ZipEntry) e.nextElement(); | ZipEntry ze = (ZipEntry) e.nextElement(); | ||||
| extractFile(fileUtils, srcF, dir, zf.getInputStream(ze), | extractFile(fileUtils, srcF, dir, zf.getInputStream(ze), | ||||
| ze.getName(), new Date(ze.getTime()), | ze.getName(), new Date(ze.getTime()), | ||||
| ze.isDirectory()); | |||||
| ze.isDirectory(), mapper); | |||||
| } | } | ||||
| log("expand complete", Project.MSG_VERBOSE); | log("expand complete", Project.MSG_VERBOSE); | ||||
| @@ -127,20 +138,40 @@ public class Expand extends Task { | |||||
| throw new BuildException("Error while expanding " + srcF.getPath(), | throw new BuildException("Error while expanding " + srcF.getPath(), | ||||
| ioe); | ioe); | ||||
| } finally { | } 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, | protected void extractFile(FileUtils fileUtils, File srcF, File dir, | ||||
| InputStream compressedInputStream, | InputStream compressedInputStream, | ||||
| String entryName, | |||||
| Date entryDate, boolean isDirectory) | |||||
| String entryName, Date entryDate, | |||||
| boolean isDirectory, FileNameMapper mapper) | |||||
| throws IOException { | throws IOException { | ||||
| if (patternsets != null && patternsets.size() > 0) { | if (patternsets != null && patternsets.size() > 0) { | ||||
| @@ -194,7 +225,11 @@ public class Expand extends Task { | |||||
| return; | 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 { | try { | ||||
| if (!overwrite && f.exists() | if (!overwrite && f.exists() | ||||
| && f.lastModified() >= entryDate.getTime()) { | && f.lastModified() >= entryDate.getTime()) { | ||||
| @@ -286,6 +321,21 @@ public class Expand extends Task { | |||||
| filesets.addElement(set); | 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. | * 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.BuildException; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.types.EnumeratedAttribute; | 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.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.bzip2.CBZip2InputStream; | ||||
| import org.apache.tools.tar.TarEntry; | import org.apache.tools.tar.TarEntry; | ||||
| import org.apache.tools.tar.TarInputStream; | import org.apache.tools.tar.TarInputStream; | ||||
| @@ -92,10 +95,11 @@ public class Untar extends Expand { | |||||
| new BufferedInputStream( | new BufferedInputStream( | ||||
| new FileInputStream(srcF)))); | new FileInputStream(srcF)))); | ||||
| TarEntry te = null; | TarEntry te = null; | ||||
| FileNameMapper mapper = getMapper(); | |||||
| while ((te = tis.getNextEntry()) != null) { | while ((te = tis.getNextEntry()) != null) { | ||||
| extractFile(fileUtils, srcF, dir, tis, | extractFile(fileUtils, srcF, dir, tis, | ||||
| te.getName(), te.getModTime(), te.isDirectory()); | |||||
| te.getName(), te.getModTime(), | |||||
| te.isDirectory(), mapper); | |||||
| } | } | ||||
| log("expand complete", Project.MSG_VERBOSE); | log("expand complete", Project.MSG_VERBOSE); | ||||
| @@ -103,13 +107,7 @@ public class Untar extends Expand { | |||||
| throw new BuildException("Error while expanding " + srcF.getPath(), | throw new BuildException("Error while expanding " + srcF.getPath(), | ||||
| ioe, getLocation()); | ioe, getLocation()); | ||||
| } finally { | } finally { | ||||
| if (tis != null) { | |||||
| try { | |||||
| tis.close(); | |||||
| } catch (IOException e) { | |||||
| // ignore | |||||
| } | |||||
| } | |||||
| FileUtils.close(tis); | |||||
| } | } | ||||
| } | } | ||||
| @@ -160,6 +160,21 @@ public class ZipFile { | |||||
| archive.close(); | 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. | * Returns all entries. | ||||
| * @return all entries as {@link ZipEntry} instances | * @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.BuildFileTest; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import java.io.IOException; | |||||
| /** | /** | ||||
| */ | */ | ||||
| public class UnzipTest extends BuildFileTest { | public class UnzipTest extends BuildFileTest { | ||||
| @@ -49,24 +51,28 @@ public class UnzipTest extends BuildFileTest { | |||||
| public void testRealTest() throws java.io.IOException { | public void testRealTest() throws java.io.IOException { | ||||
| FileUtils fileUtils = FileUtils.newFileUtils(); | |||||
| executeTarget("realTest"); | 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"), | assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"), | ||||
| project.resolveFile("asf-logo.gif"))); | project.resolveFile("asf-logo.gif"))); | ||||
| } | } | ||||
| public void testTestZipTask() throws java.io.IOException { | public void testTestZipTask() throws java.io.IOException { | ||||
| FileUtils fileUtils = FileUtils.newFileUtils(); | |||||
| executeTarget("testZipTask"); | executeTarget("testZipTask"); | ||||
| assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"), | |||||
| project.resolveFile("asf-logo.gif"))); | |||||
| assertLogoUncorrupted(); | |||||
| } | } | ||||
| public void testTestUncompressedZipTask() throws java.io.IOException { | public void testTestUncompressedZipTask() throws java.io.IOException { | ||||
| FileUtils fileUtils = FileUtils.newFileUtils(); | |||||
| executeTarget("testUncompressedZipTask"); | 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() { | public void testPatternSetExcludeOnly() { | ||||
| executeTarget("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() { | public void testPatternSetIncludeOnly() { | ||||
| executeTarget("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() { | public void testPatternSetIncludeAndExclude() { | ||||
| executeTarget("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() { | public void testPatternSetSlashOnly() { | ||||
| executeTarget("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 | * PR 10504 | ||||
| */ | */ | ||||
| public void testEncoding() { | public void testEncoding() { | ||||
| executeTarget("encodingTest"); | 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); | |||||
| } | } | ||||
| } | } | ||||