pkg/manifests.List: add SetSubject()/Subject()
Add methods for reading and writing the index-level "subject" field. Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
This commit is contained in:
parent
ba247016fa
commit
0f7852ef9b
|
@ -0,0 +1,29 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepCopyDescriptor copies a Descriptor, deeply copying its contents
|
||||||
|
func DeepCopyDescriptor(original *v1.Descriptor) *v1.Descriptor {
|
||||||
|
tmp := *original
|
||||||
|
if original.URLs != nil {
|
||||||
|
tmp.URLs = slices.Clone(original.URLs)
|
||||||
|
}
|
||||||
|
if original.Annotations != nil {
|
||||||
|
tmp.Annotations = maps.Clone(original.Annotations)
|
||||||
|
}
|
||||||
|
if original.Data != nil {
|
||||||
|
tmp.Data = slices.Clone(original.Data)
|
||||||
|
}
|
||||||
|
if original.Platform != nil {
|
||||||
|
tmpPlatform := *original.Platform
|
||||||
|
if original.Platform.OSFeatures != nil {
|
||||||
|
tmpPlatform.OSFeatures = slices.Clone(original.Platform.OSFeatures)
|
||||||
|
}
|
||||||
|
tmp.Platform = &tmpPlatform
|
||||||
|
}
|
||||||
|
return &tmp
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/containers/common/internal"
|
||||||
"github.com/containers/image/v5/manifest"
|
"github.com/containers/image/v5/manifest"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
imgspec "github.com/opencontainers/image-spec/specs-go"
|
imgspec "github.com/opencontainers/image-spec/specs-go"
|
||||||
|
@ -39,6 +40,8 @@ type List interface {
|
||||||
MediaType(instanceDigest digest.Digest) (string, error)
|
MediaType(instanceDigest digest.Digest) (string, error)
|
||||||
SetArtifactType(instanceDigest digest.Digest, artifactType string) error
|
SetArtifactType(instanceDigest digest.Digest, artifactType string) error
|
||||||
ArtifactType(instanceDigest digest.Digest) (string, error)
|
ArtifactType(instanceDigest digest.Digest) (string, error)
|
||||||
|
SetSubject(subject *v1.Descriptor) error
|
||||||
|
Subject() (*v1.Descriptor, error)
|
||||||
Serialize(mimeType string) ([]byte, error)
|
Serialize(mimeType string) ([]byte, error)
|
||||||
Instances() []digest.Digest
|
Instances() []digest.Digest
|
||||||
OCIv1() *v1.Index
|
OCIv1() *v1.Index
|
||||||
|
@ -488,6 +491,26 @@ func (l *list) ArtifactType(instanceDigest digest.Digest) (string, error) {
|
||||||
return oci.ArtifactType, nil
|
return oci.ArtifactType, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetSubject sets the image index's subject.
|
||||||
|
// The field is specific to the OCI image index format, and is not present in Docker manifest lists.
|
||||||
|
func (l *list) SetSubject(subject *v1.Descriptor) error {
|
||||||
|
if subject != nil {
|
||||||
|
subject = internal.DeepCopyDescriptor(subject)
|
||||||
|
}
|
||||||
|
l.oci.Subject = subject
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subject retrieves the subject which might have been set on the image index.
|
||||||
|
// The field is specific to the OCI image index format, and is not present in Docker manifest lists.
|
||||||
|
func (l *list) Subject() (*v1.Descriptor, error) {
|
||||||
|
s := l.oci.Subject
|
||||||
|
if s != nil {
|
||||||
|
s = internal.DeepCopyDescriptor(s)
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FromBlob builds a list from an encoded manifest list or image index.
|
// FromBlob builds a list from an encoded manifest list or image index.
|
||||||
func FromBlob(manifestBytes []byte) (List, error) {
|
func FromBlob(manifestBytes []byte) (List, error) {
|
||||||
manifestType := manifest.GuessMIMEType(manifestBytes)
|
manifestType := manifest.GuessMIMEType(manifestBytes)
|
||||||
|
|
|
@ -462,3 +462,43 @@ func TestPlatform(t *testing.T) {
|
||||||
assert.NoError(t, list.SetOSFeatures(instanceDigest, []string{}))
|
assert.NoError(t, list.SetOSFeatures(instanceDigest, []string{}))
|
||||||
assert.Nil(t, list.OCIv1().Manifests[0].Platform, "expected platform to be nil")
|
assert.Nil(t, list.OCIv1().Manifests[0].Platform, "expected platform to be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSubject(t *testing.T) {
|
||||||
|
bytes, err := os.ReadFile(ociFixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading blob: %v", err)
|
||||||
|
}
|
||||||
|
list, err := FromBlob(bytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error parsing blob: %v", err)
|
||||||
|
}
|
||||||
|
for _, wrote := range []*v1.Descriptor{
|
||||||
|
nil,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
MediaType: v1.MediaTypeImageManifest,
|
||||||
|
Digest: expectedInstance,
|
||||||
|
Size: 1234,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
err := list.SetSubject(wrote)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error setting subject: %v", err)
|
||||||
|
}
|
||||||
|
b, err := list.Serialize("")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error serializing list: %v", err)
|
||||||
|
}
|
||||||
|
list, err = FromBlob(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error parsing list: %v", err)
|
||||||
|
}
|
||||||
|
read, err := list.Subject()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error retrieving subject: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(read, wrote) {
|
||||||
|
t.Fatalf("expected subject %v, got %v", wrote, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue