Example usage for org.apache.commons.compress.archivers.zip ZipArchiveOutputStream putArchiveEntry

List of usage examples for org.apache.commons.compress.archivers.zip ZipArchiveOutputStream putArchiveEntry

Introduction

In this page you can find the example usage for org.apache.commons.compress.archivers.zip ZipArchiveOutputStream putArchiveEntry.

Prototype

public void putArchiveEntry(ArchiveEntry archiveEntry) throws IOException 

Source Link

Usage

From source file:com.citytechinc.cq.component.maven.util.ComponentMojoUtil.java

/**
 * Add files to the already constructed Archive file by creating a new
 * Archive file, appending the contents of the existing Archive file to it,
 * and then adding additional entries for the newly constructed artifacts.
 * //  ww w.  j a v a 2s. c o m
 * @param classList
 * @param classLoader
 * @param classPool
 * @param buildDirectory
 * @param componentPathBase
 * @param defaultComponentPathSuffix
 * @param defaultComponentGroup
 * @param existingArchiveFile
 * @param tempArchiveFile
 * @throws OutputFailureException
 * @throws IOException
 * @throws InvalidComponentClassException
 * @throws InvalidComponentFieldException
 * @throws ParserConfigurationException
 * @throws TransformerException
 * @throws ClassNotFoundException
 * @throws CannotCompileException
 * @throws NotFoundException
 * @throws SecurityException
 * @throws NoSuchFieldException
 * @throws IllegalArgumentException
 * @throws IllegalAccessException
 * @throws InvocationTargetException
 * @throws NoSuchMethodException
 * @throws InstantiationException
 */
public static void buildArchiveFileForProjectAndClassList(List<CtClass> classList,
        WidgetRegistry widgetRegistry, TouchUIWidgetRegistry touchUIWidgetRegistry, ClassLoader classLoader,
        ClassPool classPool, File buildDirectory, String componentPathBase, String defaultComponentPathSuffix,
        String defaultComponentGroup, File existingArchiveFile, File tempArchiveFile,
        ComponentNameTransformer transformer, boolean generateTouchUiDialogs) throws OutputFailureException,
        IOException, InvalidComponentClassException, InvalidComponentFieldException,
        ParserConfigurationException, TransformerException, ClassNotFoundException, CannotCompileException,
        NotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentException,
        IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException,
        TouchUIDialogWriteException, TouchUIDialogGenerationException {

    if (!existingArchiveFile.exists()) {
        throw new OutputFailureException("Archive file does not exist");
    }

    if (tempArchiveFile.exists()) {
        tempArchiveFile.delete();
    }

    tempArchiveFile.createNewFile();

    deleteTemporaryComponentOutputDirectory(buildDirectory);

    /*
     * Create archive input stream
     */
    ZipArchiveInputStream existingInputStream = new ZipArchiveInputStream(
            new FileInputStream(existingArchiveFile));

    /*
     * Create a zip archive output stream for the temp file
     */
    ZipArchiveOutputStream tempOutputStream = new ZipArchiveOutputStream(tempArchiveFile);

    /*
     * Iterate through all existing entries adding them to the new archive
     */
    ZipArchiveEntry curArchiveEntry;

    Set<String> existingArchiveEntryNames = new HashSet<String>();

    while ((curArchiveEntry = existingInputStream.getNextZipEntry()) != null) {
        existingArchiveEntryNames.add(curArchiveEntry.getName().toLowerCase());
        getLog().debug("Current File Name: " + curArchiveEntry.getName());
        tempOutputStream.putArchiveEntry(curArchiveEntry);
        IOUtils.copy(existingInputStream, tempOutputStream);
        tempOutputStream.closeArchiveEntry();
    }

    /*
     * Create content.xml within temp archive
     */
    ContentUtil.buildContentFromClassList(classList, tempOutputStream, existingArchiveEntryNames,
            buildDirectory, componentPathBase, defaultComponentPathSuffix, defaultComponentGroup, transformer);

    /*
     * Create Dialogs within temp archive
     */
    DialogUtil.buildDialogsFromClassList(transformer, classList, tempOutputStream, existingArchiveEntryNames,
            widgetRegistry, classLoader, classPool, buildDirectory, componentPathBase,
            defaultComponentPathSuffix);

    if (generateTouchUiDialogs) {
        TouchUIDialogUtil.buildDialogsFromClassList(classList, classLoader, classPool, touchUIWidgetRegistry,
                transformer, buildDirectory, componentPathBase, defaultComponentPathSuffix, tempOutputStream,
                existingArchiveEntryNames);
    }

    /*
     * Create edit config within temp archive
     */
    EditConfigUtil.buildEditConfigFromClassList(classList, tempOutputStream, existingArchiveEntryNames,
            buildDirectory, componentPathBase, defaultComponentPathSuffix, transformer);

    /*
     * Copy temp archive to the original archive position
     */
    tempOutputStream.finish();
    existingInputStream.close();
    tempOutputStream.close();

    existingArchiveFile.delete();
    tempArchiveFile.renameTo(existingArchiveFile);

}

