Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add nil checks for some functions #327

Merged
merged 11 commits into from
Sep 22, 2022
3 changes: 3 additions & 0 deletions copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type CopyOptions struct {
// matching manifest if exists, otherwise ErrNotFound will be returned.
// - Otherwise ErrUnsupported will be returned.
func (opts *CopyOptions) WithTargetPlatform(p *ocispec.Platform) {
if p == nil {
return
}
mapRoot := opts.MapRoot
opts.MapRoot = func(ctx context.Context, src content.ReadOnlyStorage, root ocispec.Descriptor) (desc ocispec.Descriptor, err error) {
if mapRoot != nil {
Expand Down
8 changes: 8 additions & 0 deletions copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,14 @@ func TestCopy_WithTargetPlatformOptions(t *testing.T) {
if err.Error() != expected {
t.Fatalf("Copy() error = %v, wantErr %v", err, expected)
}

// test copy with no platform filter
// opts.MapRoot should be nil
opts = oras.CopyOptions{}
opts.WithTargetPlatform(nil)
if opts.MapRoot != nil {
t.Fatal("opts.MapRoot not equal to nil when platform is not provided")
}
}

func TestCopy_RestoreDuplicates(t *testing.T) {
Expand Down
8 changes: 7 additions & 1 deletion extendedcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ func findRoots(ctx context.Context, storage content.ReadOnlyGraphStorage, node o
// when using both FilterArtifactType and FilterAnnotation, it's recommended to call
// FilterArtifactType first.
func (opts *ExtendedCopyGraphOptions) FilterAnnotation(key string, regex *regexp.Regexp) {
if key == "" {
return
}
fp := opts.FindPredecessors
opts.FindPredecessors = func(ctx context.Context, src content.ReadOnlyGraphStorage, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
var predecessors []ocispec.Descriptor
Expand Down Expand Up @@ -223,7 +226,7 @@ func (opts *ExtendedCopyGraphOptions) FilterAnnotation(key string, regex *regexp
}
}
}
if regex.MatchString(p.Annotations[key]) {
if regex == nil || regex.MatchString(p.Annotations[key]) {
filtered = append(filtered, p)
}
}
Expand All @@ -236,6 +239,9 @@ func (opts *ExtendedCopyGraphOptions) FilterAnnotation(key string, regex *regexp
// when using both FilterArtifactType and FilterAnnotation, it's recommended to call
// FilterArtifactType first.
func (opts *ExtendedCopyGraphOptions) FilterArtifactType(regex *regexp.Regexp) {
if regex == nil {
return
}
fp := opts.FindPredecessors
opts.FindPredecessors = func(ctx context.Context, src content.ReadOnlyGraphStorage, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
var predecessors []ocispec.Descriptor
Expand Down
162 changes: 162 additions & 0 deletions extendedcopy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,120 @@ func TestExtendedCopyGraph_FilterAnnotationWithRegex(t *testing.T) {
verifyCopy(dst, copiedIndice, uncopiedIndice)
}

func TestExtendedCopyGraph_FilterAnnotationWithNoKey(t *testing.T) {
// generate test content
var blobs [][]byte
var descs []ocispec.Descriptor
appendBlob := func(mediaType string, blob []byte, key string, value string) {
blobs = append(blobs, blob)
descs = append(descs, ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(blob),
Size: int64(len(blob)),
Annotations: map[string]string{key: value},
})
}
generateArtifactManifest := func(subject ocispec.Descriptor, key string, value string) {
var manifest artifactspec.Manifest
artifactSubject := descriptor.OCIToArtifact(subject)
manifest.Subject = &artifactSubject
manifest.Annotations = map[string]string{key: value}
manifestJSON, err := json.Marshal(manifest)
if err != nil {
t.Fatal(err)
}
appendBlob(artifactspec.MediaTypeArtifactManifest, manifestJSON, key, value)
}
appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"), "bar", "blackpink") // descs[0]
generateArtifactManifest(descs[0], "bar", "bluebrown") // descs[1]
generateArtifactManifest(descs[0], "bar", "blackred") // descs[2]
generateArtifactManifest(descs[0], "bar", "blackviolet") // descs[3]
generateArtifactManifest(descs[0], "bar", "greengrey") // descs[4]
generateArtifactManifest(descs[0], "bar", "brownblack") // descs[5]
ctx := context.Background()
src := memory.New()
for i := range blobs {
err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
if err != nil {
t.Fatalf("failed to push test content to src: %d: %v", i, err)
}
}
opts := oras.ExtendedCopyGraphOptions{}
exp := "black."
regex := regexp.MustCompile(exp)
opts.FilterAnnotation("", regex)
if opts.FindPredecessors != nil {
t.Fatal("FindPredecessors not nil!")
}
}

func TestExtendedCopyGraph_FilterAnnotationWithNoRegex(t *testing.T) {
// generate test content
var blobs [][]byte
var descs []ocispec.Descriptor
appendBlob := func(mediaType string, blob []byte, key string, value string) {
blobs = append(blobs, blob)
descs = append(descs, ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(blob),
Size: int64(len(blob)),
Annotations: map[string]string{key: value},
})
}
generateArtifactManifest := func(subject ocispec.Descriptor, key string, value string) {
var manifest artifactspec.Manifest
artifactSubject := descriptor.OCIToArtifact(subject)
manifest.Subject = &artifactSubject
manifest.Annotations = map[string]string{key: value}
manifestJSON, err := json.Marshal(manifest)
if err != nil {
t.Fatal(err)
}
appendBlob(artifactspec.MediaTypeArtifactManifest, manifestJSON, key, value)
}
appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"), "bar", "blackpink") // descs[0]
generateArtifactManifest(descs[0], "bar", "bluebrown") // descs[1]
generateArtifactManifest(descs[0], "bar", "blackred") // descs[2]
generateArtifactManifest(descs[0], "bar", "blackviolet") // descs[3]
generateArtifactManifest(descs[0], "bar", "greengrey") // descs[4]
generateArtifactManifest(descs[0], "bar", "brownblack") // descs[5]
ctx := context.Background()
verifyCopy := func(dst content.Fetcher, copiedIndice []int, uncopiedIndice []int) {
for _, i := range copiedIndice {
got, err := content.FetchAll(ctx, dst, descs[i])
if err != nil {
t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
continue
}
if want := blobs[i]; !bytes.Equal(got, want) {
t.Errorf("content[%d] = %v, want %v", i, got, want)
}
}
for _, i := range uncopiedIndice {
if _, err := content.FetchAll(ctx, dst, descs[i]); !errors.Is(err, errdef.ErrNotFound) {
t.Errorf("content[%d] error = %v, wantErr %v", i, err, errdef.ErrNotFound)
}
}
}
src := memory.New()
for i := range blobs {
err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
if err != nil {
t.Fatalf("failed to push test content to src: %d: %v", i, err)
}
}
// test extended copy by descs[0] with annotation filter
dst := memory.New()
opts := oras.ExtendedCopyGraphOptions{}
opts.FilterAnnotation("bar", nil)
if err := oras.ExtendedCopyGraph(ctx, src, dst, descs[0], opts); err != nil {
t.Fatalf("ExtendedCopyGraph() error = %v, wantErr %v", err, false)
}
copiedIndice := []int{0, 1, 2, 3, 4, 5}
uncopiedIndice := []int{}
verifyCopy(dst, copiedIndice, uncopiedIndice)
}

func TestExtendedCopyGraph_FilterAnnotationWithMultipleRegex(t *testing.T) {
// generate test content
var blobs [][]byte
Expand Down Expand Up @@ -889,6 +1003,54 @@ func TestExtendedCopyGraph_FilterArtifactTypeWithRegex(t *testing.T) {
verifyCopy(dst, copiedIndice, uncopiedIndice)
}

func TestExtendedCopyGraph_FilterArtifactTypeWithNoRegex(t *testing.T) {
// generate test content
var blobs [][]byte
var descs []ocispec.Descriptor
appendBlob := func(mediaType string, blob []byte) {
blobs = append(blobs, blob)
descs = append(descs, ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(blob),
Size: int64(len(blob)),
})
}
generateArtifactManifest := func(subject ocispec.Descriptor, artifactType string) {
var manifest artifactspec.Manifest
artifactSubject := descriptor.OCIToArtifact(subject)
manifest.Subject = &artifactSubject
manifest.ArtifactType = artifactType
manifestJSON, err := json.Marshal(manifest)
if err != nil {
t.Fatal(err)
}
appendBlob(artifactspec.MediaTypeArtifactManifest, manifestJSON)
}

appendBlob(ocispec.MediaTypeImageConfig, []byte("foo")) // descs[0]
generateArtifactManifest(descs[0], "good-bar-yellow") // descs[1]
generateArtifactManifest(descs[0], "bad-woo-red") // descs[2]
generateArtifactManifest(descs[0], "bad-bar-blue") // descs[3]
generateArtifactManifest(descs[0], "bad-bar-red") // descs[4]
generateArtifactManifest(descs[0], "good-woo-pink") // descs[5]

ctx := context.Background()

src := memory.New()
for i := range blobs {
err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
if err != nil {
t.Errorf("failed to push test content to src: %d: %v", i, err)
}
}

opts := oras.ExtendedCopyGraphOptions{}
opts.FilterArtifactType(nil)
if opts.FindPredecessors != nil {
t.Fatal("FindPredecessors not nil!")
}
}

func TestExtendedCopyGraph_FilterArtifactTypeWithMultipleRegex(t *testing.T) {
// generate test content
var blobs [][]byte
Expand Down