Skip to content

Commit 8c78392

Browse files
authored
Fix copy using target tag (#653)
Signed-off-by: Valentin Delaye <jonesbusy@users.noreply.github.com>
1 parent fa79592 commit 8c78392

4 files changed

Lines changed: 57 additions & 22 deletions

File tree

src/main/java/land/oras/ContainerRef.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private ContainerRef(
9797
boolean unqualified,
9898
@Nullable String namespace,
9999
String repository,
100-
String tag,
100+
@Nullable String tag,
101101
@Nullable String digest) {
102102
super(tag);
103103
this.unqualified = unqualified;
@@ -210,7 +210,8 @@ public String getRepository() {
210210

211211
@Override
212212
public ContainerRef withDigest(String digest) {
213-
return new ContainerRef(registry, unqualified, namespace, repository, tag, digest);
213+
// Ensure to set tag to null when setting digest
214+
return new ContainerRef(registry, unqualified, namespace, repository, null, digest);
214215
}
215216

216217
/**

src/main/java/land/oras/CopyUtils.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public static CopyOptions deep() {
7474
* @param sourceRef The source reference
7575
* @param target The target OCI
7676
* @param targetRef The target reference
77-
* @param recursive Copy refferers
77+
* @param recursive Copy referers
7878
* @param <SourceRefType> The source reference type
7979
* @param <TargetRefType> The target reference type
8080
*/
@@ -185,7 +185,7 @@ void copy(
185185

186186
// Write manifest as any blob
187187
Manifest manifest = source.getManifest(effectiveSourceRef);
188-
String tag = effectiveSourceRef.getTag();
188+
String targetTag = effectiveTargetRef.getTag();
189189

190190
Objects.requireNonNull(manifest.getDigest(), "Manifest digest is required for streaming copy");
191191

@@ -194,8 +194,8 @@ void copy(
194194

195195
// Push the manifest
196196
LOG.debug("Copying manifest {}", manifestDigest);
197-
target.pushManifest(effectiveTargetRef.withDigest(tag), manifest);
198-
LOG.debug("Copied manifest {}", manifestDigest);
197+
target.pushManifest(effectiveTargetRef.withDigest(targetTag), manifest);
198+
LOG.debug("Copied manifest {} with tag {}", manifestDigest, targetTag);
199199

200200
if (includeReferrers) {
201201
LOG.debug("Including referrers on copy of manifest {}", manifestDigest);
@@ -206,7 +206,7 @@ void copy(
206206
source,
207207
effectiveSourceRef.withDigest(referer.getDigest()),
208208
target,
209-
effectiveTargetRef,
209+
effectiveTargetRef.withDigest(referer.getDigest()),
210210
options);
211211
}
212212
} else {
@@ -218,7 +218,7 @@ void copy(
218218
else if (source.isIndexMediaType(contentType)) {
219219

220220
Index index = source.getIndex(effectiveSourceRef);
221-
String tag = effectiveSourceRef.getTag();
221+
String targetTag = effectiveTargetRef.getTag();
222222

223223
// Write all manifests and their config
224224
for (ManifestDescriptor manifestDescriptor : index.getManifests()) {
@@ -260,8 +260,8 @@ else if (source.isIndexMediaType(contentType)) {
260260
}
261261

262262
LOG.debug("Copying index {}", manifestDigest);
263-
Index pushedIndex = target.pushIndex(effectiveTargetRef.withDigest(tag), index);
264-
LOG.debug("Copied index {} with tag {}", pushedIndex, tag);
263+
Index pushedIndex = target.pushIndex(effectiveTargetRef.withDigest(targetTag), index);
264+
LOG.debug("Copied index {} with tag {}", pushedIndex, targetTag);
265265

266266
} else {
267267
throw new OrasException("Unsupported content type: %s".formatted(contentType));

src/test/java/land/oras/OCILayoutTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ void testShouldCopyImageIntoOciLayoutWithoutIndexAndTag() {
900900
.build();
901901

902902
OCILayout ociLayout = OCILayout.Builder.builder().defaults(layoutPath).build();
903-
LayoutRef layoutRef = LayoutRef.parse("%s".formatted(ociLayout.getPath()));
903+
LayoutRef layoutRef = LayoutRef.parse("%s:the-tag".formatted(ociLayout.getPath()));
904904

905905
ContainerRef containerRef =
906906
ContainerRef.parse("%s/library/image-no-index".formatted(this.registry.getRegistry()));
@@ -963,7 +963,7 @@ void testShouldCopyImageIntoOciLayoutWithoutIndexAndTag() {
963963
Index index = Index.fromPath(layoutPath.resolve(Const.OCI_LAYOUT_INDEX));
964964

965965
// Check latest tag
966-
assertEquals("latest", index.getManifests().get(0).getAnnotations().get(Const.ANNOTATION_REF));
966+
assertEquals("the-tag", index.getManifests().get(0).getAnnotations().get(Const.ANNOTATION_REF));
967967
}
968968

969969
@Test
@@ -978,7 +978,7 @@ void testShouldCopyImageIntoOciLayoutWithIndex() {
978978

979979
OCILayout ociLayout =
980980
OCILayout.Builder.builder().defaults(layoutPathIndex).build();
981-
LayoutRef layoutRef = LayoutRef.parse("%s".formatted(ociLayout.getPath()));
981+
LayoutRef layoutRef = LayoutRef.parse("%s:latest".formatted(ociLayout.getPath()));
982982

983983
ContainerRef containerRef =
984984
ContainerRef.parse("%s/library/artifact-image-pull".formatted(this.registry.getRegistry()));

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

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ void testShouldCopyIndexOfIndexAndUseMounting() throws IOException {
10901090
assertNotNull(index1.getDescriptor(), "Index 1 descriptor should not be null");
10911091

10921092
Index index2 = Index.fromManifests(List.of(manifest2.getDescriptor(), index1.getDescriptor()));
1093-
index2 = registry.pushIndex(containerSource.withTag("index2"), index2);
1093+
registry.pushIndex(containerSource.withTag("index2"), index2);
10941094

10951095
// Copy to other registry
10961096
ContainerRef containerTarget =
@@ -1163,7 +1163,7 @@ void testShouldCopySingleArtifactFromRegistryIntoRegistry() throws IOException {
11631163
.build();
11641164

11651165
ContainerRef containerSource =
1166-
ContainerRef.parse("%s/library/artifact-source".formatted(this.registry.getRegistry()));
1166+
ContainerRef.parse("%s/library/artifact-source:foo".formatted(this.registry.getRegistry()));
11671167
Path file1 = blobDir.resolve("source.txt");
11681168
Files.writeString(file1, "foobar");
11691169

@@ -1174,11 +1174,48 @@ void testShouldCopySingleArtifactFromRegistryIntoRegistry() throws IOException {
11741174
// Copy to other registry
11751175
try (RegistryContainer otherRegistryContainer = new RegistryContainer()) {
11761176
otherRegistryContainer.start();
1177-
ContainerRef containerTarget =
1178-
ContainerRef.parse("%s/library/artifact-target".formatted(otherRegistryContainer.getRegistry()));
1177+
ContainerRef containerTarget = ContainerRef.parse(
1178+
"%s/library/artifact-target:bar".formatted(otherRegistryContainer.getRegistry()));
11791179
CopyUtils.copy(registry, containerSource, registry, containerTarget, CopyUtils.CopyOptions.shallow());
11801180
registry.pullArtifact(containerTarget, artifactDir, true);
11811181
assertEquals("foobar", Files.readString(artifactDir.resolve("source.txt")));
1182+
Manifest manifest2 = registry.getManifest(containerTarget);
1183+
assertNotNull(manifest2.getDescriptor(), "Manifest descriptor should not be null");
1184+
}
1185+
}
1186+
1187+
@Test
1188+
void testShouldCopySingleFromDigest() throws IOException {
1189+
// Copy to same registry
1190+
Registry registry = Registry.Builder.builder()
1191+
.defaults("myuser", "mypass")
1192+
.withInsecure(true)
1193+
.build();
1194+
1195+
ContainerRef containerSource =
1196+
ContainerRef.parse("%s/library/artifact-source:foo".formatted(this.registry.getRegistry()));
1197+
Path file1 = blobDir.resolve("source.txt");
1198+
Files.writeString(file1, "foobar");
1199+
1200+
// Push
1201+
Manifest manifest = registry.pushArtifact(containerSource, LocalPath.of(file1));
1202+
assertNotNull(manifest);
1203+
1204+
// Copy to other registry
1205+
try (RegistryContainer otherRegistryContainer = new RegistryContainer()) {
1206+
otherRegistryContainer.start();
1207+
ContainerRef containerTarget =
1208+
ContainerRef.parse("%s/library/artifact-target".formatted(otherRegistryContainer.getRegistry()));
1209+
CopyUtils.copy(
1210+
registry,
1211+
containerSource.withDigest(manifest.getDigest()),
1212+
registry,
1213+
containerTarget.withDigest(manifest.getDigest()),
1214+
CopyUtils.CopyOptions.shallow());
1215+
registry.pullArtifact(containerTarget.withDigest(manifest.getDigest()), artifactDir, true);
1216+
assertEquals("foobar", Files.readString(artifactDir.resolve("source.txt")));
1217+
Manifest manifest2 = registry.getManifest(containerTarget.withDigest(manifest.getDigest()));
1218+
assertNotNull(manifest2.getDescriptor(), "Manifest descriptor should not be null");
11821219
}
11831220
}
11841221

@@ -1321,12 +1358,9 @@ void testShouldCopyFromOciLayoutToRegistryNonRecursive() throws IOException {
13211358
void testShouldCopyFromOciLayoutToRegistryRecursive() throws IOException {
13221359

13231360
// Registry to copy
1324-
Registry registry = Registry.builder()
1325-
.defaults("myuser", "mypass")
1326-
.withInsecure(true)
1327-
.build();
1361+
Registry registry = Registry.builder().withInsecure(true).build();
13281362
ContainerRef targetRef = ContainerRef.parse(
1329-
"%s/library/copied-from-oci-layout-recursive".formatted(this.registry.getRegistry()));
1363+
"%s/library/copied-from-oci-layout-recursive".formatted(this.unsecureRegistry.getRegistry()));
13301364

13311365
LayoutRef layoutRef = LayoutRef.parse("src/test/resources/oci/subject:latest");
13321366
OCILayout ociLayout =

0 commit comments

Comments
 (0)