Skip to content

Commit 1cde062

Browse files
authored
Ensure to include parent folder into archive (#356)
2 parents 2fbfc58 + 07b24a9 commit 1cde062

File tree

5 files changed

+125
-40
lines changed

5 files changed

+125
-40
lines changed

src/main/java/land/oras/OCI.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,15 @@ protected final List<Layer> pushLayers(T ref, boolean withDigest, LocalPath... p
167167
ref = ref.withDigest(ref.getAlgorithm().digest(tempArchive.getPath()));
168168
}
169169
try (InputStream is = Files.newInputStream(tempArchive.getPath())) {
170+
String title = path.getPath().isAbsolute()
171+
? path.getPath().getFileName().toString()
172+
: path.getPath().toString();
173+
LOG.debug("Uploading directory as archive with title: {}", title);
170174
Layer layer = pushBlob(ref, is)
171175
.withMediaType(path.getMediaType())
172176
.withAnnotations(Map.of(
173177
Const.ANNOTATION_TITLE,
174-
path.getPath().getFileName().toString(),
178+
title,
175179
Const.ANNOTATION_ORAS_CONTENT_DIGEST,
176180
ref.getAlgorithm().digest(tempTar.getPath()),
177181
Const.ANNOTATION_ORAS_UNPACK,

src/main/java/land/oras/utils/ArchiveUtils.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public static Path createTempDir() {
9393
*/
9494
public static LocalPath tar(LocalPath sourceDir) {
9595
Path tarFile = createTempTar();
96+
boolean isAbsolute = sourceDir.getPath().isAbsolute();
9697
try (OutputStream fos = Files.newOutputStream(tarFile);
9798

9899
// Output stream chain
@@ -104,8 +105,8 @@ public static LocalPath tar(LocalPath sourceDir) {
104105
paths.forEach(path -> {
105106
LOG.trace("Visiting path: {}", path);
106107
try {
107-
108-
Path relativePath = sourceDir.getPath().relativize(path);
108+
Path baseName = isAbsolute ? sourceDir.getPath().getFileName() : sourceDir.getPath();
109+
Path relativePath = baseName.resolve(sourceDir.getPath().relativize(path));
109110
if (relativePath.toString().isEmpty()) {
110111
LOG.trace("Skipping root directory: {}", path);
111112
return;

src/test/java/land/oras/RegistryTest.java

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -905,13 +905,14 @@ void testShouldPushAndPullCompressedTarGzDirectory() throws IOException {
905905
registry.pullArtifact(containerRef, extractDir, true);
906906

907907
// Assert extracted files
908-
assertEquals("foobar", Files.readString(extractDir.resolve("file1.txt")));
909-
assertEquals("test1234", Files.readString(extractDir.resolve("file2.txt")));
910-
assertEquals("barfoo", Files.readString(extractDir.resolve("file3.txt")));
908+
Path extractedDir = extractDir.resolve(blobDir.getFileName());
909+
assertEquals("foobar", Files.readString(extractedDir.resolve("file1.txt")));
910+
assertEquals("test1234", Files.readString(extractedDir.resolve("file2.txt")));
911+
assertEquals("barfoo", Files.readString(extractedDir.resolve("file3.txt")));
911912
}
912913

913914
@Test
914-
void testShouldPushAndPullUncompressedTarDirectory() throws IOException {
915+
void testShouldPushAndPullUncompressedTarDirectoryWithAbsolutePath() throws IOException {
915916

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

951952
// Assert extracted files
952-
assertEquals("foobar", Files.readString(extractDir.resolve("file1.txt")));
953-
assertEquals("test1234", Files.readString(extractDir.resolve("file2.txt")));
954-
assertEquals("barfoo", Files.readString(extractDir.resolve("file3.txt")));
953+
Path extractedDir = this.extractDir.resolve(blobDir.getFileName());
954+
assertEquals("foobar", Files.readString(extractedDir.resolve("file1.txt")));
955+
assertEquals("test1234", Files.readString(extractedDir.resolve("file2.txt")));
956+
assertEquals("barfoo", Files.readString(extractedDir.resolve("file3.txt")));
957+
}
958+
959+
@Test
960+
void testShouldPushAndPullUncompressedTarDirectoryWithRelativePath() throws IOException {
961+
962+
Registry registry = Registry.Builder.builder()
963+
.defaults("myuser", "mypass")
964+
.withInsecure(true)
965+
.build();
966+
ContainerRef containerRef =
967+
ContainerRef.parse("%s/library/artifact-relative-path".formatted(this.registry.getRegistry()));
968+
969+
// Source
970+
Manifest manifest = registry.pushArtifact(
971+
containerRef, LocalPath.of(Path.of("src/main/java"), Const.DEFAULT_BLOB_MEDIA_TYPE));
972+
assertEquals(1, manifest.getLayers().size());
973+
974+
Layer layer = manifest.getLayers().get(0);
975+
976+
// A compressed directory file
977+
assertEquals(Const.DEFAULT_BLOB_MEDIA_TYPE, layer.getMediaType());
978+
Map<String, String> annotations = layer.getAnnotations();
979+
980+
// Assert annotations of the layer
981+
assertEquals(3, annotations.size());
982+
assertEquals("src/main/java", annotations.get(Const.ANNOTATION_TITLE)); // Keep relative path
983+
assertEquals("true", annotations.get(Const.ANNOTATION_ORAS_UNPACK));
984+
assertEquals(
985+
SupportedAlgorithm.SHA256,
986+
SupportedAlgorithm.fromDigest(annotations.get(Const.ANNOTATION_ORAS_CONTENT_DIGEST)));
987+
988+
// Pull
989+
registry.pullArtifact(containerRef, extractDir, false);
990+
991+
// Assert files under src/main/java
992+
Path extractedDir = this.extractDir.resolve("src/main/java");
993+
assertTrue(Files.exists(extractedDir.resolve("land/oras/Config.java")), "Config.java should exist");
955994
}
956995

957996
@Test
@@ -993,9 +1032,10 @@ void testShouldPushAndPullCompressedZstdDirectory() throws IOException {
9931032
registry.pullArtifact(containerRef, extractDir, true);
9941033

9951034
// Assert extracted files
996-
assertEquals("foobar", Files.readString(extractDir.resolve("file1.txt")));
997-
assertEquals("test1234", Files.readString(extractDir.resolve("file2.txt")));
998-
assertEquals("barfoo", Files.readString(extractDir.resolve("file3.txt")));
1035+
Path extractedDir = extractDir.resolve(blobDir.getFileName());
1036+
assertEquals("foobar", Files.readString(extractedDir.resolve("file1.txt")));
1037+
assertEquals("test1234", Files.readString(extractedDir.resolve("file2.txt")));
1038+
assertEquals("barfoo", Files.readString(extractedDir.resolve("file3.txt")));
9991039
}
10001040

10011041
@Test
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*-
2+
* =LICENSE=
3+
* ORAS Java SDK
4+
* ===
5+
* Copyright (C) 2024 - 2025 ORAS
6+
* ===
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
* =LICENSEEND=
19+
*/
20+
21+
package land.oras;
22+
23+
import org.junit.jupiter.api.Disabled;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.parallel.Execution;
26+
import org.junit.jupiter.api.parallel.ExecutionMode;
27+
28+
@Execution(ExecutionMode.CONCURRENT)
29+
class ZotLocalhostITCase {
30+
31+
@Test
32+
@Disabled("Only to test using localhost:5000 container")
33+
void shouldPushArtifactAndPullWithOrasCli() {
34+
Registry registry = Registry.builder().insecure().build();
35+
ContainerRef containerRef1 = ContainerRef.parse("localhost:5000/foo:java");
36+
registry.pushArtifact(containerRef1, LocalPath.of("src/main/java"));
37+
}
38+
}

src/test/java/land/oras/utils/ArchiveUtilsTest.java

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import org.slf4j.LoggerFactory;
4444

4545
@Execution(ExecutionMode.CONCURRENT)
46-
public class ArchiveUtilsTest {
46+
class ArchiveUtilsTest {
4747

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

160160
// Ensure all files are extracted
161-
assertTrue(Files.exists(targetGzDir.resolve("dir1")), "dir1 should exist");
162-
assertTrue(Files.exists(targetGzDir.resolve("dir2")), "dir2 should exist");
163-
assertTrue(Files.exists(targetGzDir.resolve("dir1").resolve("file1")), "file1 should exist");
164-
assertTrue(Files.exists(targetGzDir.resolve("dir2").resolve("file2")), "file2 should exist");
165-
assertTrue(Files.exists(targetGzDir.resolve("dir1").resolve("file3")), "file3 should exist");
166-
assertTrue(Files.exists(targetGzDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
167-
assertTrue(Files.exists(targetGzDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");
161+
Path extractedDir = targetGzDir.resolve(directory.getPath().getFileName());
162+
assertTrue(Files.exists(extractedDir.resolve("dir1")), "dir1 should exist");
163+
assertTrue(Files.exists(extractedDir.resolve("dir2")), "dir2 should exist");
164+
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file1")), "file1 should exist");
165+
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("file2")), "file2 should exist");
166+
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file3")), "file3 should exist");
167+
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
168+
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");
168169

169170
// Empty directory
170-
assertTrue(Files.exists(targetGzDir.resolve("empty")), "empty should exist");
171+
assertTrue(Files.exists(extractedDir.resolve("empty")), "empty should exist");
171172

172173
// Assert file content
173174
assertTrue(
174-
Files.readString(targetGzDir.resolve("dir1").resolve("file1")).equals("file1"),
175+
Files.readString(extractedDir.resolve("dir1").resolve("file1")).equals("file1"),
175176
"file1 content should match");
176177
assertTrue(
177-
Files.readString(targetGzDir.resolve("dir2").resolve("file2")).equals("file2"),
178+
Files.readString(extractedDir.resolve("dir2").resolve("file2")).equals("file2"),
178179
"file2 content should match");
179180
assertTrue(
180-
Files.readString(targetGzDir.resolve("dir2").resolve("dir3").resolve("file4"))
181+
Files.readString(extractedDir.resolve("dir2").resolve("dir3").resolve("file4"))
181182
.equals("file4"),
182183
"file4 content should match");
183184

184185
// Ensure symlink is extracted
185-
assertTrue(Files.isSymbolicLink(targetGzDir.resolve("dir1").resolve("file3")), "file3 should be symlink");
186+
assertTrue(Files.isSymbolicLink(extractedDir.resolve("dir1").resolve("file3")), "file3 should be symlink");
186187

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

212213
// Ensure all files are extracted
213-
assertTrue(Files.exists(targetZstdDir.resolve("dir1")), "dir1 should exist");
214-
assertTrue(Files.exists(targetZstdDir.resolve("dir2")), "dir2 should exist");
215-
assertTrue(Files.exists(targetZstdDir.resolve("dir1").resolve("file1")), "file1 should exist");
216-
assertTrue(Files.exists(targetZstdDir.resolve("dir2").resolve("file2")), "file2 should exist");
217-
assertTrue(Files.exists(targetZstdDir.resolve("dir1").resolve("file3")), "file3 should exist");
218-
assertTrue(Files.exists(targetZstdDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
219-
assertTrue(Files.exists(targetZstdDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");
214+
Path extractedDir = targetZstdDir.resolve(directory.getPath().getFileName());
215+
assertTrue(Files.exists(extractedDir.resolve("dir1")), "dir1 should exist");
216+
assertTrue(Files.exists(extractedDir.resolve("dir2")), "dir2 should exist");
217+
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file1")), "file1 should exist");
218+
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("file2")), "file2 should exist");
219+
assertTrue(Files.exists(extractedDir.resolve("dir1").resolve("file3")), "file3 should exist");
220+
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3")), "dir3 should exist");
221+
assertTrue(Files.exists(extractedDir.resolve("dir2").resolve("dir3").resolve("file4")), "file4 should exist");
220222

221223
// Empty directory
222-
assertTrue(Files.exists(targetZstdDir.resolve("empty")), "empty should exist");
224+
assertTrue(Files.exists(extractedDir.resolve("empty")), "empty should exist");
223225

224226
// Assert file content
225227
assertTrue(
226-
Files.readString(targetZstdDir.resolve("dir1").resolve("file1")).equals("file1"),
228+
Files.readString(extractedDir.resolve("dir1").resolve("file1")).equals("file1"),
227229
"file1 content should match");
228230
assertTrue(
229-
Files.readString(targetZstdDir.resolve("dir2").resolve("file2")).equals("file2"),
231+
Files.readString(extractedDir.resolve("dir2").resolve("file2")).equals("file2"),
230232
"file2 content should match");
231233
assertTrue(
232-
Files.readString(targetZstdDir.resolve("dir2").resolve("dir3").resolve("file4"))
234+
Files.readString(extractedDir.resolve("dir2").resolve("dir3").resolve("file4"))
233235
.equals("file4"),
234236
"file4 content should match");
235237

236238
// Ensure symlink is extracted
237-
assertTrue(Files.isSymbolicLink(targetZstdDir.resolve("dir1").resolve("file3")), "file3 should be symlink");
239+
assertTrue(Files.isSymbolicLink(extractedDir.resolve("dir1").resolve("file3")), "file3 should be symlink");
238240

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

0 commit comments

Comments
 (0)