Skip to content

Commit

Permalink
Merge pull request #96 from tri-adam/nil-matcher
Browse files Browse the repository at this point in the history
feat: accept `nil` `match.Matcher`
  • Loading branch information
tri-adam authored Oct 7, 2024
2 parents f29715a + 0a15b88 commit de51f71
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 42 deletions.
19 changes: 9 additions & 10 deletions pkg/sif/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,28 @@ type image struct {
rawManifest []byte
}

var (
ErrNoMatch = errors.New("no match found")
ErrMultipleMatches = errors.New("multiple matches found")
)

// Image returns a single Image stored in f, that is selected by the provided
// Matcher. If more than one image matches, or no image matches, an error is
// returned.
// Image returns a single Image stored in f, that is selected by m. If m is nil, all manifests are
// selected. If more than one image matches, an error wrapping ErrMultipleMatches is returned. If
// no image matches, an error wrapping ErrNoMatch is returned.
func (f *OCIFileImage) Image(m match.Matcher, _ ...Option) (v1.Image, error) {
ri, err := f.RootIndex()
if err != nil {
return nil, err
}

if m == nil {
m = matchAll
}

matches, err := partial.FindImages(ri, m)
if err != nil {
return nil, err
}
if len(matches) > 1 {
return nil, ErrMultipleMatches
return nil, fmt.Errorf("%w", ErrMultipleMatches)
}
if len(matches) == 0 {
return nil, ErrNoMatch
return nil, fmt.Errorf("%w", ErrNoMatch)
}

d, err := matches[0].Digest()
Expand Down
24 changes: 14 additions & 10 deletions pkg/sif/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package sif_test

import (
"errors"
"math/rand"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -80,42 +81,45 @@ func Test_OCIFileImage_Image(t *testing.T) {
name string
matcher match.Matcher
wantImage v1.Image
wantErr bool
wantErr error
}{
{
name: "MatchingRef",
matcher: match.Name(imgRef.Name()),
wantImage: img,
wantErr: false,
wantErr: nil,
},
{
name: "NotImage",
matcher: match.Name(idxRef.Name()),
wantImage: nil,
wantErr: true,
wantErr: sif.ErrNoMatch,
},
{
name: "NonMatchingRef",
matcher: match.Name("not-present:latest"),
wantImage: nil,
wantErr: true,
wantErr: sif.ErrNoMatch,
},
{
name: "MultipleMatches",
matcher: match.MediaTypes(string(types.DockerManifestSchema2)),
wantImage: nil,
wantErr: true,
wantErr: sif.ErrMultipleMatches,
},
{
name: "NilMatcher",
matcher: nil,
wantImage: nil,
wantErr: sif.ErrMultipleMatches,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotImg, err := ofi.Image(tt.matcher)

if err != nil && !tt.wantErr {
t.Errorf("Unexpected error: %v", err)
}
if err == nil && tt.wantErr {
t.Errorf("Error expected, but nil returned.")
if got, want := err, tt.wantErr; !errors.Is(got, want) {
t.Fatalf("got error %v, want %v", got, want)
}

if tt.wantImage == nil {
Expand Down
14 changes: 9 additions & 5 deletions pkg/sif/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,28 @@ func (f *OCIFileImage) RootIndex() (v1.ImageIndex, error) {
}, nil
}

// Index returns a single ImageIndex stored in f, that is selected by the provided
// Matcher. If more than one index matches, or no index matches, an error is
// returned.
// Index returns a single ImageIndex stored in f, that is selected by m. If m is nil, all manifests
// are selected. If more than one index matches, an error wrapping ErrMultipleMatches is returned.
// If no index matches, an error wrapping ErrNoMatch is returned.
func (f *OCIFileImage) Index(m match.Matcher, _ ...Option) (v1.ImageIndex, error) {
ri, err := f.RootIndex()
if err != nil {
return nil, err
}

if m == nil {
m = matchAll
}

matches, err := partial.FindIndexes(ri, m)
if err != nil {
return nil, err
}
if len(matches) > 1 {
return nil, ErrMultipleMatches
return nil, fmt.Errorf("%w", ErrMultipleMatches)
}
if len(matches) == 0 {
return nil, ErrNoMatch
return nil, fmt.Errorf("%w", ErrNoMatch)
}

d, err := matches[0].Digest()
Expand Down
24 changes: 14 additions & 10 deletions pkg/sif/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package sif_test

import (
"errors"
"math/rand"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -137,42 +138,45 @@ func Test_OCIFileImage_Index(t *testing.T) {
name string
matcher match.Matcher
wantIndex v1.ImageIndex
wantErr bool
wantErr error
}{
{
name: "MatchingRef",
matcher: match.Name(idxRef.Name()),
wantIndex: idx,
wantErr: false,
wantErr: nil,
},
{
name: "NotIndex",
matcher: match.Name(imgRef.Name()),
wantIndex: nil,
wantErr: true,
wantErr: sif.ErrNoMatch,
},
{
name: "NonMatchingRef",
matcher: match.Name("not-present:latest"),
wantIndex: nil,
wantErr: true,
wantErr: sif.ErrNoMatch,
},
{
name: "MultipleMatches",
matcher: match.MediaTypes(string(types.OCIImageIndex)),
wantIndex: nil,
wantErr: true,
wantErr: sif.ErrMultipleMatches,
},
{
name: "NilMatcher",
matcher: nil,
wantIndex: nil,
wantErr: sif.ErrMultipleMatches,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotIndex, err := ofi.Index(tt.matcher)

if err != nil && !tt.wantErr {
t.Errorf("Unexpected error: %v", err)
}
if err == nil && tt.wantErr {
t.Errorf("Error expected, but nil returned.")
if got, want := err, tt.wantErr; !errors.Is(got, want) {
t.Fatalf("got error %v, want %v", got, want)
}

if tt.wantIndex == nil {
Expand Down
18 changes: 18 additions & 0 deletions pkg/sif/match.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2024 Sylabs Inc. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0

package sif

import (
"errors"

v1 "github.com/google/go-containerregistry/pkg/v1"
)

var (
ErrNoMatch = errors.New("no match found")
ErrMultipleMatches = errors.New("multiple matches found")
)

func matchAll(v1.Descriptor) bool { return true }
Binary file not shown.
Binary file not shown.
Binary file not shown.
27 changes: 20 additions & 7 deletions pkg/sif/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,31 +461,40 @@ func (f *OCIFileImage) RemoveBlob(hash v1.Hash) error {
sif.OptDeleteCompact(true))
}

// RemoveManifests modifies the SIF file associated with f so that its RootIndex
// no longer holds manifests selected by matcher. Any blobs in the SIF that are
// no longer referenced are removed from the SIF.
// RemoveManifests modifies the SIF file associated with f so that its
// RootIndex no longer holds manifests selected by matcher. If m is nil, all
// manifests are selected. Any blobs in the SIF that are no longer referenced
// are removed from the SIF.
func (f *OCIFileImage) RemoveManifests(matcher match.Matcher) error {
ri, err := f.RootIndex()
if err != nil {
return err
}

if matcher == nil {
matcher = matchAll
}

return f.UpdateRootIndex(mutate.RemoveManifests(ri, matcher))
}

// ReplaceImage writes img to the SIF, replacing any existing manifest that is
// selected by the matcher. Any blobs in the SIF that are no longer referenced
// are removed from the SIF.
// selected by the matcher. If m is nil, all manifests are selected. Any blobs
// in the SIF that are no longer referenced are removed from the SIF.
func (f *OCIFileImage) ReplaceImage(img v1.Image, matcher match.Matcher, opts ...AppendOpt) error {
return f.replace(img, matcher, opts...)
}

// ReplaceIndex writes ii to the SIF, replacing any existing manifest that is
// selected by the matcher. Any blobs in the SIF that are no longer referenced
// are removed from the SIF.
// selected by the matcher. If m is nil, all manifests are selected. Any blobs
// in the SIF that are no longer referenced are removed from the SIF.
func (f *OCIFileImage) ReplaceIndex(ii v1.ImageIndex, matcher match.Matcher, opts ...AppendOpt) error {
return f.replace(ii, matcher, opts...)
}

// replace writes add to the SIF, replacing any existing manifest that is
// selected by the matcher. If m is nil, all manifests are selected. Any blobs
// in the SIF that are no longer referenced are removed from the SIF.
func (f *OCIFileImage) replace(add mutate.Appendable, matcher match.Matcher, opts ...AppendOpt) error {
ao := appendOpts{
tempDir: os.TempDir(),
Expand All @@ -496,6 +505,10 @@ func (f *OCIFileImage) replace(add mutate.Appendable, matcher match.Matcher, opt
}
}

if matcher == nil {
matcher = matchAll
}

ri, err := f.RootIndex()
if err != nil {
return err
Expand Down
17 changes: 17 additions & 0 deletions pkg/sif/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ func TestRemoveManifests(t *testing.T) {
base: "hello-world-docker-v2-manifest-list",
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "m68k"}),
},
{
name: "NilMatcher",
base: "hello-world-docker-v2-manifest-list",
matcher: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -478,6 +483,12 @@ func TestReplace(t *testing.T) {
replacement: replaceImage,
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "m68k"}),
},
{
name: "ReplaceImageNilMatcher",
base: "hello-world-docker-v2-manifest",
replacement: replaceImage,
matcher: nil,
},
{
name: "ReplaceIndexManifest",
base: "hello-world-docker-v2-manifest",
Expand All @@ -496,6 +507,12 @@ func TestReplace(t *testing.T) {
replacement: replaceIndex,
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "m68k"}),
},
{
name: "ReplaceIndexNilMatcher",
base: "hello-world-docker-v2-manifest",
replacement: replaceIndex,
matcher: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down

0 comments on commit de51f71

Please sign in to comment.