Skip to content

Commit

Permalink
generic implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Xiaoxuan Wang <[email protected]>
  • Loading branch information
wangxiaoxuan273 committed Dec 20, 2023
1 parent 18435a4 commit 73a18b1
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 80 deletions.
78 changes: 0 additions & 78 deletions content/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (
"oras.land/oras-go/v2/internal/descriptor"
"oras.land/oras-go/v2/internal/graph"
"oras.land/oras-go/v2/internal/resolver"
"oras.land/oras-go/v2/internal/spec"
)

// Store implements `oras.Target`, and represents a content store
Expand Down Expand Up @@ -376,83 +375,6 @@ func (s *Store) writeIndexFile() error {
return os.WriteFile(s.indexPath, indexJSON, 0666)
}

// Referrers lists the descriptors of image or artifact manifests directly
// referencing the given manifest descriptor.
//
// fn is called on the referrer results. If artifactType is not empty, only
// referrers of the same artifact type are fed to fn.
//
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
func (s *Store) Referrers(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error {
s.sync.RLock()
defer s.sync.RUnlock()

if !descriptor.IsManifest(desc) {
return fmt.Errorf("the descriptor %v is not a manifest", desc)
}
var results []ocispec.Descriptor
predecessors, err := s.Predecessors(ctx, desc)
if err != nil {
return err
}
for _, node := range predecessors {
switch node.MediaType {
case ocispec.MediaTypeImageManifest:
fetched, err := content.FetchAll(ctx, s, node)
if err != nil {
return err
}
var manifest ocispec.Manifest
if err := json.Unmarshal(fetched, &manifest); err != nil {
return err
}
if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) {
continue
}
if manifest.ArtifactType != "" {
node.ArtifactType = manifest.ArtifactType
} else {
node.ArtifactType = manifest.Config.MediaType
}
node.Annotations = manifest.Annotations
case ocispec.MediaTypeImageIndex:
fetched, err := content.FetchAll(ctx, s, node)
if err != nil {
return err
}
var index ocispec.Index
if err := json.Unmarshal(fetched, &index); err != nil {
return err
}
if index.Subject == nil || !content.Equal(*index.Subject, desc) {
continue
}
node.ArtifactType = index.ArtifactType
node.Annotations = index.Annotations
case spec.MediaTypeArtifactManifest:
fetched, err := content.FetchAll(ctx, s, node)
if err != nil {
return err
}
var artifact spec.Artifact
if err := json.Unmarshal(fetched, &artifact); err != nil {
return err
}
if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) {
continue
}
node.ArtifactType = artifact.ArtifactType
node.Annotations = artifact.Annotations
default:
continue
}
if artifactType == "" || artifactType == node.ArtifactType {
results = append(results, node)
}
}
return fn(results)
}

// validateReference validates ref.
func validateReference(ref string) error {
if ref == "" {
Expand Down
4 changes: 2 additions & 2 deletions content/oci/oci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2364,7 +2364,7 @@ func TestStore_Referrers(t *testing.T) {
for i := 4; i < len(wantedReferrers); i++ {
want := wantedReferrers[i]
var results []ocispec.Descriptor
err := s.Referrers(ctx, descs[i], "", func(referrers []ocispec.Descriptor) error {
err := registry.Referrers(ctx, s, descs[i], "", func(referrers []ocispec.Descriptor) error {
results = append(results, referrers...)
return nil
})
Expand All @@ -2391,7 +2391,7 @@ func TestStore_Referrers(t *testing.T) {
for i := 4; i < len(wantedReferrers); i++ {
want := wantedReferrers[i]
var results []ocispec.Descriptor
err := s.Referrers(ctx, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error {
err := registry.Referrers(ctx, s, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error {
results = append(results, referrers...)
return nil
})
Expand Down
82 changes: 82 additions & 0 deletions registry/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ package registry

import (
"context"
"encoding/json"
"fmt"
"io"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2/content"
"oras.land/oras-go/v2/internal/descriptor"
"oras.land/oras-go/v2/internal/spec"
)

// Repository is an ORAS target and an union of the blob and the manifest CASs.
Expand Down Expand Up @@ -134,3 +138,81 @@ func Tags(ctx context.Context, repo TagLister) ([]string, error) {
}
return res, nil
}

// Referrers lists the descriptors of image or artifact manifests directly
// referencing the given manifest descriptor.
//
// fn is called on the referrer results. If artifactType is not empty, only
// referrers of the same artifact type are fed to fn.
//
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error {
if !descriptor.IsManifest(desc) {
return fmt.Errorf("the descriptor %v is not a manifest", desc)
}
// use the Referrer API if it is available
if rf, ok := store.(ReferrerLister); ok {
return rf.Referrers(ctx, desc, artifactType, fn)
}
var results []ocispec.Descriptor
predecessors, err := store.Predecessors(ctx, desc)
if err != nil {
return err
}
for _, node := range predecessors {
switch node.MediaType {
case ocispec.MediaTypeImageManifest:
fetched, err := content.FetchAll(ctx, store, node)
if err != nil {
return err
}
var manifest ocispec.Manifest
if err := json.Unmarshal(fetched, &manifest); err != nil {
return err
}
if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) {
continue
}
if manifest.ArtifactType != "" {
node.ArtifactType = manifest.ArtifactType
} else {
node.ArtifactType = manifest.Config.MediaType
}
node.Annotations = manifest.Annotations
case ocispec.MediaTypeImageIndex:
fetched, err := content.FetchAll(ctx, store, node)
if err != nil {
return err
}
var index ocispec.Index
if err := json.Unmarshal(fetched, &index); err != nil {
return err
}
if index.Subject == nil || !content.Equal(*index.Subject, desc) {
continue
}
node.ArtifactType = index.ArtifactType
node.Annotations = index.Annotations
case spec.MediaTypeArtifactManifest:
fetched, err := content.FetchAll(ctx, store, node)
if err != nil {
return err
}
var artifact spec.Artifact
if err := json.Unmarshal(fetched, &artifact); err != nil {
return err
}
if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) {
continue
}
node.ArtifactType = artifact.ArtifactType
node.Annotations = artifact.Annotations
default:
continue
}
if artifactType == "" || artifactType == node.ArtifactType {
results = append(results, node)
}
}
return fn(results)
}

0 comments on commit 73a18b1

Please sign in to comment.