Skip to content

Commit

Permalink
generic implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Xiaoxuan Wang <wangxiaoxuan119@gmail.com>
  • Loading branch information
wangxiaoxuan273 committed Dec 20, 2023
1 parent 18435a4 commit efd9a57
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 87 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
11 changes: 2 additions & 9 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 All @@ -2404,13 +2404,6 @@ func TestStore_Referrers(t *testing.T) {
}
}

func TestStore_ReferrersInterface(t *testing.T) {
var store interface{} = &Store{}
if _, ok := store.(registry.ReferrerLister); !ok {
t.Error("&Store{} does not conform to registry.ReferrerLister")
}
}

func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool {
if len(actual) != len(expected) {
return false
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 efd9a57

Please sign in to comment.