Skip to content

Commit

Permalink
feat (jkube-kit/common) : Add utility class to decompress archive fil…
Browse files Browse the repository at this point in the history
…es (eclipse-jkube#2456)

Add JKubeArchiveDecompressor utility class.
It's extractArchive method would extract the utility class to specified
folder. It only supports `.tgz` and `.zip` files at the moment.

Signed-off-by: Rohan Kumar <rohaan@redhat.com>
  • Loading branch information
rohanKanojia committed Nov 22, 2023
1 parent 031d08f commit 4f02057
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Usage:
* Fix #1690: Base images based on ubi9
* Fix #2390: support for all missing Chart.yaml fields
* Fix #2444: Add support for Spring Boot application properties placeholders
* Fix #2456: Add utility class to decompress archive files

### 1.15.0 (2023-11-10)
* Fix #2138: Support for Spring Boot Native Image
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.kit.common.archive;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.eclipse.jkube.kit.common.util.FileUtil;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class JKubeArchiveDecompressor {
private JKubeArchiveDecompressor() { }

/**
* Extracts a given archive file to specified target directory
*
* @param inputArchiveFile input archive file
* @param targetDirectory target folder where you want to extract
*/
public static void extractArchive(File inputArchiveFile, File targetDirectory) throws IOException {
if (targetDirectory.exists()) {
FileUtil.cleanDirectory(targetDirectory);
}
Files.createDirectory(targetDirectory.toPath());
if (inputArchiveFile.getName().endsWith(".tgz")) {
extractTarArchive(inputArchiveFile, targetDirectory.toPath());
} else if (inputArchiveFile.getName().endsWith(".zip")) {
extractZipArchive(inputArchiveFile, targetDirectory.toPath());
}
}

private static void extractTarArchive(File downloadedArchive, Path targetExtractionDir) throws IOException {
try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(downloadedArchive.toPath()));
TarArchiveInputStream tar = new TarArchiveInputStream(new GzipCompressorInputStream(inputStream))) {
ArchiveEntry entry;
while ((entry = tar.getNextEntry()) != null) {
Path extractTo = targetExtractionDir.resolve(entry.getName());
if (entry.isDirectory()) {
Files.createDirectories(extractTo);
} else {
Files.copy(tar, extractTo);
}
}
}
}

private static void extractZipArchive(File downloadedArchive, Path targetExtractionDir) throws IOException {
byte[] buffer = new byte[1024];
try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(downloadedArchive.toPath()))) {
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = new File(targetExtractionDir.toFile(), zipEntry.getName());
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
} else {
// fix for Windows-created archives
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent);
}

// write file content
try (FileOutputStream fos = new FileOutputStream(newFile)) {
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
}
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at:
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jkube.kit.common.archive;

import org.eclipse.jkube.kit.common.assertj.FileAssertions;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import java.io.File;
import java.io.IOException;

class JKubeArchiveDecompressorTest {
@TempDir
private File temporaryFolder;

@ParameterizedTest
@CsvSource({
"/archives/pack-v0.31.0-linux.tgz,pack",
"/archives/pack-v0.31.0-windows.zip,pack.exe"
})
void extractArchive_whenArchiveWithSingleFileProvided_thenExtractToSpecifiedDir(String filePath, String expectedFileInExtractedArchiveName) throws IOException {
// Given
File input = new File(getClass().getResource(filePath).getFile());

// When
JKubeArchiveDecompressor.extractArchive(input, temporaryFolder);

// Then
FileAssertions.assertThat(temporaryFolder)
.exists()
.fileTree()
.containsExactlyInAnyOrder(expectedFileInExtractedArchiveName);
}

@ParameterizedTest
@CsvSource({
"/archives/nested-archive.tgz,nested,nested/folder,nested/folder/artifact",
"/archives/nested-archive.zip,nested,nested/folder,nested/folder/artifact.exe"
})
void extractArchive_whenArchiveWithNestedDir_thenExtractToSpecifiedDir(String filePath, String parentDir, String artifactParentDir, String artifact) throws IOException {
// Given
File input = new File(getClass().getResource(filePath).getFile());

// When
JKubeArchiveDecompressor.extractArchive(input, temporaryFolder);

// Then
FileAssertions.assertThat(temporaryFolder)
.exists()
.fileTree()
.containsExactlyInAnyOrder(parentDir, artifactParentDir, artifact);
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 4f02057

Please sign in to comment.