From 3abf5712c788c73549e7c3fc09af8354410c961a Mon Sep 17 00:00:00 2001 From: Valentin Delaye Date: Wed, 12 Mar 2025 11:07:11 +0100 Subject: [PATCH] Push up size, digest and artifact type on descriptor Signed-off-by: Valentin Delaye --- src/main/java/land/oras/Config.java | 26 ++----------- src/main/java/land/oras/Descriptor.java | 37 ++++++++++++++++++- src/main/java/land/oras/Index.java | 12 +----- src/main/java/land/oras/Layer.java | 34 +---------------- src/main/java/land/oras/Manifest.java | 14 +++---- src/test/java/land/oras/ConfigTest.java | 19 +++++++++- src/test/java/land/oras/IndexTest.java | 17 +++++++++ .../land/oras/ManifestDescriptorTest.java | 3 ++ src/test/java/land/oras/OCILayoutTest.java | 5 +++ 9 files changed, 93 insertions(+), 74 deletions(-) diff --git a/src/main/java/land/oras/Config.java b/src/main/java/land/oras/Config.java index b6d25be3..08cbde70 100644 --- a/src/main/java/land/oras/Config.java +++ b/src/main/java/land/oras/Config.java @@ -34,9 +34,6 @@ @NullUnmarked public final class Config extends Descriptor { - private final String digest; - private final long size; - /** * The base 64 encoded data */ @@ -50,10 +47,11 @@ public final class Config extends Descriptor { */ private Config(String mediaType, String digest, long size, @Nullable String data, Annotations annotations) { super( + digest, + size, mediaType, - !annotations.configAnnotations().isEmpty() ? Map.copyOf(annotations.configAnnotations()) : null); - this.digest = digest; - this.size = size; + !annotations.configAnnotations().isEmpty() ? Map.copyOf(annotations.configAnnotations()) : null, + null); this.data = data; } @@ -66,22 +64,6 @@ private Config(String mediaType, String digest, long size, @Nullable String data return annotations; } - /** - * Get the digest - * @return The digest - */ - public String getDigest() { - return digest; - } - - /** - * Get the size - * @return The size - */ - public long getSize() { - return size; - } - /** * Create a new config with annotations * @param annotations The annotations diff --git a/src/main/java/land/oras/Descriptor.java b/src/main/java/land/oras/Descriptor.java index cb7e44b2..e1979ad1 100644 --- a/src/main/java/land/oras/Descriptor.java +++ b/src/main/java/land/oras/Descriptor.java @@ -40,9 +40,17 @@ public abstract sealed class Descriptor permits Config, Manifest, Layer, Index { */ protected final @Nullable Map annotations; - protected Descriptor(String mediaType, Map annotations) { + protected final @Nullable String digest; + protected final @Nullable Long size; + protected final @Nullable String artifactType; + + protected Descriptor( + String digest, Long size, String mediaType, Map annotations, String artifactType) { + this.digest = digest; + this.size = size; this.mediaType = mediaType; this.annotations = annotations; + this.artifactType = artifactType; } /** @@ -64,6 +72,33 @@ public final String getMediaType() { return mediaType; } + /** + * Get the digest + * @return The digest + */ + public @Nullable String getDigest() { + return digest; + } + + /** + * Get the size + * @return The size + */ + public @Nullable Long getSize() { + return size; + } + + /** + * Get the artifact type + * @return The artifact type + */ + public @Nullable ArtifactType getArtifactType() { + if (artifactType != null) { + return ArtifactType.from(artifactType); + } + return null; + } + /** * Return the JSON representation of this descriptor * @return The JSON string diff --git a/src/main/java/land/oras/Index.java b/src/main/java/land/oras/Index.java index a5a6a5c6..0eda45ca 100644 --- a/src/main/java/land/oras/Index.java +++ b/src/main/java/land/oras/Index.java @@ -34,7 +34,6 @@ public final class Index extends Descriptor { private final int schemaVersion; - private final String artifactType; private final List manifests; /** @@ -54,10 +53,9 @@ private Index( List manifests, ManifestDescriptor descriptor, String json) { - super(mediaType, Map.of()); + super(null, null, mediaType, Map.of(), artifactType); this.schemaVersion = schemaVersion; this.descriptor = descriptor; - this.artifactType = artifactType; this.manifests = manifests; this.json = json; } @@ -70,14 +68,6 @@ public int getSchemaVersion() { return schemaVersion; } - /** - * Get the artifact type - * @return The artifact type - */ - public String getArtifactType() { - return artifactType; - } - /** * Get the list of manifests * @return The list of manifests diff --git a/src/main/java/land/oras/Layer.java b/src/main/java/land/oras/Layer.java index ae45de4c..932589ae 100644 --- a/src/main/java/land/oras/Layer.java +++ b/src/main/java/land/oras/Layer.java @@ -38,16 +38,6 @@ @NullMarked public final class Layer extends Descriptor { - /** - * The digest of the layer - */ - private final String digest; - - /** - * The size of the layer - */ - private final long size; - /** * The base 64 encoded data. Might be null if path is set */ @@ -71,9 +61,7 @@ private Layer( long size, @Nullable String data, @Nullable Map annotations) { - super(mediaType, annotations); - this.digest = digest; - this.size = size; + super(digest, size, mediaType, annotations, null); this.data = data; this.blobPath = null; } @@ -86,29 +74,11 @@ private Layer( * @param blobPath The path to the blob */ private Layer(String mediaType, String digest, long size, Path blobPath, Map annotations) { - super(mediaType, annotations); - this.digest = digest; - this.size = size; + super(digest, size, mediaType, annotations, null); this.data = null; this.blobPath = blobPath; } - /** - * Get the digest - * @return The digest - */ - public String getDigest() { - return digest; - } - - /** - * Get the size - * @return The size - */ - public long getSize() { - return size; - } - /** * Get the data * @return The data diff --git a/src/main/java/land/oras/Manifest.java b/src/main/java/land/oras/Manifest.java index 5d4eb306..f647c912 100644 --- a/src/main/java/land/oras/Manifest.java +++ b/src/main/java/land/oras/Manifest.java @@ -37,7 +37,6 @@ public final class Manifest extends Descriptor { private final int schemaVersion; - private final String artifactType; private final Config config; private final Subject subject; private final List layers; @@ -62,9 +61,13 @@ private Manifest( List layers, Annotations annotations, String json) { - super(mediaType, Map.copyOf(annotations.manifestAnnotations())); + super( + null, + null, + mediaType, + Map.copyOf(annotations.manifestAnnotations()), + artifactType != null ? artifactType.getMediaType() : null); this.schemaVersion = schemaVersion; - this.artifactType = artifactType != null ? artifactType.getMediaType() : null; this.descriptor = descriptor; this.config = config; this.subject = subject; @@ -80,10 +83,7 @@ public int getSchemaVersion() { return schemaVersion; } - /** - * Get the artifact type - * @return The artifact type - */ + @Override public @NonNull ArtifactType getArtifactType() { if (artifactType != null) { return ArtifactType.from(artifactType); diff --git a/src/test/java/land/oras/ConfigTest.java b/src/test/java/land/oras/ConfigTest.java index 3d40535d..b5d374ba 100644 --- a/src/test/java/land/oras/ConfigTest.java +++ b/src/test/java/land/oras/ConfigTest.java @@ -21,8 +21,10 @@ package land.oras; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import java.util.Map; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; @@ -34,7 +36,7 @@ public class ConfigTest { void shouldSerializeEmptyConfig() { Config config = Config.empty(); assertEquals( - "{\"digest\":\"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a\",\"size\":2,\"data\":\"e30=\",\"mediaType\":\"application/vnd.oci.empty.v1+json\"}", + "{\"data\":\"e30=\",\"mediaType\":\"application/vnd.oci.empty.v1+json\",\"digest\":\"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a\",\"size\":2}", config.toJson()); } @@ -58,4 +60,19 @@ void shouldDeserializeConfigWithAnnotations() { assertEquals(1, config.getAnnotations().size()); assertEquals("value", config.getAnnotations().get("key")); } + + @Test + void shouldSaveNullForEmptyAnnotations() { + Config config = Config.empty(); + config = config.withAnnotations(Annotations.ofConfig(Map.of())); + assertNull(config.getAnnotations(), "Annotations should be null"); + } + + @Test + void shouldSaveNonEmptyAnnotations() { + Config config = Config.empty(); + config = config.withAnnotations(Annotations.ofConfig(Map.of("foo", "bar"))); + assertNotNull(config.getAnnotations(), "Annotations should be null"); + assertEquals("bar", config.getAnnotations().get("foo")); + } } diff --git a/src/test/java/land/oras/IndexTest.java b/src/test/java/land/oras/IndexTest.java index 161f6617..9a17e221 100644 --- a/src/test/java/land/oras/IndexTest.java +++ b/src/test/java/land/oras/IndexTest.java @@ -52,6 +52,23 @@ void shouldReadAndWriteIndex() { index.toJson(); } + @Test + void shouldReadAndWriteIndexWithArtifactType() { + String json = + "{\"schemaVersion\":2,\"manifests\":[{\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"digest\":\"sha256:f381775b1f558b02165b5dfe1b2f973387d995e18302c4039daabd32f938cb27\",\"size\":559}],\"artifactType\":\"foo/bar\"}"; + Index index = Index.fromJson(json); + assertNull(index.getMediaType()); + assertEquals(2, index.getSchemaVersion()); + assertEquals(1, index.getManifests().size()); + assertEquals("foo/bar", index.getArtifactType().getMediaType()); + assertNull(index.getDescriptor()); + assertEquals( + "sha256:f381775b1f558b02165b5dfe1b2f973387d995e18302c4039daabd32f938cb27", + index.getManifests().get(0).getDigest()); + assertEquals(559, index.getManifests().get(0).getSize()); + assertEquals(json, index.toJson()); + } + @Test void shouldAddManifest() { Index index = Index.fromManifests(List.of()); diff --git a/src/test/java/land/oras/ManifestDescriptorTest.java b/src/test/java/land/oras/ManifestDescriptorTest.java index 0718b126..b36df3af 100644 --- a/src/test/java/land/oras/ManifestDescriptorTest.java +++ b/src/test/java/land/oras/ManifestDescriptorTest.java @@ -25,7 +25,10 @@ import java.util.Map; import land.oras.utils.Const; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +@Execution(ExecutionMode.CONCURRENT) public class ManifestDescriptorTest { @Test diff --git a/src/test/java/land/oras/OCILayoutTest.java b/src/test/java/land/oras/OCILayoutTest.java index 6f8a8ab1..5207ec29 100644 --- a/src/test/java/land/oras/OCILayoutTest.java +++ b/src/test/java/land/oras/OCILayoutTest.java @@ -37,6 +37,8 @@ import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -44,6 +46,8 @@ @Execution(ExecutionMode.CONCURRENT) public class OCILayoutTest { + private static final Logger LOG = LoggerFactory.getLogger(OCILayoutTest.class); + @TempDir private Path extractDir; @@ -666,6 +670,7 @@ private void assertOciLayout(Path layoutPath) { private void assertIndex(Path ociLayoutPath, Manifest manifest) { assertTrue(Files.exists(ociLayoutPath.resolve(Const.OCI_LAYOUT_INDEX))); Index index = JsonUtils.fromJson(ociLayoutPath.resolve(Const.OCI_LAYOUT_INDEX), Index.class); + LOG.debug("Index is {}", index.toJson()); assertEquals(2, index.getSchemaVersion()); assertEquals(1, index.getManifests().size()); assertEquals(Const.DEFAULT_INDEX_MEDIA_TYPE, index.getMediaType());