diff --git a/WHATSNEW b/WHATSNEW index 0c25ab4dc..166269275 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -109,6 +109,11 @@ Fixed bugs: Other changes: -------------- +* Gzip and Bzip2 files can now be constructed in the fly when using + the tar task without having to create the intermediate tar file on + disk. The Untar task can also untar GZip and BZip2 files on the fly + without creating the intermediate tar file. + * New optional type, added. * now allows control over which additional classes and interfaces diff --git a/docs/manual/CoreTasks/tar.html b/docs/manual/CoreTasks/tar.html index d846ec01e..60511f10a 100644 --- a/docs/manual/CoreTasks/tar.html +++ b/docs/manual/CoreTasks/tar.html @@ -41,8 +41,8 @@ attribute is warn which behaves just like the gnu option except that it produces a warning for each file path encountered that does not match the limit.

-

Note that this task does not perform compression. You might want to use the -GZip task to prepare a .tar.gz package.

+

This task can perform compression by setting the compression attribute to "gzip" +or "bzip2".

Parameters

@@ -99,6 +99,13 @@ the limit.

("yes"/"no"). Default excludes are used when omitted. + + + + +
No
compressioncompression method. Allowable values are + "none", "gzip" and "bzip2". Default is + "none".No

Nested Elements

diff --git a/docs/manual/CoreTasks/unzip.html b/docs/manual/CoreTasks/unzip.html index 4dd756c5c..fb8bb6bbb 100644 --- a/docs/manual/CoreTasks/unzip.html +++ b/docs/manual/CoreTasks/unzip.html @@ -44,6 +44,14 @@ to perform unarchival upon. true). No + + compression + compression method for untar. Allowable values are + "none", "gzip" and "bzip2". Default is + "none". + No + +

Examples

@@ -82,7 +90,7 @@ to perform unarchival upon.


-

Copyright © 2001 Apache Software Foundation. All rights +

Copyright © 2001-2002 Apache Software Foundation. All rights Reserved.

