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 (#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 <[email protected]>
  • Loading branch information
rohanKanojia committed Nov 22, 2023
1 parent 031d08f commit 659ff96
Show file tree
Hide file tree
Showing 7 changed files with 156 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,90 @@
/*
* 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
* @throws IOException in case of failure while trying to create any directory
*/
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()) {

Check failure

Code scanning / SonarCloud

Extracting archives should not lead to zip slip vulnerabilities Critical

Change this code to not construct the path from file name entry of an archive. See more on SonarCloud
throw new IOException("Failed to create directory " + newFile);
}
} else {
try (FileOutputStream fos = new FileOutputStream(newFile)) {

Check failure

Code scanning / SonarCloud

Extracting archives should not lead to zip slip vulnerabilities Critical

Change this code to not construct the path from file name entry of an archive. See more on SonarCloud
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 659ff96

Please sign in to comment.