From source file:com.xpn.xwiki.plugin.packaging.AbstractPackageTest.java

/**
 * Create a XAR file using commons compress.
 *
 * @param docs The documents to include.
 * @param encodings The charset for each document.
 * @param packageXmlEncoding The encoding of package.xml
 * @return the XAR file as a byte array.
 *//*from ww  w . ja  v a 2s .co  m*/
protected byte[] createZipFileUsingCommonsCompress(XWikiDocument docs[], String[] encodings,
        String packageXmlEncoding) throws Exception {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ZipArchiveOutputStream zos = new ZipArchiveOutputStream(baos);
    ZipArchiveEntry zipp = new ZipArchiveEntry("package.xml");
    zos.putArchiveEntry(zipp);
    zos.write(getEncodedByteArray(getPackageXML(docs, packageXmlEncoding), packageXmlEncoding));
    for (int i = 0; i < docs.length; i++) {
        String zipEntryName = docs[i].getSpace() + "/" + docs[i].getName();
        if (docs[i].getTranslation() != 0) {
            zipEntryName += "." + docs[i].getLanguage();
        }
        ZipArchiveEntry zipe = new ZipArchiveEntry(zipEntryName);
        zos.putArchiveEntry(zipe);
        String xmlCode = docs[i].toXML(false, false, false, false, getContext());
        zos.write(getEncodedByteArray(xmlCode, encodings[i]));
        zos.closeArchiveEntry();
    }
    zos.finish();
    zos.close();
    return baos.toByteArray();
}

From source file:com.gitblit.utils.CompressionUtils.java

/**
 * Zips the contents of the tree at the (optionally) specified revision and
 * the (optionally) specified basepath to the supplied outputstream.
 * //from   w ww .j a  v  a  2  s .  c  o m
 * @param repository
 * @param basePath
 *            if unspecified, entire repository is assumed.
 * @param objectId
 *            if unspecified, HEAD is assumed.
 * @param os
 * @return true if repository was successfully zipped to supplied output
 *         stream
 */
public static boolean zip(Repository repository, String basePath, String objectId, OutputStream os) {
    RevCommit commit = JGitUtils.getCommit(repository, objectId);
    if (commit == null) {
        return false;
    }
    boolean success = false;
    RevWalk rw = new RevWalk(repository);
    TreeWalk tw = new TreeWalk(repository);
    try {
        tw.reset();
        tw.addTree(commit.getTree());
        ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);
        zos.setComment("Generated by Gitblit");
        if (!StringUtils.isEmpty(basePath)) {
            PathFilter f = PathFilter.create(basePath);
            tw.setFilter(f);
        }
        tw.setRecursive(true);
        MutableObjectId id = new MutableObjectId();
        ObjectReader reader = tw.getObjectReader();
        long modified = commit.getAuthorIdent().getWhen().getTime();
        while (tw.next()) {
            FileMode mode = tw.getFileMode(0);
            if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
                continue;
            }
            tw.getObjectId(id, 0);

            ZipArchiveEntry entry = new ZipArchiveEntry(tw.getPathString());
            entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB));
            entry.setComment(commit.getName());
            entry.setUnixMode(mode.getBits());
            entry.setTime(modified);
            zos.putArchiveEntry(entry);

            ObjectLoader ldr = repository.open(id);
            ldr.copyTo(zos);
            zos.closeArchiveEntry();
        }
        zos.finish();
        success = true;
    } catch (IOException e) {
        error(e, repository, "{0} failed to zip files from commit {1}", commit.getName());
    } finally {
        tw.release();
        rw.dispose();
    }
    return success;
}

From source file:cz.muni.fi.xklinec.zipstream.PostponedEntry.java