diff --git a/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.bz2 b/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.bz2 new file mode 100644 index 000000000..99a91fc46 Binary files /dev/null and b/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.bz2 differ diff --git a/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.gz b/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.gz new file mode 100644 index 000000000..ddd23a240 Binary files /dev/null and b/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.gz differ diff --git a/src/etc/testcases/taskdefs/tar.xml b/src/etc/testcases/taskdefs/tar.xml index 58b56be07..6eb075ac3 100644 --- a/src/etc/testcases/taskdefs/tar.xml +++ b/src/etc/testcases/taskdefs/tar.xml @@ -53,6 +53,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -63,12 +85,25 @@ + + + + + + + diff --git a/src/etc/testcases/taskdefs/untar.xml b/src/etc/testcases/taskdefs/untar.xml index 575240d6c..801045c2a 100644 --- a/src/etc/testcases/taskdefs/untar.xml +++ b/src/etc/testcases/taskdefs/untar.xml @@ -12,10 +12,31 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/Tar.java b/src/main/org/apache/tools/ant/taskdefs/Tar.java index 597951fa9..3f01ae147 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Tar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Tar.java @@ -57,7 +57,9 @@ package org.apache.tools.ant.taskdefs; import java.io.File; import java.io.IOException; import java.io.FileOutputStream; +import java.io.OutputStream; import java.io.FileInputStream; +import java.io.BufferedOutputStream; import java.util.Vector; import java.util.Enumeration; import org.apache.tools.ant.BuildException; @@ -70,11 +72,15 @@ import org.apache.tools.ant.util.MergingMapper; import org.apache.tools.tar.TarOutputStream; import org.apache.tools.tar.TarConstants; import org.apache.tools.tar.TarEntry; +import java.util.zip.GZIPOutputStream; +import org.apache.tools.bzip2.CBZip2OutputStream; + + /** * Creates a TAR archive. * - * @author Stefano Mazzocchi + * @author Stefano Mazzocchi * stefano@apache.org * @author Stefan Bodewig * @author Magesh Umasankar @@ -125,6 +131,8 @@ public class Tar extends MatchingTask { */ private boolean longWarningGiven = false; + private TarCompressionMethod compression = new TarCompressionMethod(); + public TarFileSet createTarFileSet() { TarFileSet fileset = new TarFileSet(); filesets.addElement(fileset); @@ -191,6 +199,18 @@ public class Tar extends MatchingTask { this.longFileMode = mode; } + /** + * Set compression method. + * + * Allowable values are + * none - no compression + * gzip - Gzip compression + * bzip2 - Bzip2 compression + */ + public void setCompression(TarCompressionMethod mode) { + this.compression = mode; + } + public void execute() throws BuildException { if (tarFile == null) { throw new BuildException("tarfile attribute must be set!", @@ -211,7 +231,7 @@ public class Tar extends MatchingTask { try { if (baseDir != null) { if (!baseDir.exists()) { - throw new BuildException("basedir does not exist!", + throw new BuildException("basedir does not exist!", location); } @@ -226,7 +246,7 @@ public class Tar extends MatchingTask { + "attribute or some nested filesets.", location); } - + // check if tar is out of date with respect to each // fileset boolean upToDate = true; @@ -239,7 +259,7 @@ public class Tar extends MatchingTask { } for (int i = 0; i < files.length; ++i) { - if (tarFile.equals(new File(fs.getDir(project), + if (tarFile.equals(new File(fs.getDir(project), files[i]))) { throw new BuildException("A tar file cannot include " + "itself", location); @@ -257,7 +277,10 @@ public class Tar extends MatchingTask { TarOutputStream tOut = null; try { - tOut = new TarOutputStream(new FileOutputStream(tarFile)); + tOut = new TarOutputStream( + compression.compress( + new BufferedOutputStream( + new FileOutputStream(tarFile)))); tOut.setDebug(true); if (longFileMode.isTruncateMode()) { tOut.setLongFileMode(TarOutputStream.LONGFILE_TRUNCATE); @@ -270,13 +293,13 @@ public class Tar extends MatchingTask { } longWarningGiven = false; - for (Enumeration e = filesets.elements(); + for (Enumeration e = filesets.elements(); e.hasMoreElements();) { TarFileSet fs = (TarFileSet) e.nextElement(); String[] files = fs.getFiles(project); if (files.length > 1 && fs.getFullpath().length() > 0) { throw new BuildException("fullpath attribute may only " - + "be specified for " + + "be specified for " + "filesets that specify a " + "single file."); } @@ -315,11 +338,11 @@ public class Tar extends MatchingTask { if (vPath.length() <= 0) { return; } - + if (file.isDirectory() && !vPath.endsWith("/")) { vPath += "/"; } - + String prefix = tarFileSet.getPrefix(); // '/' is appended for compatibility with the zip task. if (prefix.length() > 0 && !prefix.endsWith("/")) { @@ -333,7 +356,7 @@ public class Tar extends MatchingTask { if (l <= 1) { // we would end up adding "" to the archive return; - } + } vPath = vPath.substring(1, l); } @@ -344,11 +367,11 @@ public class Tar extends MatchingTask { return; } else if (longFileMode.isWarnMode()) { log("Entry: " + vPath + " longer than " + - TarConstants.NAMELEN + " characters.", + TarConstants.NAMELEN + " characters.", Project.MSG_WARN); if (!longWarningGiven) { log("Resulting tar file can only be processed " - + "successfully by GNU compatible tar commands", + + "successfully by GNU compatible tar commands", Project.MSG_WARN); longWarningGiven = true; } @@ -406,7 +429,7 @@ public class Tar extends MatchingTask { private String prefix = ""; private String fullpath = ""; private boolean preserveLeadingSlashes = false; - + public TarFileSet(FileSet fileset) { super(fileset); } @@ -528,4 +551,65 @@ public class Tar extends MatchingTask { return OMIT.equalsIgnoreCase(getValue()); } } + + /** + * Valid Modes for Compression attribute to Tar Task + * + */ + public static final class TarCompressionMethod extends EnumeratedAttribute { + + // permissable values for compression attribute + /** + * No compression + */ + private static final String NONE = "none"; + /** + * GZIP compression + */ + private static final String GZIP = "gzip"; + /** + * BZIP2 compression + */ + private static final String BZIP2 = "bzip2"; + + + /** + * Default constructor + */ + public TarCompressionMethod() { + super(); + setValue(NONE); + } + + /** + * Get valid enumeration values. + * @return valid enumeration values + */ + public String[] getValues() { + return new String[] { NONE, GZIP, BZIP2 }; + } + + /** + * This method wraps the output stream with the + * corresponding compression method + * + * @param ostream output stream + * @return output stream with on-the-fly compression + * @exception IOException thrown if file is not writable + */ + private OutputStream compress(final OutputStream ostream) + throws IOException { + final String value = getValue(); + if (GZIP.equals(value)) { + return new GZIPOutputStream(ostream); + } else { + if (BZIP2.equals(value)) { + ostream.write('B'); + ostream.write('Z'); + return new CBZip2OutputStream(ostream); + } + } + return ostream; + } + } } diff --git a/src/main/org/apache/tools/ant/taskdefs/Untar.java b/src/main/org/apache/tools/ant/taskdefs/Untar.java index 8a332092e..dbc520e65 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Untar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Untar.java @@ -61,7 +61,13 @@ import org.apache.tools.tar.TarEntry; import org.apache.tools.ant.util.FileUtils; import java.io.File; import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.InputStream; import java.io.IOException; +import java.util.zip.GZIPInputStream; +import org.apache.tools.bzip2.CBZip2InputStream; +import org.apache.tools.ant.types.EnumeratedAttribute; + /** @@ -75,13 +81,33 @@ import java.io.IOException; * @ant.task category="packaging" */ public class Untar extends Expand { + /** + * compression method + */ + private UntarCompressionMethod compression = new UntarCompressionMethod(); + + /** + * Set compression method. + * + * Allowable values are + * none - no compression + * gzip - Gzip compression + * bzip2 - Bzip2 compression + * + * @param method compression method + */ + public void setCompression(UntarCompressionMethod method) { + compression = method; + } protected void expandFile(FileUtils fileUtils, File srcF, File dir) { TarInputStream tis = null; try { log("Expanding: " + srcF + " into " + dir, Project.MSG_INFO); - - tis = new TarInputStream(new FileInputStream(srcF)); + tis = new TarInputStream( + compression.decompress(srcF, + new BufferedInputStream( + new FileInputStream(srcF)))); TarEntry te = null; while ((te = tis.getNextEntry()) != null) { @@ -101,4 +127,76 @@ public class Untar extends Expand { } } } + + /** + * Valid Modes for Compression attribute to Untar Task + * + */ + public static final class UntarCompressionMethod + extends EnumeratedAttribute { + + // permissable values for compression attribute + /** + * No compression + */ + private static final String NONE = "none"; + /** + * GZIP compression + */ + private static final String GZIP = "gzip"; + /** + * BZIP2 compression + */ + private static final String BZIP2 = "bzip2"; + + + /** + * Constructor + */ + public UntarCompressionMethod() { + super(); + setValue(NONE); + } + + /** + * Get valid enumeration values + * + * @return valid values + */ + public String[] getValues() { + return new String[] { NONE, GZIP, BZIP2 }; + } + + /** + * This method wraps the input stream with the + * corresponding decompression method + * + * @param file provides location information for BuildException + * @param istream input stream + * @return input stream with on-the-fly decompression + * @exception IOException thrown by GZIPInputStream constructor + * @exception BuildException thrown if bzip stream does not + * start with expected magic values + */ + private InputStream decompress(final File file, + final InputStream istream) + throws IOException, BuildException { + final String value = getValue(); + if (GZIP.equals(value)) { + return new GZIPInputStream(istream); + } else { + if (BZIP2.equals(value)) { + final char[] magic = new char[] { 'B', 'Z' }; + for (int i = 0; i < magic.length; i++) { + if (istream.read() != magic[i]) { + throw new BuildException( + "Invalid bz2 file." + file.toString()); + } + } + return new CBZip2InputStream(istream); + } + } + return istream; + } + } } diff --git a/src/main/org/apache/tools/bzip2/CBZip2InputStream.java b/src/main/org/apache/tools/bzip2/CBZip2InputStream.java index 9691bdb53..ef6404ad5 100644 --- a/src/main/org/apache/tools/bzip2/CBZip2InputStream.java +++ b/src/main/org/apache/tools/bzip2/CBZip2InputStream.java @@ -298,7 +298,15 @@ public class CBZip2InputStream extends InputStream implements BZip2Constants { } private void bsFinishedWithStream() { - bsStream = null; + try { + if (this.bsStream != null) { + if (this.bsStream != System.in) { + this.bsStream.close(); + this.bsStream= null; + } + } + } catch (IOException ioe) { + } } private void bsSetStream(InputStream f) { diff --git a/src/testcases/org/apache/tools/ant/taskdefs/TarTest.java b/src/testcases/org/apache/tools/ant/taskdefs/TarTest.java index 76b9d7210..05be9e8e2 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/TarTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/TarTest.java @@ -124,6 +124,29 @@ public class TarTest extends BuildFileTest { } } + public void test9() { + expectBuildException("test9", "Invalid value specified for compression attribute."); + } + + public void test10() { + executeTarget("test10"); + java.io.File f1 + = new java.io.File("src/etc/testcases/taskdefs/test10.xml"); + if (! f1.exists()) { + fail("The fullpath attribute or the preserveLeadingSlashes attribute does not work propertly"); + } + } + + public void test11() { + executeTarget("test11"); + java.io.File f1 + = new java.io.File("src/etc/testcases/taskdefs/test11.xml"); + if (! f1.exists()) { + fail("The fullpath attribute or the preserveLeadingSlashes attribute does not work propertly"); + } + } + + public void tearDown() { executeTarget("cleanup"); } diff --git a/src/testcases/org/apache/tools/ant/taskdefs/UntarTest.java b/src/testcases/org/apache/tools/ant/taskdefs/UntarTest.java index a180314a3..b93877975 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/UntarTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/UntarTest.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2001 The Apache Software Foundation. All rights + * Copyright (c) 2001-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -82,6 +82,20 @@ public class UntarTest extends BuildFileTest { project.resolveFile("asf-logo.gif"))); } + public void testRealGzipTest() throws java.io.IOException { + FileUtils fileUtils = FileUtils.newFileUtils(); + executeTarget("realGzipTest"); + assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"), + project.resolveFile("asf-logo.gif"))); + } + + public void testRealBzip2Test() throws java.io.IOException { + FileUtils fileUtils = FileUtils.newFileUtils(); + executeTarget("realBzip2Test"); + assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"), + project.resolveFile("asf-logo.gif"))); + } + public void testTestTarTask() throws java.io.IOException { FileUtils fileUtils = FileUtils.newFileUtils(); executeTarget("testTarTask"); @@ -89,6 +103,20 @@ public class UntarTest extends BuildFileTest { project.resolveFile("asf-logo.gif"))); } + public void testTestGzipTarTask() throws java.io.IOException { + FileUtils fileUtils = FileUtils.newFileUtils(); + executeTarget("testGzipTarTask"); + assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"), + project.resolveFile("asf-logo.gif"))); + } + + public void testTestBzip2TarTask() throws java.io.IOException { + FileUtils fileUtils = FileUtils.newFileUtils(); + executeTarget("testBzip2TarTask"); + assertTrue(fileUtils.contentEquals(project.resolveFile("../asf-logo.gif"), + project.resolveFile("asf-logo.gif"))); + } + public void testSrcDirTest() throws java.io.IOException { FileUtils fileUtils = FileUtils.newFileUtils(); expectBuildException("srcDirTest", "Src cannot be a directory.");