diff --git a/pkg/sif/create.go b/pkg/sif/create.go index 8c160fd..d22ae74 100644 --- a/pkg/sif/create.go +++ b/pkg/sif/create.go @@ -12,6 +12,7 @@ package sif import ( + "encoding" "encoding/binary" "errors" "fmt" @@ -680,3 +681,45 @@ func (f *FileImage) SetPrimPart(id uint32, opts ...SetOpt) error { return nil } + +// SetMetadata sets the metadata of the data object with id to md, according to opts. +// +// By default, the image/object modification times are set to the current time for +// non-deterministic images, and unset otherwise. To override this, consider using +// OptSetDeterministic or OptSetWithTime. +func (f *FileImage) SetMetadata(id uint32, md encoding.BinaryMarshaler, opts ...SetOpt) error { + so := setOpts{} + + if !f.isDeterministic() { + so.t = time.Now() + } + + for _, opt := range opts { + if err := opt(&so); err != nil { + return fmt.Errorf("%w", err) + } + } + + rd, err := f.getDescriptor(WithID(id)) + if err != nil { + return fmt.Errorf("%w", err) + } + + if err := rd.setExtra(md); err != nil { + return fmt.Errorf("%w", err) + } + + rd.ModifiedAt = so.t.Unix() + + if err := f.writeDescriptors(); err != nil { + return fmt.Errorf("%w", err) + } + + f.h.ModifiedAt = so.t.Unix() + + if err := f.writeHeader(); err != nil { + return fmt.Errorf("%w", err) + } + + return nil +} diff --git a/pkg/sif/create_test.go b/pkg/sif/create_test.go index d1455d5..ce59a22 100644 --- a/pkg/sif/create_test.go +++ b/pkg/sif/create_test.go @@ -653,3 +653,84 @@ func TestSetPrimPart(t *testing.T) { }) } } + +func TestSetMetadata(t *testing.T) { + tests := []struct { + name string + createOpts []CreateOpt + id uint32 + opts []SetOpt + wantErr error + }{ + { + name: "Deterministic", + createOpts: []CreateOpt{ + OptCreateWithID("de170c43-36ab-44a8-bca9-1ea1a070a274"), + OptCreateWithDescriptors( + getDescriptorInput(t, DataOCIBlob, []byte{0xfa, 0xce}), + ), + OptCreateWithTime(time.Unix(946702800, 0)), + }, + id: 1, + opts: []SetOpt{ + OptSetDeterministic(), + }, + }, + { + name: "WithTime", + createOpts: []CreateOpt{ + OptCreateDeterministic(), + OptCreateWithDescriptors( + getDescriptorInput(t, DataOCIBlob, []byte{0xfa, 0xce}), + ), + }, + id: 1, + opts: []SetOpt{ + OptSetWithTime(time.Unix(946702800, 0)), + }, + }, + { + name: "One", + createOpts: []CreateOpt{ + OptCreateDeterministic(), + OptCreateWithDescriptors( + getDescriptorInput(t, DataOCIBlob, []byte{0xfa, 0xce}), + ), + }, + id: 1, + }, + { + name: "Two", + createOpts: []CreateOpt{ + OptCreateDeterministic(), + OptCreateWithDescriptors( + getDescriptorInput(t, DataOCIBlob, []byte{0xfa, 0xce}), + getDescriptorInput(t, DataOCIBlob, []byte{0xfe, 0xed}), + ), + }, + id: 2, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var b Buffer + + f, err := CreateContainer(&b, tt.createOpts...) + if err != nil { + t.Fatal(err) + } + + if got, want := f.SetMetadata(tt.id, newOCIBlobDigest(), tt.opts...), tt.wantErr; !errors.Is(got, want) { + t.Errorf("got error %v, want %v", got, want) + } + + if err := f.UnloadContainer(); err != nil { + t.Error(err) + } + + g := goldie.New(t, goldie.WithTestNameForDir(true)) + g.Assert(t, tt.name, b.Bytes()) + }) + } +} diff --git a/pkg/sif/testdata/TestSetMetadata/Deterministic.golden b/pkg/sif/testdata/TestSetMetadata/Deterministic.golden new file mode 100644 index 0000000..aab5f44 Binary files /dev/null and b/pkg/sif/testdata/TestSetMetadata/Deterministic.golden differ diff --git a/pkg/sif/testdata/TestSetMetadata/ErrObjectNotFound.golden b/pkg/sif/testdata/TestSetMetadata/ErrObjectNotFound.golden new file mode 100644 index 0000000..01584e2 Binary files /dev/null and b/pkg/sif/testdata/TestSetMetadata/ErrObjectNotFound.golden differ diff --git a/pkg/sif/testdata/TestSetMetadata/One.golden b/pkg/sif/testdata/TestSetMetadata/One.golden new file mode 100644 index 0000000..33e0b15 Binary files /dev/null and b/pkg/sif/testdata/TestSetMetadata/One.golden differ diff --git a/pkg/sif/testdata/TestSetMetadata/Two.golden b/pkg/sif/testdata/TestSetMetadata/Two.golden new file mode 100644 index 0000000..1e26637 Binary files /dev/null and b/pkg/sif/testdata/TestSetMetadata/Two.golden differ diff --git a/pkg/sif/testdata/TestSetMetadata/WithTime.golden b/pkg/sif/testdata/TestSetMetadata/WithTime.golden new file mode 100644 index 0000000..58331df Binary files /dev/null and b/pkg/sif/testdata/TestSetMetadata/WithTime.golden differ