/**
 * Writes whole entry to the ZIPArchiveOutputStream.
 * Optionally recomputes CRC32 checksum.
 * /*from   ww w. java2s  .c  o  m*/
 * @param zop
 * @param recomputeCrc
 * @throws IOException 
 */
public void dump(ZipArchiveOutputStream zop, boolean recomputeCrc) throws IOException {
    ZipArchiveEntry zen = (ZipArchiveEntry) ze.clone();

    // recompute CRC?
    if (recomputeCrc) {
        crc.reset();
        crc.update(byteData);
        ze.setCrc(crc.getValue());
    }

    zop.putArchiveEntry(zen);
    zop.write(byteData, 0, byteData.length);
    zop.closeArchiveEntry();
    zop.flush();
}

From source file:fr.gael.ccsds.sip.archive.ZipArchiveManager.java

/**
 * Produces Zip compressed archive./*  ww  w .  java 2s  .  c  o  m*/
 */
@Override
public File copy(final File src, final File zip_file, final String dst) throws Exception {
    if (zip_file.exists()) {
        final FileInputStream fis = new FileInputStream(zip_file);
        final ZipArchiveInputStream zis = new ZipArchiveInputStream(fis);

        final File tempFile = File.createTempFile("updateZip", "zip");
        final FileOutputStream fos = new FileOutputStream(tempFile);
        final ZipArchiveOutputStream zos = new ZipArchiveOutputStream(fos);

        // copy the existing entries
        ZipArchiveEntry nextEntry;
        while ((nextEntry = zis.getNextZipEntry()) != null) {
            zos.putArchiveEntry(nextEntry);
            IOUtils.copy(zis, zos);
            zos.closeArchiveEntry();
        }

        // create the new entry
        final ZipArchiveEntry entry = new ZipArchiveEntry(src, dst);
        entry.setSize(src.length());
        zos.putArchiveEntry(entry);
        final FileInputStream sfis = new FileInputStream(src);
        IOUtils.copy(sfis, zos);
        sfis.close();
        zos.closeArchiveEntry();

        zos.finish();
        zis.close();
        fis.close();
        zos.close();

        // Rename the new file over the old
        boolean status = zip_file.delete();
        File saved_tempFile = tempFile;
        status = tempFile.renameTo(zip_file);

        // Copy the new file over the old if the renaming failed
        if (!status) {
            final FileInputStream tfis = new FileInputStream(saved_tempFile);
            final FileOutputStream tfos = new FileOutputStream(zip_file);

            final byte[] buf = new byte[1024];
            int i = 0;

            while ((i = tfis.read(buf)) != -1) {
                tfos.write(buf, 0, i);
            }

            tfis.close();
            tfos.close();

            saved_tempFile.delete();
        }

        return zip_file;

    } else {
        final FileOutputStream fos = new FileOutputStream(zip_file);
        final ZipArchiveOutputStream zos = new ZipArchiveOutputStream(fos);

        final ZipArchiveEntry entry = new ZipArchiveEntry(src, dst);
        entry.setSize(src.length());
        zos.putArchiveEntry(entry);

        final FileInputStream sfis = new FileInputStream(src);
        IOUtils.copy(sfis, zos);
        sfis.close();

        zos.closeArchiveEntry();

        zos.finish();
        zos.close();
        fos.close();
    }
    return zip_file;
}

From source file:com.citytechinc.cq.component.maven.util.ComponentMojoUtil.java

/**
 * Writes a provided file to a provided archive output stream at a path
 * determined by the class of the component.
 * //from  w ww.  ja  va 2 s. c o  m
 * @param file
 * @param componentClass
 * @param archiveStream
 * @param reservedNames A list of files which already exist within the Zip
 *            Archive. If a file already exists for a particular component,
 *            it is left untouched.
 * @param componentPathBase
 * @throws IOException
 * @throws ClassNotFoundException
 */
public static void writeElementToArchiveFile(ComponentNameTransformer transformer, File file,
        CtClass componentClass, ZipArchiveOutputStream archiveStream, Set<String> reservedNames,
        String componentPathBase, String defaultComponentPathSuffix, String path)
        throws IOException, ClassNotFoundException {
    String editConfigFilePath = ComponentMojoUtil.getComponentBasePathForComponentClass(componentClass,
            componentPathBase)
            + "/"
            + ComponentMojoUtil.getComponentPathSuffixForComponentClass(componentClass,
                    defaultComponentPathSuffix)
            + "/" + ComponentMojoUtil.getComponentNameForComponentClass(transformer, componentClass) + path;

    if (!reservedNames.contains(editConfigFilePath.toLowerCase())) {

        ZipArchiveEntry entry = new ZipArchiveEntry(file, editConfigFilePath);

        archiveStream.putArchiveEntry(entry);

        IOUtils.copy(new FileInputStream(file), archiveStream);

        archiveStream.closeArchiveEntry();

    } else {
        ComponentMojoUtil.getLog().debug("Existing file found at " + editConfigFilePath);
    }
}

