11package ocimem
22
33import (
4+ "cmp"
45 "encoding/json"
56 "fmt"
7+ "iter"
68
79 "cuelabs.dev/go/oci/ociregistry"
810 ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -22,25 +24,37 @@ type descInfo struct {
2224 desc ociregistry.Descriptor
2325}
2426
25- type descIter func (yield func (descInfo ) bool )
27+ type manifestInfo struct {
28+ // descriptors iterates over all direct references inside the manifest
29+ descriptors descIter
30+ // subject holds the subject (referred-to manifest) of the manifest
31+ subject ociregistry.Digest
32+ // artifactType holds the artifact type of the manifest
33+ artifactType string
34+ // annotations holds any annotations from the manifest.
35+ annotations map [string ]string
36+ }
37+
38+ type descIter = iter.Seq [descInfo ]
2639
2740// TODO support other manifest types.
28- var manifestIterators = map [string ]func (data []byte ) (descIter , error ){
29- ocispec .MediaTypeImageManifest : descIterForType ( imageDescIter ),
30- ocispec .MediaTypeImageIndex : descIterForType ( indexDescIter ),
41+ var manifestInfoByMediaType = map [string ]func (data []byte ) (manifestInfo , error ){
42+ ocispec .MediaTypeImageManifest : manifestInfoForType ( imageInfo ),
43+ ocispec .MediaTypeImageIndex : manifestInfoForType ( indexInfo ),
3144}
3245
33- // manifestReferences returns an iterator that iterates over all
34- // direct references inside the given manifest described byx the
35- // given descriptor that holds the given data.
36- func manifestReferences (mediaType string , data []byte ) (descIter , error ) {
37- dataIter := manifestIterators [mediaType ]
38- if dataIter == nil {
46+ // getManifestInfo returns information on the manifest
47+ // described by the given media type and data.
48+ func getManifestInfo (mediaType string , data []byte ) (manifestInfo , error ) {
49+ getInfo := manifestInfoByMediaType [mediaType ]
50+ if getInfo == nil {
3951 // TODO provide a configuration option to disallow unknown manifest types.
4052 //return nil, fmt.Errorf("media type %q: %w", mediaType, errUnknownManifestMediaTypeForIteration)
41- return func (func (descInfo ) bool ) {}, nil
53+ return manifestInfo {
54+ descriptors : func (func (descInfo ) bool ) {},
55+ }, nil
4256 }
43- return dataIter (data )
57+ return getInfo (data )
4458}
4559
4660// repoTagIter returns an iterator that iterates through
@@ -59,18 +73,19 @@ func repoTagIter(r *repository) descIter {
5973 }
6074}
6175
62- func descIterForType [T any ](newIter func (T ) descIter ) func (data []byte ) (descIter , error ) {
63- return func (data []byte ) (descIter , error ) {
76+ func manifestInfoForType [T any ](getInfo func (T ) manifestInfo ) func (data []byte ) (manifestInfo , error ) {
77+ return func (data []byte ) (manifestInfo , error ) {
6478 var x T
6579 if err := json .Unmarshal (data , & x ); err != nil {
66- return nil , fmt .Errorf ("cannot unmarshal into %T: %v" , & x , err )
80+ return manifestInfo {} , fmt .Errorf ("cannot unmarshal into %T: %v" , & x , err )
6781 }
68- return newIter (x ), nil
82+ return getInfo (x ), nil
6983 }
7084}
7185
72- func imageDescIter (m ociregistry.Manifest ) descIter {
73- return func (yield func (descInfo ) bool ) {
86+ func imageInfo (m ociregistry.Manifest ) manifestInfo {
87+ var info manifestInfo
88+ info .descriptors = func (yield func (descInfo ) bool ) {
7489 for i , layer := range m .Layers {
7590 if ! yield (descInfo {
7691 name : fmt .Sprintf ("layers[%d]" , i ),
@@ -97,10 +112,27 @@ func imageDescIter(m ociregistry.Manifest) descIter {
97112 }
98113 }
99114 }
115+ // From https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers
116+ //
117+ // The descriptors MUST include an artifactType field that is set to
118+ // the value of the artifactType in the image manifest or index, if
119+ // present. If the artifactType is empty or missing in the image
120+ // manifest, the value of artifactType MUST be set to the config
121+ // descriptor mediaType value. If the artifactType is empty or
122+ // missing in an index, the artifactType MUST be omitted. The
123+ // descriptors MUST include annotations from the image manifest or
124+ // index.
125+ info .artifactType = cmp .Or (m .ArtifactType , m .Config .MediaType )
126+ info .annotations = m .Annotations
127+ if m .Subject != nil {
128+ info .subject = m .Subject .Digest
129+ }
130+ return info
100131}
101132
102- func indexDescIter (m ocispec.Index ) descIter {
103- return func (yield func (descInfo ) bool ) {
133+ func indexInfo (m ocispec.Index ) manifestInfo {
134+ var info manifestInfo
135+ info .descriptors = func (yield func (descInfo ) bool ) {
104136 for i , manifest := range m .Manifests {
105137 if ! yield (descInfo {
106138 name : fmt .Sprintf ("manifests[%d]" , i ),
@@ -120,4 +152,10 @@ func indexDescIter(m ocispec.Index) descIter {
120152 }
121153 }
122154 }
155+ info .artifactType = m .ArtifactType // Note: no config descriptor to fall back to.
156+ info .annotations = m .Annotations
157+ if m .Subject != nil {
158+ info .subject = m .Subject .Digest
159+ }
160+ return info
123161}
0 commit comments