From 39f730988bc25d8f037c94c2cfb4e88a95891444 Mon Sep 17 00:00:00 2001 From: Valentin Delaye Date: Thu, 19 Feb 2026 11:21:36 +0100 Subject: [PATCH] Fix copy with alias Signed-off-by: Valentin Delaye --- src/main/java/land/oras/ContainerRef.java | 5 +++ src/main/java/land/oras/CopyUtils.java | 43 ++++++++++++----------- src/main/java/land/oras/LayoutRef.java | 5 +++ src/main/java/land/oras/Ref.java | 7 ++++ src/test/java/land/oras/RegistryTest.java | 2 -- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/main/java/land/oras/ContainerRef.java b/src/main/java/land/oras/ContainerRef.java index c76594a8..7b886e1d 100644 --- a/src/main/java/land/oras/ContainerRef.java +++ b/src/main/java/land/oras/ContainerRef.java @@ -482,6 +482,11 @@ public ContainerRef forTarget(String target) { return forRegistry(target); } + @Override + public ContainerRef forTarget(OCI target) { + return forRegistry((Registry) target); + } + @Override public String getTarget(OCI target) { return getEffectiveRegistry((Registry) target); diff --git a/src/main/java/land/oras/CopyUtils.java b/src/main/java/land/oras/CopyUtils.java index 107cd0c2..0df3a496 100644 --- a/src/main/java/land/oras/CopyUtils.java +++ b/src/main/java/land/oras/CopyUtils.java @@ -76,16 +76,18 @@ void copy( LOG.debug("Content type: {}", contentType); LOG.debug("Manifest digest: {}", manifestDigest); + SourceRefType effectiveSourceRef = sourceRef.forTarget(source).forTarget(resolveSourceRegistry); + TargetRefType effectiveTargetRef = targetRef.forTarget(target).forTarget(effectiveTargetRegistry); + // Write all layer - for (Layer layer : source.collectLayers(sourceRef.forTarget(resolveSourceRegistry), contentType, true)) { + for (Layer layer : source.collectLayers(effectiveSourceRef, contentType, true)) { Objects.requireNonNull(layer.getDigest(), "Layer digest is required for streaming copy"); Objects.requireNonNull(layer.getSize(), "Layer size is required for streaming copy"); LOG.debug("Copying layer {}", layer.getDigest()); target.pushBlob( - targetRef.forTarget(effectiveTargetRegistry).withDigest(layer.getDigest()), + effectiveTargetRef.withDigest(layer.getDigest()), layer.getSize(), - () -> source.fetchBlob( - sourceRef.forTarget(resolveSourceRegistry).withDigest(layer.getDigest())), + () -> source.fetchBlob(effectiveSourceRef.withDigest(layer.getDigest())), layer.getAnnotations()); LOG.debug("Copied layer {}", layer.getDigest()); } @@ -94,25 +96,30 @@ void copy( if (source.isManifestMediaType(contentType)) { // Write manifest as any blob - Manifest manifest = source.getManifest(sourceRef); - String tag = sourceRef.getTag(); + Manifest manifest = source.getManifest(effectiveSourceRef); + String tag = effectiveSourceRef.getTag(); Objects.requireNonNull(manifest.getDigest(), "Manifest digest is required for streaming copy"); // Push config - copyConfig(manifest, resolveSourceRegistry, effectiveTargetRegistry, source, sourceRef, target, targetRef); + copyConfig(manifest, source, effectiveSourceRef, target, effectiveTargetRef); // Push the manifest LOG.debug("Copying manifest {}", manifestDigest); - target.pushManifest(targetRef.withDigest(tag), manifest); + target.pushManifest(effectiveTargetRef.withDigest(tag), manifest); LOG.debug("Copied manifest {}", manifestDigest); if (recursive) { LOG.debug("Recursively copy referrers"); - Referrers referrers = source.getReferrers(sourceRef.withDigest(manifestDigest), null); + Referrers referrers = source.getReferrers(effectiveSourceRef.withDigest(manifestDigest), null); for (ManifestDescriptor referer : referrers.getManifests()) { LOG.info("Copy reference {}", referer.getDigest()); - copy(source, sourceRef.withDigest(referer.getDigest()), target, targetRef, recursive); + copy( + source, + effectiveSourceRef.withDigest(referer.getDigest()), + target, + effectiveTargetRef, + recursive); } } @@ -128,18 +135,18 @@ else if (source.isIndexMediaType(contentType)) { Manifest manifest = source.getManifest(sourceRef.withDigest(manifestDescriptor.getDigest())); // Push config - copyConfig( - manifest, resolveSourceRegistry, effectiveTargetRegistry, source, sourceRef, target, targetRef); + copyConfig(manifest, source, effectiveSourceRef, target, effectiveTargetRef); // Push the manifest LOG.debug("Copying manifest {}", manifestDigest); target.pushManifest( - targetRef.withDigest(manifest.getDigest()), manifest.withDescriptor(manifestDescriptor)); + effectiveTargetRef.withDigest(manifest.getDigest()), + manifest.withDescriptor(manifestDescriptor)); LOG.debug("Copied manifest {}", manifestDigest); } LOG.debug("Copying index {}", manifestDigest); - target.pushIndex(targetRef.withDigest(tag), index); + target.pushIndex(effectiveTargetRef.withDigest(tag), index); LOG.debug("Copied index {}", manifestDigest); } else { @@ -152,8 +159,6 @@ else if (source.isIndexMediaType(contentType)) { TargetRefType extends Ref<@NonNull TargetRefType>> void copyConfig( Manifest manifest, - String resolvedSourceRegistry, - String effectiveTargetRegistry, OCI source, SourceRefType sourceRef, OCI target, @@ -164,11 +169,9 @@ void copyConfig( Objects.requireNonNull(config.getDigest(), "Config digest is required for streaming copy"); Objects.requireNonNull(config.getSize(), "Config size is required for streaming copy"); target.pushBlob( - targetRef - .forTarget(effectiveTargetRegistry) - .withDigest(manifest.getConfig().getDigest()), + targetRef.forTarget(target).withDigest(manifest.getConfig().getDigest()), config.getSize(), - () -> source.pullConfig(sourceRef.forTarget(resolvedSourceRegistry), manifest.getConfig()), + () -> source.pullConfig(sourceRef, manifest.getConfig()), config.getAnnotations()); LOG.debug("Copied config {}", manifest.getConfig().getDigest()); } diff --git a/src/main/java/land/oras/LayoutRef.java b/src/main/java/land/oras/LayoutRef.java index b0c991d8..8598ea8d 100644 --- a/src/main/java/land/oras/LayoutRef.java +++ b/src/main/java/land/oras/LayoutRef.java @@ -159,6 +159,11 @@ public LayoutRef forTarget(String target) { return new LayoutRef(Path.of(target), tag); } + @Override + public LayoutRef forTarget(OCI target) { + return forTarget(((OCILayout) target).getPath().toString()); + } + @Override public String getTarget(OCI target) { return folder.toString(); diff --git a/src/main/java/land/oras/Ref.java b/src/main/java/land/oras/Ref.java index 3dbada76..19755084 100644 --- a/src/main/java/land/oras/Ref.java +++ b/src/main/java/land/oras/Ref.java @@ -78,6 +78,13 @@ protected Ref(@Nullable String tag) { */ public abstract T forTarget(String target); + /** + * Return a container ref for the target repository + * @param target The target repository + * @return The container ref + */ + public abstract T forTarget(OCI target); + /** * Get the target repository for the ref * @param target The target repository diff --git a/src/test/java/land/oras/RegistryTest.java b/src/test/java/land/oras/RegistryTest.java index 32361fac..9da56fc6 100644 --- a/src/test/java/land/oras/RegistryTest.java +++ b/src/test/java/land/oras/RegistryTest.java @@ -40,7 +40,6 @@ import land.oras.utils.ZotUnsecureContainer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.parallel.Execution; @@ -947,7 +946,6 @@ void testShouldArtifactWithAlias(@TempDir Path homeDir) throws Exception { @Test @Execution(ExecutionMode.SAME_THREAD) - @Disabled("#") void testShouldCopyFromAliasToAlias(@TempDir Path homeDir) throws Exception { try (RegistryContainer otherRegistryContainer = new RegistryContainer()) {