/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package org.apache.tools.ant.taskdefs;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.zip.GZIPOutputStream;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.ArchiveFileSet;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.ArchiveResource;
import org.apache.tools.ant.types.resources.FileProvider;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.types.resources.TarResource;
import org.apache.tools.ant.types.selectors.SelectorUtils;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.MergingMapper;
import org.apache.tools.ant.util.ResourceUtils;
import org.apache.tools.ant.util.SourceFileScanner;
import org.apache.tools.bzip2.CBZip2OutputStream;
import org.apache.tools.tar.TarConstants;
import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarOutputStream;

Creates a tar archive.
Since:Ant 1.1
@ant.taskcategory="packaging"
/** * Creates a tar archive. * * @since Ant 1.1 * * @ant.task category="packaging" */
public class Tar extends MatchingTask { private static final int BUFFER_SIZE = 8 * 1024;
Deprecated:since 1.5.x. Tar.WARN is deprecated and is replaced with Tar.TarLongFileMode.WARN
/** * @deprecated since 1.5.x. * Tar.WARN is deprecated and is replaced with * Tar.TarLongFileMode.WARN */
@Deprecated public static final String WARN = "warn";
Deprecated:since 1.5.x. Tar.FAIL is deprecated and is replaced with Tar.TarLongFileMode.FAIL
/** * @deprecated since 1.5.x. * Tar.FAIL is deprecated and is replaced with * Tar.TarLongFileMode.FAIL */
@Deprecated public static final String FAIL = "fail";
Deprecated:since 1.5.x. Tar.TRUNCATE is deprecated and is replaced with Tar.TarLongFileMode.TRUNCATE
/** * @deprecated since 1.5.x. * Tar.TRUNCATE is deprecated and is replaced with * Tar.TarLongFileMode.TRUNCATE */
@Deprecated public static final String TRUNCATE = "truncate";
Deprecated:since 1.5.x. Tar.GNU is deprecated and is replaced with Tar.TarLongFileMode.GNU
/** * @deprecated since 1.5.x. * Tar.GNU is deprecated and is replaced with * Tar.TarLongFileMode.GNU */
@Deprecated public static final String GNU = "gnu";
Deprecated:since 1.5.x. Tar.OMIT is deprecated and is replaced with Tar.TarLongFileMode.OMIT
/** * @deprecated since 1.5.x. * Tar.OMIT is deprecated and is replaced with * Tar.TarLongFileMode.OMIT */
@Deprecated public static final String OMIT = "omit"; // CheckStyle:VisibilityModifier OFF - bc File tarFile; File baseDir; private TarLongFileMode longFileMode = new TarLongFileMode(); // need to keep the package private version for backwards compatibility Vector<TarFileSet> filesets = new Vector<>(); // we must keep two lists since other classes may modify the // filesets Vector (it is package private) without us noticing private final List<ResourceCollection> resourceCollections = new Vector<>(); // CheckStyle:VisibilityModifier ON
Indicates whether the user has been warned about long files already.
/** * Indicates whether the user has been warned about long files already. */
private boolean longWarningGiven = false; private TarCompressionMethod compression = new TarCompressionMethod();
Encoding to use for filenames, defaults to the platform's default encoding.
/** * Encoding to use for filenames, defaults to the platform's * default encoding. */
private String encoding;
Add a new fileset with the option to specify permissions
Returns:the tar fileset to be used as the nested element.
/** * Add a new fileset with the option to specify permissions * @return the tar fileset to be used as the nested element. */
public TarFileSet createTarFileSet() { final TarFileSet fs = new TarFileSet(); fs.setProject(getProject()); filesets.addElement(fs); return fs; }
Add a collection of resources to archive.
Params:
  • res – a resource collection to archive.
Since:Ant 1.7
/** * Add a collection of resources to archive. * @param res a resource collection to archive. * @since Ant 1.7 */
public void add(final ResourceCollection res) { resourceCollections.add(res); }
Set is the name/location of where to create the tar file.
Params:
  • tarFile – the location of the tar file.
Deprecated:since 1.5.x. For consistency with other tasks, please use setDestFile().
/** * Set is the name/location of where to create the tar file. * @param tarFile the location of the tar file. * @deprecated since 1.5.x. * For consistency with other tasks, please use setDestFile(). */
@Deprecated public void setTarfile(final File tarFile) { this.tarFile = tarFile; }
Set is the name/location of where to create the tar file.
Params:
  • destFile – The output of the tar
Since:Ant 1.5
/** * Set is the name/location of where to create the tar file. * @since Ant 1.5 * @param destFile The output of the tar */
public void setDestFile(final File destFile) { this.tarFile = destFile; }
This is the base directory to look in for things to tar.
Params:
  • baseDir – the base directory.
/** * This is the base directory to look in for things to tar. * @param baseDir the base directory. */
public void setBasedir(final File baseDir) { this.baseDir = baseDir; }
Set how to handle long files, those with a path>100 chars. Optional, default=warn.

Allowable values are

