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); | |||||
} | } | ||||
} | } |