cuelabs.dev/go/oci/ociregistry@v0.0.0-20240906074133-82eb438dd565/ocimem/desciter.go (about) 1 package ocimem 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "cuelabs.dev/go/oci/ociregistry" 8 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 9 ) 10 11 type refKind int 12 13 const ( 14 kindSubjectManifest refKind = iota 15 kindBlob 16 kindManifest 17 ) 18 19 type descInfo struct { 20 name string 21 kind refKind 22 desc ociregistry.Descriptor 23 } 24 25 type descIter func(yield func(descInfo) bool) 26 27 // 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), 31 } 32 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 { 39 // TODO provide a configuration option to disallow unknown manifest types. 40 //return nil, fmt.Errorf("media type %q: %w", mediaType, errUnknownManifestMediaTypeForIteration) 41 return func(func(descInfo) bool) {}, nil 42 } 43 return dataIter(data) 44 } 45 46 // repoTagIter returns an iterator that iterates through 47 // all the tags in the given repository. 48 func repoTagIter(r *repository) descIter { 49 return func(yield func(descInfo) bool) { 50 for tag, desc := range r.tags { 51 if !yield(descInfo{ 52 name: tag, 53 desc: desc, 54 kind: kindManifest, 55 }) { 56 break 57 } 58 } 59 } 60 } 61 62 func descIterForType[T any](newIter func(T) descIter) func(data []byte) (descIter, error) { 63 return func(data []byte) (descIter, error) { 64 var x T 65 if err := json.Unmarshal(data, &x); err != nil { 66 return nil, fmt.Errorf("cannot unmarshal into %T: %v", &x, err) 67 } 68 return newIter(x), nil 69 } 70 } 71 72 func imageDescIter(m ociregistry.Manifest) descIter { 73 return func(yield func(descInfo) bool) { 74 for i, layer := range m.Layers { 75 if !yield(descInfo{ 76 name: fmt.Sprintf("layers[%d]", i), 77 desc: layer, 78 kind: kindBlob, 79 }) { 80 return 81 } 82 } 83 if !yield(descInfo{ 84 name: "config", 85 desc: m.Config, 86 kind: kindBlob, 87 }) { 88 return 89 } 90 if m.Subject != nil { 91 if !yield(descInfo{ 92 name: "subject", 93 kind: kindSubjectManifest, 94 desc: *m.Subject, 95 }) { 96 return 97 } 98 } 99 } 100 } 101 102 func indexDescIter(m ocispec.Index) descIter { 103 return func(yield func(descInfo) bool) { 104 for i, manifest := range m.Manifests { 105 if !yield(descInfo{ 106 name: fmt.Sprintf("manifests[%d]", i), 107 kind: kindManifest, 108 desc: manifest, 109 }) { 110 return 111 } 112 } 113 if m.Subject != nil { 114 if !yield(descInfo{ 115 name: "subject", 116 kind: kindSubjectManifest, 117 desc: *m.Subject, 118 }) { 119 return 120 } 121 } 122 } 123 }