From source file:io.selendroid.builder.SelendroidServerBuilder.java

File createAndAddCustomizedAndroidManifestToSelendroidServer()
        throws IOException, ShellCommandException, AndroidSdkException {
    String targetPackageName = applicationUnderTest.getBasePackage();
    File tempdir = new File(FileUtils.getTempDirectoryPath() + File.separatorChar + targetPackageName
            + System.currentTimeMillis());

    if (!tempdir.exists()) {
        tempdir.mkdirs();/*from  w  w  w  .j a va 2s  . c  o  m*/
    }

    File customizedManifest = new File(tempdir, "AndroidManifest.xml");
    log.info("Adding target package '" + targetPackageName + "' to " + customizedManifest.getAbsolutePath());

    // add target package
    InputStream inputStream = getResourceAsStream(selendroidApplicationXmlTemplate);
    if (inputStream == null) {
        throw new SelendroidException("AndroidApplication.xml template file was not found.");
    }
    String content = IOUtils.toString(inputStream, Charset.defaultCharset().displayName());

    // find the first occurance of "package" and appending the targetpackagename to begining
    int i = content.toLowerCase().indexOf("package");
    int cnt = 0;
    for (; i < content.length(); i++) {
        if (content.charAt(i) == '\"') {
            cnt++;
        }
        if (cnt == 2) {
            break;
        }
    }
    content = content.substring(0, i) + "." + targetPackageName + content.substring(i);
    log.info("Final Manifest File:\n" + content);
    content = content.replaceAll(SELENDROID_TEST_APP_PACKAGE, targetPackageName);
    // Seems like this needs to be done
    if (content.contains(ICON)) {
        content = content.replaceAll(ICON, "");
    }

    OutputStream outputStream = new FileOutputStream(customizedManifest);
    IOUtils.write(content, outputStream, Charset.defaultCharset().displayName());
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);

    // adding the xml to an empty apk
    CommandLine createManifestApk = new CommandLine(AndroidSdk.aapt());

    createManifestApk.addArgument("package", false);
    createManifestApk.addArgument("-M", false);
    createManifestApk.addArgument(customizedManifest.getAbsolutePath(), false);
    createManifestApk.addArgument("-I", false);
    createManifestApk.addArgument(AndroidSdk.androidJar(), false);
    createManifestApk.addArgument("-F", false);
    createManifestApk.addArgument(tempdir.getAbsolutePath() + File.separatorChar + "manifest.apk", false);
    createManifestApk.addArgument("-f", false);
    log.info(ShellCommand.exec(createManifestApk, 20000L));

    ZipFile manifestApk = new ZipFile(
            new File(tempdir.getAbsolutePath() + File.separatorChar + "manifest.apk"));
    ZipArchiveEntry binaryManifestXml = manifestApk.getEntry("AndroidManifest.xml");

    File finalSelendroidServerFile = new File(tempdir.getAbsolutePath() + "selendroid-server.apk");
    ZipArchiveOutputStream finalSelendroidServer = new ZipArchiveOutputStream(finalSelendroidServerFile);
    finalSelendroidServer.putArchiveEntry(binaryManifestXml);
    IOUtils.copy(manifestApk.getInputStream(binaryManifestXml), finalSelendroidServer);

    ZipFile selendroidPrebuildApk = new ZipFile(selendroidServer.getAbsolutePath());
    Enumeration<ZipArchiveEntry> entries = selendroidPrebuildApk.getEntries();
    for (; entries.hasMoreElements();) {
        ZipArchiveEntry dd = entries.nextElement();
        finalSelendroidServer.putArchiveEntry(dd);

        IOUtils.copy(selendroidPrebuildApk.getInputStream(dd), finalSelendroidServer);
    }

    finalSelendroidServer.closeArchiveEntry();
    finalSelendroidServer.close();
    manifestApk.close();
    log.info("file: " + finalSelendroidServerFile.getAbsolutePath());
    return finalSelendroidServerFile;
}