  • truncate - paths are truncated to the maximum length
  • fail - paths greater than the maximum cause a build exception
  • warn - paths greater than the maximum cause a warning and GNU is used
  • gnu - GNU extensions are used for any paths greater than the maximum.
  • omit - paths greater than the maximum are omitted from the archive
Params:
  • mode – the mode string to handle long files.
Deprecated:since 1.5.x. setLongFile(String) is deprecated and is replaced with setLongFile(Tar.TarLongFileMode) to make Ant's Introspection mechanism do the work and also to encapsulate operations on the mode in its own class.
/** * Set how to handle long files, those with a path&gt;100 chars. * Optional, default=warn. * <p> * Allowable values are * <ul> * <li> truncate - paths are truncated to the maximum length * <li> fail - paths greater than the maximum cause a build exception * <li> warn - paths greater than the maximum cause a warning and GNU is used * <li> gnu - GNU extensions are used for any paths greater than the maximum. * <li> omit - paths greater than the maximum are omitted from the archive * </ul> * @param mode the mode string to handle long files. * @deprecated since 1.5.x. * setLongFile(String) is deprecated and is replaced with * setLongFile(Tar.TarLongFileMode) to make Ant's Introspection * mechanism do the work and also to encapsulate operations on * the mode in its own class. */
@Deprecated public void setLongfile(final String mode) { log("DEPRECATED - The setLongfile(String) method has been deprecated. Use setLongfile(Tar.TarLongFileMode) instead."); this.longFileMode = new TarLongFileMode(); longFileMode.setValue(mode); }
Set how to handle long files, those with a path>100 chars. Optional, default=warn.

Allowable values are

