...

Source file src/cuelabs.dev/go/oci/ociregistry/ocimem/desciter.go

Documentation: cuelabs.dev/go/oci/ociregistry/ocimem

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

View as plain text