/* * Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file 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 com.amazonaws.codepipeline.jenkinsplugin; import hudson.model.TaskListener; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.utils.IOUtils; import org.apache.commons.io.FileUtils; import com.amazonaws.codepipeline.jenkinsplugin.CodePipelineStateModel.CompressionType; import com.amazonaws.services.s3.model.S3Object; public final class ExtractionTools { private ExtractionTools() {} private static void extractZip(final File source, final File destination) throws IOException { try (final ZipFile zipFile = new ZipFile(source, StandardCharsets.UTF_8.name(), true)) { extractZipFile(destination, zipFile); } } private static void extractTar(final File source, final File destination) throws IOException { try (final ArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(new FileInputStream(source))) { extractArchive(destination, tarArchiveInputStream); } } private static void extractTarGz(final File source, final File destination) throws IOException { try (final ArchiveInputStream tarGzArchiveInputStream = new TarArchiveInputStream(new GzipCompressorInputStream(new FileInputStream(source)))) { extractArchive(destination, tarGzArchiveInputStream); } } // Use of ZipFile is recommended, ZipArchiveInputStream has many limitations // https://commons.apache.org/proper/commons-compress/zip.html private static void extractZipFile(final File destination, final ZipFile zipFile) throws IOException { final Enumeration<ZipArchiveEntry> entries = zipFile.getEntries(); while (entries.hasMoreElements()) { final ZipArchiveEntry entry = entries.nextElement(); final File entryDestination = new File(destination, entry.getName()); if (entry.isDirectory()) { entryDestination.mkdirs(); } else { entryDestination.getParentFile().mkdirs(); final InputStream in = zipFile.getInputStream(entry); try (final OutputStream out = new FileOutputStream(entryDestination)) { IOUtils.copy(in, out); IOUtils.closeQuietly(in); } } } } private static void extractArchive(final File destination, final ArchiveInputStream archiveInputStream) throws IOException { final int BUFFER_SIZE = 8192; ArchiveEntry entry = archiveInputStream.getNextEntry(); while (entry != null) { final File destinationFile = new File(destination, entry.getName()); if (entry.isDirectory()) { destinationFile.mkdir(); } else { destinationFile.getParentFile().mkdirs(); try (final OutputStream fileOutputStream = new FileOutputStream(destinationFile)) { final byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = archiveInputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, bytesRead); } } } entry = archiveInputStream.getNextEntry(); } } public static void deleteTemporaryCompressedFile(final File fileToDelete) throws IOException { if (fileToDelete.isDirectory()) { FileUtils.deleteDirectory(fileToDelete); } else { if (!fileToDelete.delete()) { fileToDelete.deleteOnExit(); } } } public static CompressionType getCompressionType(final S3Object sessionObject, final TaskListener l) { final String key = sessionObject.getKey(); CompressionType compressionType = CompressionType.None; if (endsWithLowerCase(key, ".zip")) { compressionType = CompressionType.Zip; } else if (endsWithLowerCase(key, ".tar.gz")) { compressionType = CompressionType.TarGz; } else if (endsWithLowerCase(key, ".tar")) { compressionType = CompressionType.Tar; } if (compressionType == CompressionType.None) { final String contentType = sessionObject.getObjectMetadata().getContentType(); if ("application/zip".equalsIgnoreCase(contentType)) { compressionType = CompressionType.Zip; } else if ("application/gzip".equalsIgnoreCase(contentType) || "application/x-gzip".equalsIgnoreCase(contentType)) { compressionType = CompressionType.TarGz; } else if ("application/tar".equalsIgnoreCase(contentType) || "application/x-tar".equalsIgnoreCase(contentType)) { compressionType = CompressionType.Tar; } } LoggingHelper.log(l, "Detected compression type: %s", compressionType.name()); return compressionType; } public static boolean endsWithLowerCase(final String input, final String postFix) { return input.toLowerCase().endsWith(postFix.toLowerCase()); } public static void decompressFile( final File compressedFile, final File destination, final CompressionType compressionType, final TaskListener listener) throws IOException { LoggingHelper.log(listener, "Extracting '%s' to '%s'", compressedFile.getAbsolutePath(), destination.getAbsolutePath()); switch (compressionType) { case None: // Attempt to decompress with Zip if it is unknown case Zip: extractZip(compressedFile, destination); break; case Tar: extractTar(compressedFile, destination); break; case TarGz: extractTarGz(compressedFile, destination); break; } } }