Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/main/java/land/oras/OCI.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,15 @@ protected final List<Layer> pushLayers(T ref, boolean withDigest, LocalPath... p
ref = ref.withDigest(ref.getAlgorithm().digest(tempArchive.getPath()));
}
try (InputStream is = Files.newInputStream(tempArchive.getPath())) {
String title = path.getPath().isAbsolute()
? path.getPath().getFileName().toString()
: path.getPath().toString();
LOG.debug("Uploading directory as archive with title: {}", title);
Layer layer = pushBlob(ref, is)
.withMediaType(path.getMediaType())
.withAnnotations(Map.of(
Const.ANNOTATION_TITLE,
path.getPath().getFileName().toString(),
title,
Const.ANNOTATION_ORAS_CONTENT_DIGEST,
ref.getAlgorithm().digest(tempTar.getPath()),
Const.ANNOTATION_ORAS_UNPACK,
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/land/oras/utils/ArchiveUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public static Path createTempDir() {
*/
public static LocalPath tar(LocalPath sourceDir) {
Path tarFile = createTempTar();
boolean isAbsolute = sourceDir.getPath().isAbsolute();
try (OutputStream fos = Files.newOutputStream(tarFile);

// Output stream chain
Expand All @@ -104,8 +105,8 @@ public static LocalPath tar(LocalPath sourceDir) {
paths.forEach(path -> {
LOG.trace("Visiting path: {}", path);
try {

Path relativePath = sourceDir.getPath().relativize(path);
Path baseName = isAbsolute ? sourceDir.getPath().getFileName() : sourceDir.getPath();
Path relativePath = baseName.resolve(sourceDir.getPath().relativize(path));
if (relativePath.toString().isEmpty()) {
LOG.trace("Skipping root directory: {}", path);
return;
Expand Down
60 changes: 50 additions & 10 deletions src/test/java/land/oras/RegistryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -905,13 +905,14 @@ void testShouldPushAndPullCompressedTarGzDirectory() throws IOException {
registry.pullArtifact(containerRef, extractDir, true);

// Assert extracted files
assertEquals("foobar", Files.readString(extractDir.resolve("file1.txt")));
assertEquals("test1234", Files.readString(extractDir.resolve("file2.txt")));
assertEquals("barfoo", Files.readString(extractDir.resolve("file3.txt")));
Path extractedDir = extractDir.resolve(blobDir.getFileName());
assertEquals("foobar", Files.readString(extractedDir.resolve("file1.txt")));
assertEquals("test1234", Files.readString(extractedDir.resolve("file2.txt")));
assertEquals("barfoo", Files.readString(extractedDir.resolve("file3.txt")));
}

@Test
void testShouldPushAndPullUncompressedTarDirectory() throws IOException {
void testShouldPushAndPullUncompressedTarDirectoryWithAbsolutePath() throws IOException {

Registry registry = Registry.Builder.builder()
.defaults("myuser", "mypass")
Expand Down Expand Up @@ -949,9 +950,47 @@ void testShouldPushAndPullUncompressedTarDirectory() throws IOException {
registry.pullArtifact(containerRef, extractDir, true);

// Assert extracted files
assertEquals("foobar", Files.readString(extractDir.resolve("file1.txt")));
assertEquals("test1234", Files.readString(extractDir.resolve("file2.txt")));
assertEquals("barfoo", Files.readString(extractDir.resolve("file3.txt")));
Path extractedDir = this.extractDir.resolve(blobDir.getFileName());
assertEquals("foobar", Files.readString(extractedDir.resolve("file1.txt")));
assertEquals("test1234", Files.readString(extractedDir.resolve("file2.txt")));
assertEquals("barfoo", Files.readString(extractedDir.resolve("file3.txt")));
}

@Test
void testShouldPushAndPullUncompressedTarDirectoryWithRelativePath() throws IOException {

Registry registry = Registry.Builder.builder()
.defaults("myuser", "mypass")
.withInsecure(true)
.build();
ContainerRef containerRef =
ContainerRef.parse("%s/library/artifact-relative-path".formatted(this.registry.getRegistry()));

// Source
Manifest manifest = registry.pushArtifact(
containerRef, LocalPath.of(Path.of("src/main/java"), Const.DEFAULT_BLOB_MEDIA_TYPE));
assertEquals(1, manifest.getLayers().size());

Layer layer = manifest.getLayers().get(0);

// A compressed directory file
assertEquals(Const.DEFAULT_BLOB_MEDIA_TYPE, layer.getMediaType());
Map<String, String> annotations = layer.getAnnotations();

// Assert annotations of the layer
assertEquals(3, annotations.size());
assertEquals("src/main/java", annotations.get(Const.ANNOTATION_TITLE)); // Keep relative path
assertEquals("true", annotations.get(Const.ANNOTATION_ORAS_UNPACK));
assertEquals(
SupportedAlgorithm.SHA256,
SupportedAlgorithm.fromDigest(annotations.get(Const.ANNOTATION_ORAS_CONTENT_DIGEST)));

// Pull
registry.pullArtifact(containerRef, extractDir, false);

// Assert files under src/main/java
Path extractedDir = this.extractDir.resolve("src/main/java");
assertTrue(Files.exists(extractedDir.resolve("land/oras/Config.java")), "Config.java should exist");
}

@Test
Expand Down Expand Up @@ -993,9 +1032,10 @@ void testShouldPushAndPullCompressedZstdDirectory() throws IOException {
registry.pullArtifact(containerRef, extractDir, true);

// Assert extracted files
assertEquals("foobar", Files.readString(extractDir.resolve("file1.txt")));
assertEquals("test1234", Files.readString(extractDir.resolve("file2.txt")));
assertEquals("barfoo", Files.readString(extractDir.resolve("file3.txt")));
Path extractedDir = extractDir.resolve(blobDir.getFileName());
assertEquals("foobar", Files.readString(extractedDir.resolve("file1.txt")));
assertEquals("test1234", Files.readString(extractedDir.resolve("file2.txt")));
assertEquals("barfoo", Files.readString(extractedDir.resolve("file3.txt")));
}

@Test
Expand Down
38 changes: 38 additions & 0 deletions src/test/java/land/oras/ZotLocalhostITCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*-
* =LICENSE=
* ORAS Java SDK
* ===
* Copyright (C) 2024 - 2025 ORAS
* ===
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.
* =LICENSEEND=
*/

package land.oras;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;

@Execution(ExecutionMode.CONCURRENT)
class ZotLocalhostITCase {

@Test
@Disabled("Only to test using localhost:5000 container")
void shouldPushArtifactAndPullWithOrasCli() {
Registry registry = Registry.builder().insecure().build();
ContainerRef containerRef1 = ContainerRef.parse("localhost:5000/foo:java");
registry.pushArtifact(containerRef1, LocalPath.of("src/main/java"));
}
}
56 changes: 29 additions & 27 deletions src/test/java/land/oras/utils/ArchiveUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import org.slf4j.LoggerFactory;

@Execution(ExecutionMode.CONCURRENT)
public class ArchiveUtilsTest {
class ArchiveUtilsTest {

/**
* Logger
Expand Down Expand Up @@ -155,34 +155,35 @@ void shouldCreateTarGzAndExtractIt() throws Exception {
// Untar to temporary
Path tmp = ArchiveUtils.untar(archive.getPath());
assertTrue(Files.exists(tmp), "Temp should exist");
assertTrue(Files.exists(tmp.resolve("dir1")), "dir1 should exist");
assertTrue(Files.exists(tmp.resolve(directory.getPath().getFileName()).resolve("dir1")), "dir1 should exist");

// Ensure all files are extracted
assertTrue(Files.exists(targetGzDir.resolve("dir1")), "dir1 should exist");
assertTrue(Files.exists(targetGzDir.resolve("dir2")), "dir2 should exist");
assertTrue(Files.exists(targetGzDir.resolve("dir1").resolve("file1")), "file1 should exist");
assertTrue(Files.exists(targetGzDir.resolve("dir2").resolve("file2")), "file2 should exist");
assertTrue(Files.exists(targetGzDir.resolve("dir1").resolve("file3")), "file3 should exist");
assertTrue(Files.exists(targetGzDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
assertTrue(Files.exists(targetGzDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");
Path extractedDir = targetGzDir.resolve(directory.getPath().getFileName());
assertTrue(Files.exists(extractedDir.resolve("dir1")), "dir1 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2")), "dir2 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file1")), "file1 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("file2")), "file2 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file3")), "file3 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");

// Empty directory
assertTrue(Files.exists(targetGzDir.resolve("empty")), "empty should exist");
assertTrue(Files.exists(extractedDir.resolve("empty")), "empty should exist");

// Assert file content
assertTrue(
Files.readString(targetGzDir.resolve("dir1").resolve("file1")).equals("file1"),
Files.readString(extractedDir.resolve("dir1").resolve("file1")).equals("file1"),
"file1 content should match");
assertTrue(
Files.readString(targetGzDir.resolve("dir2").resolve("file2")).equals("file2"),
Files.readString(extractedDir.resolve("dir2").resolve("file2")).equals("file2"),
"file2 content should match");
assertTrue(
Files.readString(targetGzDir.resolve("dir2").resolve("dir3").resolve("file4"))
Files.readString(extractedDir.resolve("dir2").resolve("dir3").resolve("file4"))
.equals("file4"),
"file4 content should match");

// Ensure symlink is extracted
assertTrue(Files.isSymbolicLink(targetGzDir.resolve("dir1").resolve("file3")), "file3 should be symlink");
assertTrue(Files.isSymbolicLink(extractedDir.resolve("dir1").resolve("file3")), "file3 should be symlink");

// To temporary
Path temp = ArchiveUtils.uncompressuntar(compressedArchive, directory.getMediaType());
Expand All @@ -207,34 +208,35 @@ void shouldCreateTarZstdAndExtractIt() throws Exception {
// Untar to temporary
Path tmp = ArchiveUtils.untar(archive.getPath());
assertTrue(Files.exists(tmp), "Temp should exist");
assertTrue(Files.exists(tmp.resolve("dir1")), "dir1 should exist");
assertTrue(Files.exists(tmp.resolve(directory.getPath().getFileName()).resolve("dir1")), "dir1 should exist");

// Ensure all files are extracted
assertTrue(Files.exists(targetZstdDir.resolve("dir1")), "dir1 should exist");
assertTrue(Files.exists(targetZstdDir.resolve("dir2")), "dir2 should exist");
assertTrue(Files.exists(targetZstdDir.resolve("dir1").resolve("file1")), "file1 should exist");
assertTrue(Files.exists(targetZstdDir.resolve("dir2").resolve("file2")), "file2 should exist");
assertTrue(Files.exists(targetZstdDir.resolve("dir1").resolve("file3")), "file3 should exist");
assertTrue(Files.exists(targetZstdDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
assertTrue(Files.exists(targetZstdDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");
Path extractedDir = targetZstdDir.resolve(directory.getPath().getFileName());
assertTrue(Files.exists(extractedDir.resolve("dir1")), "dir1 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2")), "dir2 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file1")), "file1 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("file2")), "file2 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file3")), "file3 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");

// Empty directory
assertTrue(Files.exists(targetZstdDir.resolve("empty")), "empty should exist");
assertTrue(Files.exists(extractedDir.resolve("empty")), "empty should exist");

// Assert file content
assertTrue(
Files.readString(targetZstdDir.resolve("dir1").resolve("file1")).equals("file1"),
Files.readString(extractedDir.resolve("dir1").resolve("file1")).equals("file1"),
"file1 content should match");
assertTrue(
Files.readString(targetZstdDir.resolve("dir2").resolve("file2")).equals("file2"),
Files.readString(extractedDir.resolve("dir2").resolve("file2")).equals("file2"),
"file2 content should match");
assertTrue(
Files.readString(targetZstdDir.resolve("dir2").resolve("dir3").resolve("file4"))
Files.readString(extractedDir.resolve("dir2").resolve("dir3").resolve("file4"))
.equals("file4"),
"file4 content should match");

// Ensure symlink is extracted
assertTrue(Files.isSymbolicLink(targetZstdDir.resolve("dir1").resolve("file3")), "file3 should be symlink");
assertTrue(Files.isSymbolicLink(extractedDir.resolve("dir1").resolve("file3")), "file3 should be symlink");

// To temporary
Path temp = ArchiveUtils.uncompressuntar(compressedArchive, directory.getMediaType());
Expand Down