From source file:net.larry1123.elec.util.logger.LoggerDirectoryHandler.java

protected void packFile(File file, ZipArchiveOutputStream zipArchiveOutputStream) throws IOException {
    String relative = getDirectoryPath().relativize(file.toPath()).toString();
    // Make an Entry in the archive
    ArchiveEntry archiveEntry = zipArchiveOutputStream.createArchiveEntry(file, relative);
    FileInputStream fileInputStream = FileUtils.openInputStream(file);
    zipArchiveOutputStream.putArchiveEntry(archiveEntry);
    // Copy file content into archive
    IOUtils.copy(fileInputStream, zipArchiveOutputStream);
    zipArchiveOutputStream.closeArchiveEntry();
}

From source file:io.selendroid.standalone.builder.SelendroidServerBuilder.java

File createAndAddCustomizedAndroidManifestToSelendroidServer()
        throws IOException, ShellCommandException, AndroidSdkException {
    String targetPackageName = applicationUnderTest.getBasePackage();

    File tmpDir = Files.createTempDir();
    if (deleteTmpFiles()) {
        tmpDir.deleteOnExit();//from w  w  w. j  av  a  2  s  . com
    }

    File customizedManifest = new File(tmpDir, "AndroidManifest.xml");
    if (deleteTmpFiles()) {
        customizedManifest.deleteOnExit();
    }
    log.info("Adding target package '" + targetPackageName + "' to " + customizedManifest.getAbsolutePath());

    // add target package
    InputStream inputStream = getResourceAsStream(selendroidApplicationXmlTemplate);
    if (inputStream == null) {
        throw new SelendroidException("AndroidApplication.xml template file was not found.");
    }
    String content = IOUtils.toString(inputStream, Charset.defaultCharset().displayName());

    // find the first occurance of "package" and appending the targetpackagename to begining
    int i = content.toLowerCase().indexOf("package");
    int cnt = 0;
    for (; i < content.length(); i++) {
        if (content.charAt(i) == '\"') {
            cnt++;
        }
        if (cnt == 2) {
            break;
        }
    }
    content = content.substring(0, i) + "." + targetPackageName + content.substring(i);
    log.info("Final Manifest File:\n" + content);
    content = content.replaceAll(SELENDROID_TEST_APP_PACKAGE, targetPackageName);
    // Seems like this needs to be done
    if (content.contains(ICON)) {
        content = content.replaceAll(ICON, "");
    }

    OutputStream outputStream = new FileOutputStream(customizedManifest);
    IOUtils.write(content, outputStream, Charset.defaultCharset().displayName());
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);

    // adding the xml to an empty apk
    CommandLine createManifestApk = new CommandLine(AndroidSdk.aapt());

    File manifestApkFile = File.createTempFile("manifest", ".apk");
    if (deleteTmpFiles()) {
        manifestApkFile.deleteOnExit();
    }

    createManifestApk.addArgument("package", false);
    createManifestApk.addArgument("-M", false);
    createManifestApk.addArgument(customizedManifest.getAbsolutePath(), false);
    createManifestApk.addArgument("-I", false);
    createManifestApk.addArgument(AndroidSdk.androidJar(), false);
    createManifestApk.addArgument("-F", false);
    createManifestApk.addArgument(manifestApkFile.getAbsolutePath(), false);
    createManifestApk.addArgument("-f", false);
    log.info(ShellCommand.exec(createManifestApk, 20000L));

    ZipFile manifestApk = new ZipFile(manifestApkFile);
    ZipArchiveEntry binaryManifestXml = manifestApk.getEntry("AndroidManifest.xml");

    File finalSelendroidServerFile = File.createTempFile("selendroid-server", ".apk");
    if (deleteTmpFiles()) {
        finalSelendroidServerFile.deleteOnExit();
    }

    ZipArchiveOutputStream finalSelendroidServer = new ZipArchiveOutputStream(finalSelendroidServerFile);
    finalSelendroidServer.putArchiveEntry(binaryManifestXml);
    IOUtils.copy(manifestApk.getInputStream(binaryManifestXml), finalSelendroidServer);

    ZipFile selendroidPrebuildApk = new ZipFile(selendroidServer.getAbsolutePath());
    Enumeration<ZipArchiveEntry> entries = selendroidPrebuildApk.getEntries();
    for (; entries.hasMoreElements();) {
        ZipArchiveEntry dd = entries.nextElement();
        finalSelendroidServer.putArchiveEntry(dd);

        IOUtils.copy(selendroidPrebuildApk.getInputStream(dd), finalSelendroidServer);
    }

    finalSelendroidServer.closeArchiveEntry();
    finalSelendroidServer.close();
    manifestApk.close();
    log.info("file: " + finalSelendroidServerFile.getAbsolutePath());
    return finalSelendroidServerFile;
}

