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: 6 additions & 0 deletions src/main/java/land/oras/Describable.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ public interface Describable {
* @return The manifest descriptor
*/
ManifestDescriptor getDescriptor();

/**
* Get the subject
* @return The subject
*/
Subject getSubject();
}
5 changes: 1 addition & 4 deletions src/main/java/land/oras/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,7 @@ protected Index withJson(String json) {
return this;
}

/**
* Get the subject
* @return The subject
*/
@Override
public Subject getSubject() {
return subject;
}
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/land/oras/Manifest.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,7 @@ public Config getConfig() {
return config;
}

/**
* Get the subject
* @return The subject
*/
@Override
public Subject getSubject() {
return subject;
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/land/oras/OCI.java
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,14 @@ public abstract Manifest pushArtifact(
*/
public abstract Layer pushBlob(T ref, byte[] data);

/**
* Get the referrers of a container
* @param ref The ref
* @param artifactType The optional artifact type
* @return The referrers
*/
public abstract Referrers getReferrers(T ref, @Nullable ArtifactType artifactType);

/**
* Attach file to an existing manifest
* @param ref The ref
Expand Down
32 changes: 26 additions & 6 deletions src/main/java/land/oras/OCILayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import land.oras.exception.OrasException;
Expand Down Expand Up @@ -283,6 +284,31 @@
}
}

@Override
public Referrers getReferrers(LayoutRef ref, @Nullable ArtifactType artifactType) {
Index index = Index.fromPath(getIndexPath());
ManifestDescriptor currentDescriptor = findManifestDescriptor(ref);
String currentDescriptorDigest = currentDescriptor.getDigest();
LOG.info("Looking for referrers of manifest: {}", currentDescriptorDigest);
List<ManifestDescriptor> manifestDescriptors = new LinkedList<>();
for (ManifestDescriptor manifestDescriptor : index.getManifests()) {
String digest = manifestDescriptor.getDigest();
Descriptor descriptor = probeDescriptor(ref.withDigest(digest));
Describable describable = isIndexMediaType(descriptor.getMediaType())
? getIndex(ref.withDigest(digest))

Check warning on line 298 in src/main/java/land/oras/OCILayout.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/land/oras/OCILayout.java#L298

Added line #L298 was not covered by tests
: getManifest(ref.withDigest(digest));
if (describable.getSubject() != null) {
Subject subject = describable.getSubject();
String subjectDigest = subject.getDigest();
if (subjectDigest.equals(currentDescriptorDigest)) {
LOG.info("Subject with digest {} found for manifest: {}", subjectDigest, digest);
manifestDescriptors.add(manifestDescriptor);
}
}
}
return Referrers.from(manifestDescriptors);
}

private void setPath(Path path) {
this.path = path;
}
Expand Down Expand Up @@ -505,12 +531,6 @@
return getBlobPath().resolve(algorithm.getPrefix()).resolve(SupportedAlgorithm.getDigest(digest));
}

private Path getBlobPath(Config config) {
String digest = config.getDigest();
SupportedAlgorithm algorithm = SupportedAlgorithm.fromDigest(digest);
return getBlobPath().resolve(algorithm.getPrefix()).resolve(SupportedAlgorithm.getDigest(digest));
}

private Path getBlobPath(Layer layer) {
String digest = layer.getDigest();
SupportedAlgorithm algorithm = SupportedAlgorithm.fromDigest(digest);
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/land/oras/Referrers.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package land.oras;

import java.util.List;
import land.oras.utils.Const;
import land.oras.utils.JsonUtils;

/**
Expand All @@ -34,7 +35,10 @@ public class Referrers {
/**
* Private constructor
*/
private Referrers() {}
private Referrers(List<ManifestDescriptor> manifests) {
this.mediaType = Const.DEFAULT_INDEX_MEDIA_TYPE;
this.manifests = manifests;
}

/**
* Get the media type
Expand Down Expand Up @@ -68,4 +72,13 @@ public String toJson() {
public static Referrers fromJson(String json) {
return JsonUtils.fromJson(json, Referrers.class);
}

/**
* Create a referrers object from a list of descriptors
* @param descriptors The list of descriptors
* @return The referrers object
*/
public static Referrers from(List<ManifestDescriptor> descriptors) {
return new Referrers(descriptors);
}
}
7 changes: 1 addition & 6 deletions src/main/java/land/oras/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,7 @@ public List<String> getTags(ContainerRef containerRef) {
return JsonUtils.fromJson(response.response(), Tags.class).tags();
}

/**
* Get the referrers of a container
* @param containerRef The container
* @param artifactType The optional artifact type
* @return The referrers
*/
@Override
public Referrers getReferrers(ContainerRef containerRef, @Nullable ArtifactType artifactType) {
if (containerRef.getDigest() == null) {
throw new OrasException("Digest is required to get referrers");
Expand Down
24 changes: 24 additions & 0 deletions src/test/java/land/oras/OCILayoutTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,30 @@ void shouldPullViaTagFromOciLayout() throws IOException {
Files.readString(extractDir1.resolve("manifest.json")));
}

@Test
void shouldGetReferrers() throws IOException {

Path extractDir1 = extractDir.resolve("shouldGetReferrers");
Files.createDirectory(extractDir1);

LayoutRef layoutRef = LayoutRef.parse("src/test/resources/oci/subject:latest");
OCILayout ociLayout =
OCILayout.Builder.builder().defaults(layoutRef.getFolder()).build();

Referrers referrers = ociLayout.getReferrers(layoutRef, null);
assertEquals(1, referrers.getManifests().size());

ManifestDescriptor manifestDescriptor = referrers.getManifests().get(0);
assertEquals(
"sha256:ccec2a2be7ce7c6aadc8ed0dc03df8f91cbd3534272dd1f8284226a8d3516dd6",
manifestDescriptor.getDigest());
assertEquals(746, manifestDescriptor.getSize());
assertEquals("application/vnd.oci.image.manifest.v1+json", manifestDescriptor.getMediaType());
assertNotNull(manifestDescriptor.getAnnotations());
assertEquals(1, manifestDescriptor.getAnnotations().size());
assertEquals("2025-04-07T14:54:25Z", manifestDescriptor.getAnnotations().get(Const.ANNOTATION_CREATED));
}

@Test
void shouldPullIndex() throws IOException {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.text.file.v1+json","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2,"data":"e30="},"layers":[{"mediaType":"plain/text","digest":"sha256:98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4","size":3,"annotations":{"org.opencontainers.image.title":"hi.txt"}}],"annotations":{"org.opencontainers.image.created":"2025-04-07T14:54:19Z"}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.text.file.v1+json","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2,"data":"e30="},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar","digest":"sha256:e094bc809626f0a401a40d75c56df478e546902ff812772c4594265203b23980","size":4,"annotations":{"org.opencontainers.image.title":"hi2.txt"}}],"subject":{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:bb329f103a5fd68e96771f7dcfaa7722e9ec727bb9ab83c2beee96d6f25b08d6","size":554},"annotations":{"org.opencontainers.image.created":"2025-04-07T14:54:25Z"}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hi2
1 change: 1 addition & 0 deletions src/test/resources/oci/subject/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:bb329f103a5fd68e96771f7dcfaa7722e9ec727bb9ab83c2beee96d6f25b08d6","size":554,"annotations":{"org.opencontainers.image.ref.name":"latest"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:ccec2a2be7ce7c6aadc8ed0dc03df8f91cbd3534272dd1f8284226a8d3516dd6","size":746,"annotations":{"org.opencontainers.image.created":"2025-04-07T14:54:25Z"},"artifactType":"application/vnd.text.file.v1+json"}]}
1 change: 1 addition & 0 deletions src/test/resources/oci/subject/oci-layout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"imageLayoutVersion":"1.0.0"}