Skip to content

Commit

Permalink
Add support for gzip compressed layers
Browse files Browse the repository at this point in the history
  • Loading branch information
mhalbritter committed Apr 23, 2024
1 parent e496a6f commit 307cd4d
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@

package org.springframework.boot.buildpack.platform.build;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
Expand Down Expand Up @@ -109,6 +112,56 @@ static Buildpack resolve(BuildpackResolverContext context, BuildpackReference re
}
}

enum FileType {

TAR(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72 }, 257) {
@Override
InputStream wrap(InputStream stream) {
return stream;
}
},
TAR_GZIP(new byte[] { 0x1f, (byte) 0x8b }, 0) {
@Override
InputStream wrap(InputStream stream) throws IOException {
return new GZIPInputStream(stream);
}
},
TAR_ZSTD(new byte[] { 0x28, (byte) 0xb5, 0x2f, (byte) 0xfd }, 0) {
@Override
InputStream wrap(InputStream stream) {
throw new IllegalStateException("zstd compression is not supported");
}
};

private final int offset;

private final byte[] magic;

FileType(byte[] magic, int offset) {
this.offset = offset;
this.magic = magic;
}

abstract InputStream wrap(InputStream stream) throws IOException;

static FileType detect(Path path) throws IOException {
try (FileInputStream stream = new FileInputStream(path.toFile())) {
for (FileType value : FileType.values()) {
byte[] magic = new byte[value.magic.length];
stream.getChannel().position(value.offset);
if (stream.read(magic) == -1) {
continue;
}
if (Arrays.equals(magic, value.magic)) {
return value;
}
}
return FileType.TAR;
}
}

}

private static class ExportedLayers {

private final List<Path> layerFiles;
Expand All @@ -128,7 +181,8 @@ private Path copyToTemp(Path path) throws IOException {
}

private void copyLayerTar(Path path, OutputStream out) throws IOException {
try (TarArchiveInputStream tarIn = new TarArchiveInputStream(Files.newInputStream(path));
FileType fileType = FileType.detect(path);
try (TarArchiveInputStream tarIn = new TarArchiveInputStream(fileType.wrap(Files.newInputStream(path)));
TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) {
tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
TarArchiveEntry entry = tarIn.getNextEntry();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
Expand All @@ -34,6 +36,7 @@
import org.junit.jupiter.api.Test;
import org.mockito.invocation.InvocationOnMock;

import org.springframework.boot.buildpack.platform.build.ImageBuildpack.FileType;
import org.springframework.boot.buildpack.platform.docker.type.Image;
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
import org.springframework.boot.buildpack.platform.io.IOBiConsumer;
Expand Down Expand Up @@ -174,6 +177,22 @@ void resolveWhenUnqualifiedReferenceWithInvalidImageReferenceReturnsNull() {
assertThat(buildpack).isNull();
}

@Test
void detectsType() throws IOException {
assertThat(FileType.detect(extractResource("empty.tar"))).isEqualTo(FileType.TAR);
assertThat(FileType.detect(extractResource("empty.tar.gz"))).isEqualTo(FileType.TAR_GZIP);
assertThat(FileType.detect(extractResource("empty.tar.zst"))).isEqualTo(FileType.TAR_ZSTD);
}

private static Path extractResource(String resource) throws IOException {
Path file = Files.createTempFile("ImageBuildpackTests", ".tmp");
try (InputStream stream = ImageBuildpackTests.class.getResourceAsStream(resource)) {
assertThat(stream).as("Resource %s", resource).isNotNull();
Files.copy(stream, file, StandardCopyOption.REPLACE_EXISTING);
}
return file;
}

private Object withMockLayers(InvocationOnMock invocation) {
try {
IOBiConsumer<String, Path> consumer = invocation.getArgument(1);
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 307cd4d

Please sign in to comment.