From source file:com.gitblit.servlet.PtServlet.java

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    try {//from ww  w  . ja  v a 2 s .  c o m
        response.setContentType("application/octet-stream");
        response.setDateHeader("Last-Modified", lastModified);
        response.setHeader("Cache-Control", "none");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);

        boolean windows = false;
        try {
            String useragent = request.getHeader("user-agent").toString();
            windows = useragent.toLowerCase().contains("windows");
        } catch (Exception e) {
        }

        byte[] pyBytes;
        File file = runtimeManager.getFileOrFolder("tickets.pt", "${baseFolder}/pt.py");
        if (file.exists()) {
            // custom script
            pyBytes = readAll(new FileInputStream(file));
        } else {
            // default script
            pyBytes = readAll(getClass().getResourceAsStream("/pt.py"));
        }

        if (windows) {
            // windows: download zip file with pt.py and pt.cmd
            response.setHeader("Content-Disposition", "attachment; filename=\"pt.zip\"");

            OutputStream os = response.getOutputStream();
            ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);

            // add the Python script
            ZipArchiveEntry pyEntry = new ZipArchiveEntry("pt.py");
            pyEntry.setSize(pyBytes.length);
            pyEntry.setUnixMode(FileMode.EXECUTABLE_FILE.getBits());
            pyEntry.setTime(lastModified);
            zos.putArchiveEntry(pyEntry);
            zos.write(pyBytes);
            zos.closeArchiveEntry();

            // add a Python launch cmd file
            byte[] cmdBytes = readAll(getClass().getResourceAsStream("/pt.cmd"));
            ZipArchiveEntry cmdEntry = new ZipArchiveEntry("pt.cmd");
            cmdEntry.setSize(cmdBytes.length);
            cmdEntry.setUnixMode(FileMode.REGULAR_FILE.getBits());
            cmdEntry.setTime(lastModified);
            zos.putArchiveEntry(cmdEntry);
            zos.write(cmdBytes);
            zos.closeArchiveEntry();

            // add a brief readme
            byte[] txtBytes = readAll(getClass().getResourceAsStream("/pt.txt"));
            ZipArchiveEntry txtEntry = new ZipArchiveEntry("readme.txt");
            txtEntry.setSize(txtBytes.length);
            txtEntry.setUnixMode(FileMode.REGULAR_FILE.getBits());
            txtEntry.setTime(lastModified);
            zos.putArchiveEntry(txtEntry);
            zos.write(txtBytes);
            zos.closeArchiveEntry();

            // cleanup
            zos.finish();
            zos.close();
            os.flush();
        } else {
            // unix: download a tar.gz file with pt.py set with execute permissions
            response.setHeader("Content-Disposition", "attachment; filename=\"pt.tar.gz\"");

            OutputStream os = response.getOutputStream();
            CompressorOutputStream cos = new CompressorStreamFactory()
                    .createCompressorOutputStream(CompressorStreamFactory.GZIP, os);
            TarArchiveOutputStream tos = new TarArchiveOutputStream(cos);
            tos.setAddPaxHeadersForNonAsciiNames(true);
            tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);

            // add the Python script
            TarArchiveEntry pyEntry = new TarArchiveEntry("pt");
            pyEntry.setMode(FileMode.EXECUTABLE_FILE.getBits());
            pyEntry.setModTime(lastModified);
            pyEntry.setSize(pyBytes.length);
            tos.putArchiveEntry(pyEntry);
            tos.write(pyBytes);
            tos.closeArchiveEntry();

            // add a brief readme
            byte[] txtBytes = readAll(getClass().getResourceAsStream("/pt.txt"));
            TarArchiveEntry txtEntry = new TarArchiveEntry("README");
            txtEntry.setMode(FileMode.REGULAR_FILE.getBits());
            txtEntry.setModTime(lastModified);
            txtEntry.setSize(txtBytes.length);
            tos.putArchiveEntry(txtEntry);
            tos.write(txtBytes);
            tos.closeArchiveEntry();

            // cleanup
            tos.finish();
            tos.close();
            cos.close();
            os.flush();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}