  • truncate - paths are truncated to the maximum length
  • fail - paths greater than the maximum cause a build exception
  • warn - paths greater than the maximum cause a warning and GNU is used
  • gnu - extensions used by older versions of GNU tar are used for any paths greater than the maximum.
  • posix - use POSIX PAX extension headers for any paths greater than the maximum. Supported by all modern tar implementations.
  • omit - paths greater than the maximum are omitted from the archive
Params:
  • mode – the mode to handle long file names.
/** * Set how to handle long files, those with a path&gt;100 chars. * Optional, default=warn. * <p> * Allowable values are * <ul> * <li> truncate - paths are truncated to the maximum length * <li> fail - paths greater than the maximum cause a build exception * <li> warn - paths greater than the maximum cause a warning and GNU is used * <li> gnu - extensions used by older versions of GNU tar are used for any paths greater than the maximum. * <li> posix - use POSIX PAX extension headers for any paths greater than the maximum. Supported by all modern tar implementations. * <li> omit - paths greater than the maximum are omitted from the archive * </ul> * @param mode the mode to handle long file names. */
public void setLongfile(final TarLongFileMode mode) { this.longFileMode = mode; }
Set compression method. Allowable values are
  • none - no compression
  • gzip - Gzip compression
  • bzip2 - Bzip2 compression
  • xz - XZ compression, requires XZ for Java
Params:
  • mode – the compression method.
/** * Set compression method. * Allowable values are * <ul> * <li> none - no compression * <li> gzip - Gzip compression * <li> bzip2 - Bzip2 compression * <li>xz - XZ compression, requires XZ for Java * </ul> * @param mode the compression method. */
public void setCompression(final TarCompressionMethod mode) { this.compression = mode; }
Encoding to use for filenames, defaults to the platform's default encoding.

For a list of possible values see https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html.

Params:
  • encoding – the encoding name
Since:Ant 1.9.5
/** * Encoding to use for filenames, defaults to the platform's * default encoding. * * <p>For a list of possible values see <a * href="https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html">https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html</a>.</p> * @param encoding the encoding name * * @since Ant 1.9.5 */
public void setEncoding(final String encoding) { this.encoding = encoding; }
do the business
Throws:
  • BuildException – on error
/** * do the business * @throws BuildException on error */
@Override public void execute() throws BuildException { if (tarFile == null) { throw new BuildException("tarfile attribute must be set!", getLocation()); } if (tarFile.exists() && tarFile.isDirectory()) { throw new BuildException("tarfile is a directory!", getLocation()); } if (tarFile.exists() && !tarFile.canWrite()) { throw new BuildException("Can not write to the specified tarfile!", getLocation()); } final Vector<TarFileSet> savedFileSets = new Vector<>(filesets); try { if (baseDir != null) { if (!baseDir.exists()) { throw new BuildException("basedir does not exist!", getLocation()); } // add the main fileset to the list of filesets to process. final TarFileSet mainFileSet = new TarFileSet(fileset); mainFileSet.setDir(baseDir); filesets.addElement(mainFileSet); } if (filesets.isEmpty() && resourceCollections.isEmpty()) { throw new BuildException( "You must supply either a basedir attribute or some nested resource collections.", getLocation()); } // check if tar is out of date with respect to each // fileset boolean upToDate = true; for (final TarFileSet tfs : filesets) { upToDate &= check(tfs); } for (final ResourceCollection rcol : resourceCollections) { upToDate &= check(rcol); } if (upToDate) { log("Nothing to do: " + tarFile.getAbsolutePath() + " is up to date.", Project.MSG_INFO); return; } final File parent = tarFile.getParentFile(); if (parent != null && !parent.isDirectory() && !(parent.mkdirs() || parent.isDirectory())) { throw new BuildException( "Failed to create missing parent directory for %s", tarFile); } log("Building tar: " + tarFile.getAbsolutePath(), Project.MSG_INFO); try (TarOutputStream tOut = new TarOutputStream( compression.compress(new BufferedOutputStream( Files.newOutputStream(tarFile.toPath()))), encoding)) { tOut.setDebug(true); if (longFileMode.isTruncateMode()) { tOut.setLongFileMode(TarOutputStream.LONGFILE_TRUNCATE); } else if (longFileMode.isFailMode() || longFileMode.isOmitMode()) { tOut.setLongFileMode(TarOutputStream.LONGFILE_ERROR); } else if (longFileMode.isPosixMode()) { tOut.setLongFileMode(TarOutputStream.LONGFILE_POSIX); } else { // warn or GNU tOut.setLongFileMode(TarOutputStream.LONGFILE_GNU); } longWarningGiven = false; for (final TarFileSet tfs : filesets) { tar(tfs, tOut); } for (final ResourceCollection rcol : resourceCollections) { tar(rcol, tOut); } } catch (final IOException ioe) { final String msg = "Problem creating TAR: " + ioe.getMessage(); throw new BuildException(msg, ioe, getLocation()); } } finally { filesets = savedFileSets; } }
tar a file
Params:
  • file – the file to tar
  • tOut – the output stream
  • vPath – the path name of the file to tar
  • tarFileSet – the fileset that the file came from.
Throws:
/** * tar a file * @param file the file to tar * @param tOut the output stream * @param vPath the path name of the file to tar * @param tarFileSet the fileset that the file came from. * @throws IOException on error */
protected void tarFile(final File file, final TarOutputStream tOut, final String vPath, final TarFileSet tarFileSet) throws IOException { if (file.equals(tarFile)) { // If the archive is built for the first time and it is // matched by a resource collection, then it hasn't been // found in check (it hasn't been there) but will be // included now. // // for some strange reason the old code would simply skip // the entry and not fail, do the same now for backwards // compatibility reasons. Without this, the which4j build // fails in Gump return; } tarResource(new FileResource(file), tOut, vPath, tarFileSet); }
tar a resource
Params:
  • r – the resource to tar
  • tOut – the output stream
  • vPath – the path name of the file to tar
  • tarFileSet – the fileset that the file came from, may be null.
Throws:
Since:Ant 1.7
/** * tar a resource * @param r the resource to tar * @param tOut the output stream * @param vPath the path name of the file to tar * @param tarFileSet the fileset that the file came from, may be null. * @throws IOException on error * @since Ant 1.7 */
protected void tarResource(final Resource r, final TarOutputStream tOut, String vPath, final TarFileSet tarFileSet) throws IOException { if (!r.isExists()) { return; } boolean preserveLeadingSlashes = false; if (tarFileSet != null) { final String fullpath = tarFileSet.getFullpath(this.getProject()); if (fullpath.isEmpty()) { // don't add "" to the archive if (vPath.isEmpty()) { return; } String prefix = tarFileSet.getPrefix(this.getProject()); // '/' is appended for compatibility with the zip task. if (!prefix.isEmpty() && !prefix.endsWith("/")) { prefix += "/"; } vPath = prefix + vPath; } else { vPath = fullpath; } preserveLeadingSlashes = tarFileSet.getPreserveLeadingSlashes(); if (vPath.startsWith("/") && !preserveLeadingSlashes) { final int l = vPath.length(); if (l <= 1) { // we would end up adding "" to the archive return; } vPath = vPath.substring(1, l); } } if (r.isDirectory() && !vPath.endsWith("/")) { vPath += "/"; } if (vPath.length() >= TarConstants.NAMELEN) { if (longFileMode.isOmitMode()) { log("Omitting: " + vPath, Project.MSG_INFO); return; } else if (longFileMode.isWarnMode()) { log("Entry: " + vPath + " longer than " + TarConstants.NAMELEN + " characters.", Project.MSG_WARN); if (!longWarningGiven) { log("Resulting tar file can only be processed " + "successfully by GNU compatible tar commands", Project.MSG_WARN); longWarningGiven = true; } } else if (longFileMode.isFailMode()) { throw new BuildException("Entry: " + vPath + " longer than " + TarConstants.NAMELEN + "characters.", getLocation()); } } final TarEntry te = new TarEntry(vPath, preserveLeadingSlashes); te.setModTime(r.getLastModified()); // preserve permissions if (r instanceof ArchiveResource) { final ArchiveResource ar = (ArchiveResource) r; te.setMode(ar.getMode()); if (r instanceof TarResource) { final TarResource tr = (TarResource) r; te.setUserName(tr.getUserName()); te.setUserId(tr.getLongUid()); te.setGroupName(tr.getGroup()); te.setGroupId(tr.getLongGid()); } } if (!r.isDirectory()) { if (r.size() > TarConstants.MAXSIZE) { throw new BuildException( "Resource: " + r + " larger than " + TarConstants.MAXSIZE + " bytes."); } te.setSize(r.getSize()); // override permissions if set explicitly if (tarFileSet != null && tarFileSet.hasFileModeBeenSet()) { te.setMode(tarFileSet.getMode()); } } else if (tarFileSet != null && tarFileSet.hasDirModeBeenSet()) { // override permissions if set explicitly te.setMode(tarFileSet.getDirMode(this.getProject())); } if (tarFileSet != null) { // only override permissions if set explicitly if (tarFileSet.hasUserNameBeenSet()) { te.setUserName(tarFileSet.getUserName()); } if (tarFileSet.hasGroupBeenSet()) { te.setGroupName(tarFileSet.getGroup()); } if (tarFileSet.hasUserIdBeenSet()) { te.setUserId(tarFileSet.getUid()); } if (tarFileSet.hasGroupIdBeenSet()) { te.setGroupId(tarFileSet.getGid()); } } InputStream in = null; try { tOut.putNextEntry(te); if (!r.isDirectory()) { in = r.getInputStream(); final byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; do { tOut.write(buffer, 0, count); count = in.read(buffer, 0, buffer.length); } while (count != -1); } tOut.closeEntry(); } finally { FileUtils.close(in); } }
Is the archive up to date in relationship to a list of files.
Params:
  • files – the files to check
Returns:true if the archive is up to date.
Deprecated:since 1.5.x. use the two-arg version instead.
/** * Is the archive up to date in relationship to a list of files. * @param files the files to check * @return true if the archive is up to date. * @deprecated since 1.5.x. * use the two-arg version instead. */
@Deprecated protected boolean archiveIsUpToDate(final String[] files) { return archiveIsUpToDate(files, baseDir); }
Is the archive up to date in relationship to a list of files.
Params:
  • files – the files to check
  • dir – the base directory for the files.
Returns:true if the archive is up to date.
Since:Ant 1.5.2
/** * Is the archive up to date in relationship to a list of files. * @param files the files to check * @param dir the base directory for the files. * @return true if the archive is up to date. * @since Ant 1.5.2 */
protected boolean archiveIsUpToDate(final String[] files, final File dir) { final SourceFileScanner sfs = new SourceFileScanner(this); final MergingMapper mm = new MergingMapper(); mm.setTo(tarFile.getAbsolutePath()); return sfs.restrict(files, dir, null, mm).length == 0; }
Is the archive up to date in relationship to a list of files.
Params:
  • r – the files to check
Returns:true if the archive is up to date.
Since:Ant 1.7
/** * Is the archive up to date in relationship to a list of files. * @param r the files to check * @return true if the archive is up to date. * @since Ant 1.7 */
protected boolean archiveIsUpToDate(final Resource r) { return SelectorUtils.isOutOfDate(new FileResource(tarFile), r, FileUtils.getFileUtils() .getFileTimestampGranularity()); }
Whether this task can deal with non-file resources.

This implementation returns true only if this task is <tar>. Any subclass of this class that also wants to support non-file resources needs to override this method. We need to do so for backwards compatibility reasons since we can't expect subclasses to support resources.

Returns:true for this task.
Since:Ant 1.7
/** * Whether this task can deal with non-file resources. * * <p>This implementation returns true only if this task is * &lt;tar&gt;. Any subclass of this class that also wants to * support non-file resources needs to override this method. We * need to do so for backwards compatibility reasons since we * can't expect subclasses to support resources.</p> * @return true for this task. * @since Ant 1.7 */
protected boolean supportsNonFileResources() { return getClass().equals(Tar.class); }
Checks whether the archive is out-of-date with respect to the resources of the given collection.

Also checks that either all collections only contain file resources or this class supports non-file collections.

And - in case of file-collections - ensures that the archive won't contain itself.

Params:
  • rc – the resource collection to check
Returns:whether the archive is up-to-date
Since:Ant 1.7
/** * Checks whether the archive is out-of-date with respect to the resources * of the given collection. * * <p>Also checks that either all collections only contain file * resources or this class supports non-file collections.</p> * * <p>And - in case of file-collections - ensures that the archive won't * contain itself.</p> * * @param rc the resource collection to check * @return whether the archive is up-to-date * @since Ant 1.7 */
protected boolean check(final ResourceCollection rc) { boolean upToDate = true; if (isFileFileSet(rc)) { final FileSet fs = (FileSet) rc; upToDate = check(fs.getDir(getProject()), getFileNames(fs)); } else if (!rc.isFilesystemOnly() && !supportsNonFileResources()) { throw new BuildException("only filesystem resources are supported"); } else if (rc.isFilesystemOnly()) { final Set<File> basedirs = new HashSet<>(); final Map<File, List<String>> basedirToFilesMap = new HashMap<>(); for (final Resource res : rc) { final FileResource r = ResourceUtils .asFileResource(res.as(FileProvider.class)); File base = r.getBaseDir(); if (base == null) { base = Copy.NULL_FILE_PLACEHOLDER; } basedirs.add(base); List<String> files = basedirToFilesMap.computeIfAbsent(base, k -> new Vector<>()); if (base == Copy.NULL_FILE_PLACEHOLDER) { files.add(r.getFile().getAbsolutePath()); } else { files.add(r.getName()); } } for (final File base : basedirs) { final File tmpBase = base == Copy.NULL_FILE_PLACEHOLDER ? null : base; final List<String> files = basedirToFilesMap.get(base); upToDate &= check(tmpBase, files); } } else { // non-file resources for (Resource r : rc) { upToDate = archiveIsUpToDate(r); } } return upToDate; }

Checks whether the archive is out-of-date with respect to the given files, ensures that the archive won't contain itself.

Params:
  • basedir – base directory for file names
  • files – array of relative file names
Returns:whether the archive is up-to-date
Since:Ant 1.7
/** * <p>Checks whether the archive is out-of-date with respect to the * given files, ensures that the archive won't contain itself.</p> * * @param basedir base directory for file names * @param files array of relative file names * @return whether the archive is up-to-date * @since Ant 1.7 */
protected boolean check(final File basedir, final String[] files) { boolean upToDate = true; if (!archiveIsUpToDate(files, basedir)) { upToDate = false; } for (String file : files) { if (tarFile.equals(new File(basedir, file))) { throw new BuildException("A tar file cannot include itself", getLocation()); } } return upToDate; }

Checks whether the archive is out-of-date with respect to the given files, ensures that the archive won't contain itself.

Params:
  • basedir – base directory for file names
  • files – array of relative file names
See Also:
Returns:whether the archive is up-to-date
Since:Ant 1.9.5
/** * <p>Checks whether the archive is out-of-date with respect to the * given files, ensures that the archive won't contain itself.</p> * * @param basedir base directory for file names * @param files array of relative file names * @return whether the archive is up-to-date * @see #check(File, String[]) * @since Ant 1.9.5 */
protected boolean check(final File basedir, final Collection<String> files) { return check(basedir, files.toArray(new String[files.size()])); }
Adds the resources contained in this collection to the archive.

Uses the file based methods for file resources for backwards compatibility.

Params:
  • rc – the collection containing resources to add
  • tOut – stream writing to the archive.
Throws:
Since:Ant 1.7
/** * Adds the resources contained in this collection to the archive. * * <p>Uses the file based methods for file resources for backwards * compatibility.</p> * * @param rc the collection containing resources to add * @param tOut stream writing to the archive. * @throws IOException on error. * @since Ant 1.7 */
protected void tar(final ResourceCollection rc, final TarOutputStream tOut) throws IOException { ArchiveFileSet afs = null; if (rc instanceof ArchiveFileSet) { afs = (ArchiveFileSet) rc; } if (afs != null && afs.size() > 1 && !afs.getFullpath(this.getProject()).isEmpty()) { throw new BuildException( "fullpath attribute may only be specified for filesets that specify a single file."); } final TarFileSet tfs = asTarFileSet(afs); if (isFileFileSet(rc)) { final FileSet fs = (FileSet) rc; for (String file : getFileNames(fs)) { final File f = new File(fs.getDir(getProject()), file); final String name = file.replace(File.separatorChar, '/'); tarFile(f, tOut, name, tfs); } } else if (rc.isFilesystemOnly()) { for (final Resource r : rc) { final File f = r.as(FileProvider.class).getFile(); tarFile(f, tOut, f.getName(), tfs); } } else { // non-file resources for (final Resource r : rc) { tarResource(r, tOut, r.getName(), tfs); } } }
whether the given resource collection is a (subclass of) FileSet that only contains file system resources.
Params:
  • rc – the resource collection to check.
Returns:true if the collection is a fileset.
Since:Ant 1.7
/** * whether the given resource collection is a (subclass of) * FileSet that only contains file system resources. * @param rc the resource collection to check. * @return true if the collection is a fileset. * @since Ant 1.7 */
protected static boolean isFileFileSet(final ResourceCollection rc) { return rc instanceof FileSet && rc.isFilesystemOnly(); }
Grabs all included files and directors from the FileSet and returns them as an array of (relative) file names.
Params:
  • fs – the fileset to operate on.
Returns:a list of the filenames.
Since:Ant 1.7
/** * Grabs all included files and directors from the FileSet and * returns them as an array of (relative) file names. * @param fs the fileset to operate on. * @return a list of the filenames. * @since Ant 1.7 */
protected static String[] getFileNames(final FileSet fs) { final DirectoryScanner ds = fs.getDirectoryScanner(fs.getProject()); final String[] directories = ds.getIncludedDirectories(); final String[] filesPerSe = ds.getIncludedFiles(); final String[] files = new String[directories.length + filesPerSe.length]; System.arraycopy(directories, 0, files, 0, directories.length); System.arraycopy(filesPerSe, 0, files, directories.length, filesPerSe.length); return files; }
Copies fullpath, prefix and permission attributes from the ArchiveFileSet to a new TarFileSet (or returns it unchanged if it already is a TarFileSet).
Params:
  • archiveFileSet – fileset to copy attributes from, may be null
Returns:a new TarFileSet.
Since:Ant 1.7
/** * Copies fullpath, prefix and permission attributes from the * ArchiveFileSet to a new TarFileSet (or returns it unchanged if * it already is a TarFileSet). * * @param archiveFileSet fileset to copy attributes from, may be null * @return a new TarFileSet. * @since Ant 1.7 */
protected TarFileSet asTarFileSet(final ArchiveFileSet archiveFileSet) { TarFileSet tfs; if (archiveFileSet instanceof TarFileSet) { tfs = (TarFileSet) archiveFileSet; } else { tfs = new TarFileSet(); tfs.setProject(getProject()); if (archiveFileSet != null) { tfs.setPrefix(archiveFileSet.getPrefix(getProject())); tfs.setFullpath(archiveFileSet.getFullpath(getProject())); if (archiveFileSet.hasFileModeBeenSet()) { tfs.integerSetFileMode(archiveFileSet .getFileMode(getProject())); } if (archiveFileSet.hasDirModeBeenSet()) { tfs.integerSetDirMode(archiveFileSet .getDirMode(getProject())); } if (archiveFileSet instanceof org.apache.tools.ant.types.TarFileSet) { final org.apache.tools.ant.types.TarFileSet t = (org.apache.tools.ant.types.TarFileSet) archiveFileSet; if (t.hasUserNameBeenSet()) { tfs.setUserName(t.getUserName()); } if (t.hasGroupBeenSet()) { tfs.setGroup(t.getGroup()); } if (t.hasUserIdBeenSet()) { tfs.setUid(t.getUid()); } if (t.hasGroupIdBeenSet()) { tfs.setGid(t.getGid()); } } } } return tfs; }
This is a FileSet with the option to specify permissions and other attributes.
/** * This is a FileSet with the option to specify permissions * and other attributes. */
public static class TarFileSet extends org.apache.tools.ant.types.TarFileSet { private String[] files = null; private boolean preserveLeadingSlashes = false;
Creates a new TarFileSet instance. Using a fileset as a constructor argument.
Params:
  • fileset – a FileSet value
/** * Creates a new <code>TarFileSet</code> instance. * Using a fileset as a constructor argument. * * @param fileset a <code>FileSet</code> value */
public TarFileSet(final FileSet fileset) { super(fileset); }
Creates a new TarFileSet instance.
/** * Creates a new <code>TarFileSet</code> instance. * */
public TarFileSet() { super(); }
Get a list of files and directories specified in the fileset.
Params:
  • p – the current project.
Returns:a list of file and directory names, relative to the baseDir for the project.
/** * Get a list of files and directories specified in the fileset. * @param p the current project. * @return a list of file and directory names, relative to * the baseDir for the project. */
public String[] getFiles(final Project p) { if (files == null) { files = getFileNames(this); } return files; }
A 3 digit octal string, specify the user, group and other modes in the standard Unix fashion; optional, default=0644
Params:
  • octalString – a 3 digit octal string.
/** * A 3 digit octal string, specify the user, group and * other modes in the standard Unix fashion; * optional, default=0644 * @param octalString a 3 digit octal string. */
public void setMode(final String octalString) { setFileMode(octalString); }
Returns:the current mode.
/** * @return the current mode. */
public int getMode() { return getFileMode(this.getProject()); }
Flag to indicates whether leading `/'s should be preserved in the file names. Optional, default is false.
Params:
  • b – the leading slashes flag.
/** * Flag to indicates whether leading `/'s should * be preserved in the file names. * Optional, default is <code>false</code>. * @param b the leading slashes flag. */
public void setPreserveLeadingSlashes(final boolean b) { this.preserveLeadingSlashes = b; }
Returns:the leading slashes flag.
/** * @return the leading slashes flag. */
public boolean getPreserveLeadingSlashes() { return preserveLeadingSlashes; } }
Set of options for long file handling in the task.
/** * Set of options for long file handling in the task. * */
public static class TarLongFileMode extends EnumeratedAttribute {
permissible values for longfile attribute
/** permissible values for longfile attribute */
public static final String WARN = "warn", FAIL = "fail", TRUNCATE = "truncate", GNU = "gnu", POSIX = "posix", OMIT = "omit"; private static final String[] VALID_MODES = { WARN, FAIL, TRUNCATE, GNU, POSIX, OMIT };
Constructor, defaults to "warn"
/** Constructor, defaults to "warn" */
public TarLongFileMode() { super(); setValue(WARN); }
Returns:the possible values for this enumerated type.
/** * @return the possible values for this enumerated type. */
@Override public String[] getValues() { return VALID_MODES; }
Returns:true if value is "truncate".
/** * @return true if value is "truncate". */
public boolean isTruncateMode() { return TRUNCATE.equalsIgnoreCase(getValue()); }
Returns:true if value is "warn".
/** * @return true if value is "warn". */
public boolean isWarnMode() { return WARN.equalsIgnoreCase(getValue()); }
Returns:true if value is "gnu".
/** * @return true if value is "gnu". */
public boolean isGnuMode() { return GNU.equalsIgnoreCase(getValue()); }
Returns:true if value is "fail".
/** * @return true if value is "fail". */
public boolean isFailMode() { return FAIL.equalsIgnoreCase(getValue()); }
Returns:true if value is "omit".
/** * @return true if value is "omit". */
public boolean isOmitMode() { return OMIT.equalsIgnoreCase(getValue()); }
Returns:true if value is "posix".
/** * @return true if value is "posix". */
public boolean isPosixMode() { return POSIX.equalsIgnoreCase(getValue()); } }
Valid Modes for Compression attribute to Tar Task
/** * Valid Modes for Compression attribute to Tar Task * */
public static final class TarCompressionMethod extends EnumeratedAttribute { // permissible values for compression attribute
No compression
/** * No compression */
private static final String NONE = "none";
GZIP compression
/** * GZIP compression */
private static final String GZIP = "gzip";
BZIP2 compression
/** * BZIP2 compression */
private static final String BZIP2 = "bzip2";
XZ compression
Since:1.10.1
/** * XZ compression * @since 1.10.1 */
private static final String XZ = "xz";
Default constructor
/** * Default constructor */
public TarCompressionMethod() { super(); setValue(NONE); }
Get valid enumeration values. @return valid enumeration values
/** * Get valid enumeration values. * @return valid enumeration values */
@Override public String[] getValues() { return new String[] {NONE, GZIP, BZIP2, XZ}; }
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
/** * 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 v = getValue(); if (GZIP.equals(v)) { return new GZIPOutputStream(ostream); } if (XZ.equals(v)) { return newXZOutputStream(ostream); } if (BZIP2.equals(v)) { ostream.write('B'); ostream.write('Z'); return new CBZip2OutputStream(ostream); } return ostream; } private static OutputStream newXZOutputStream(OutputStream ostream) throws BuildException { try { Class<?> fClazz = Class.forName("org.tukaani.xz.FilterOptions"); Class<?> oClazz = Class.forName("org.tukaani.xz.LZMA2Options"); Class<? extends OutputStream> sClazz = Class.forName("org.tukaani.xz.XZOutputStream") .asSubclass(OutputStream.class); Constructor<? extends OutputStream> c = sClazz.getConstructor(OutputStream.class, fClazz); return c.newInstance(ostream, oClazz.newInstance()); } catch (ClassNotFoundException ex) { throw new BuildException("xz compression requires the XZ for Java library", ex); } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex) { throw new BuildException("failed to create XZOutputStream", ex); } } } }