Skip to content

Commit b3d301b

Browse files
authored
Merge pull request #91 from dtrudg/issue-85
feat: ReplaceImage / ReplaceIndex
2 parents a8566db + 8f4142f commit b3d301b

8 files changed

+145
-5
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

pkg/sif/update.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -408,17 +408,27 @@ func (f *OCIFileImage) append(add mutate.Appendable, opts ...AppendOpt) error {
408408
return err
409409
}
410410

411+
ri, err = appendToIndex(ri, add, ao)
412+
if err != nil {
413+
return err
414+
}
415+
416+
return f.UpdateRootIndex(ri, OptUpdateTempDir(ao.tempDir))
417+
}
418+
419+
func appendToIndex(base v1.ImageIndex, add mutate.Appendable, ao appendOpts) (v1.ImageIndex, error) {
411420
ia := mutate.IndexAddendum{Add: add}
412421

422+
var err error
413423
if ao.ref != nil {
414-
ri, err = removeRefAnnotation(ri, ao.ref)
424+
base, err = removeRefAnnotation(base, ao.ref)
415425
if err != nil {
416-
return err
426+
return nil, err
417427
}
418428

419429
d, err := partial.Descriptor(add)
420430
if err != nil {
421-
return err
431+
return nil, err
422432
}
423433
if d.Annotations != nil {
424434
ia.Annotations = maps.Clone(d.Annotations)
@@ -427,9 +437,8 @@ func (f *OCIFileImage) append(add mutate.Appendable, opts ...AppendOpt) error {
427437
}
428438
ia.Annotations[imagespec.AnnotationRefName] = ao.ref.Name()
429439
}
430-
ri = mutate.AppendManifests(ri, ia)
431440

432-
return f.UpdateRootIndex(ri, OptUpdateTempDir(ao.tempDir))
441+
return mutate.AppendManifests(base, ia), nil
433442
}
434443

435444
// removeRefAnnotation removes an existing "org.opencontainers.image.ref.name"
@@ -462,3 +471,42 @@ func (f *OCIFileImage) RemoveManifests(matcher match.Matcher) error {
462471
}
463472
return f.UpdateRootIndex(mutate.RemoveManifests(ri, matcher))
464473
}
474+
475+
// ReplaceImage writes img to the SIF, replacing any existing manifest that is
476+
// selected by the matcher. Any blobs in the SIF that are no longer referenced
477+
// are removed from the SIF.
478+
func (f *OCIFileImage) ReplaceImage(img v1.Image, matcher match.Matcher, opts ...AppendOpt) error {
479+
return f.replace(img, matcher, opts...)
480+
}
481+
482+
// ReplaceIndex writes ii to the SIF, replacing any existing manifest that is
483+
// selected by the matcher. Any blobs in the SIF that are no longer referenced
484+
// are removed from the SIF.
485+
func (f *OCIFileImage) ReplaceIndex(ii v1.ImageIndex, matcher match.Matcher, opts ...AppendOpt) error {
486+
return f.replace(ii, matcher, opts...)
487+
}
488+
489+
func (f *OCIFileImage) replace(add mutate.Appendable, matcher match.Matcher, opts ...AppendOpt) error {
490+
ao := appendOpts{
491+
tempDir: os.TempDir(),
492+
}
493+
for _, opt := range opts {
494+
if err := opt(&ao); err != nil {
495+
return err
496+
}
497+
}
498+
499+
ri, err := f.RootIndex()
500+
if err != nil {
501+
return err
502+
}
503+
504+
ri = mutate.RemoveManifests(ri, matcher)
505+
506+
ri, err = appendToIndex(ri, add, ao)
507+
if err != nil {
508+
return err
509+
}
510+
511+
return f.UpdateRootIndex(ri, OptUpdateTempDir(ao.tempDir))
512+
}

pkg/sif/update_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,95 @@ func TestRemoveManifests(t *testing.T) {
439439
})
440440
}
441441
}
442+
443+
//nolint:dupl
444+
func TestReplace(t *testing.T) {
445+
r := rand.NewSource(randomSeed)
446+
newImage, err := random.Image(64, 1, random.WithSource(r))
447+
if err != nil {
448+
t.Fatal(err)
449+
}
450+
newIndex, err := random.Index(64, 1, 1, random.WithSource(r))
451+
if err != nil {
452+
t.Fatal(err)
453+
}
454+
455+
replaceImage := func(ofi *sif.OCIFileImage, m match.Matcher) error { return ofi.ReplaceImage(newImage, m) }
456+
replaceIndex := func(ofi *sif.OCIFileImage, m match.Matcher) error { return ofi.ReplaceIndex(newIndex, m) }
457+
tests := []struct {
458+
name string
459+
base string
460+
replacement func(ofi *sif.OCIFileImage, m match.Matcher) error
461+
matcher match.Matcher
462+
}{
463+
{
464+
name: "ReplaceImageManifest",
465+
base: "hello-world-docker-v2-manifest",
466+
replacement: replaceImage,
467+
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "arm64", Variant: "v8"}),
468+
},
469+
{
470+
name: "ReplaceImageManifestList",
471+
base: "hello-world-docker-v2-manifest-list",
472+
replacement: replaceImage,
473+
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "arm64", Variant: "v8"}),
474+
},
475+
{
476+
name: "ReplaceImageNoMatch",
477+
base: "hello-world-docker-v2-manifest",
478+
replacement: replaceImage,
479+
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "m68k"}),
480+
},
481+
{
482+
name: "ReplaceIndexManifest",
483+
base: "hello-world-docker-v2-manifest",
484+
replacement: replaceIndex,
485+
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "arm64", Variant: "v8"}),
486+
},
487+
{
488+
name: "ReplaceIndexManifestList",
489+
base: "hello-world-docker-v2-manifest-list",
490+
replacement: replaceIndex,
491+
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "arm64", Variant: "v8"}),
492+
},
493+
{
494+
name: "ReplaceIndexNoMatch",
495+
base: "hello-world-docker-v2-manifest",
496+
replacement: replaceIndex,
497+
matcher: match.Platforms(v1.Platform{OS: "linux", Architecture: "m68k"}),
498+
},
499+
}
500+
for _, tt := range tests {
501+
t.Run(tt.name, func(t *testing.T) {
502+
sifPath := corpus.SIF(t, tt.base, sif.OptWriteWithSpareDescriptorCapacity(8))
503+
fi, err := ssif.LoadContainerFromPath(sifPath)
504+
if err != nil {
505+
t.Fatal(err)
506+
}
507+
508+
ofi, err := sif.FromFileImage(fi)
509+
if err != nil {
510+
t.Fatal(err)
511+
}
512+
513+
if err := tt.replacement(ofi, tt.matcher); err != nil {
514+
t.Fatal(err)
515+
}
516+
517+
if err := fi.UnloadContainer(); err != nil {
518+
t.Fatal(err)
519+
}
520+
521+
b, err := os.ReadFile(sifPath)
522+
if err != nil {
523+
t.Fatal(err)
524+
}
525+
526+
g := goldie.New(t,
527+
goldie.WithTestNameForDir(true),
528+
)
529+
530+
g.Assert(t, tt.name, b)
531+
})
532+
}
533+
}

0 commit comments

Comments
 (0)