github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/manifest/types/types.go (about)

     1  package types
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/distribution/reference"
     7  	"github.com/khulnasoft-lab/distribution"
     8  	"github.com/khulnasoft-lab/distribution/manifest/manifestlist"
     9  	"github.com/khulnasoft-lab/distribution/manifest/ocischema"
    10  	"github.com/khulnasoft-lab/distribution/manifest/schema2"
    11  	"github.com/opencontainers/go-digest"
    12  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // ImageManifest contains info to output for a manifest object.
    17  type ImageManifest struct {
    18  	Ref        *SerializableNamed
    19  	Descriptor ocispec.Descriptor
    20  	Raw        []byte `json:",omitempty"`
    21  
    22  	// SchemaV2Manifest is used for inspection
    23  	SchemaV2Manifest *schema2.DeserializedManifest `json:",omitempty"`
    24  	// OCIManifest is used for inspection
    25  	OCIManifest *ocischema.DeserializedManifest `json:",omitempty"`
    26  }
    27  
    28  // OCIPlatform creates an OCI platform from a manifest list platform spec
    29  func OCIPlatform(ps *manifestlist.PlatformSpec) *ocispec.Platform {
    30  	if ps == nil {
    31  		return nil
    32  	}
    33  	return &ocispec.Platform{
    34  		Architecture: ps.Architecture,
    35  		OS:           ps.OS,
    36  		OSVersion:    ps.OSVersion,
    37  		OSFeatures:   ps.OSFeatures,
    38  		Variant:      ps.Variant,
    39  	}
    40  }
    41  
    42  // PlatformSpecFromOCI creates a platform spec from OCI platform
    43  func PlatformSpecFromOCI(p *ocispec.Platform) *manifestlist.PlatformSpec {
    44  	if p == nil {
    45  		return nil
    46  	}
    47  	return &manifestlist.PlatformSpec{
    48  		Architecture: p.Architecture,
    49  		OS:           p.OS,
    50  		OSVersion:    p.OSVersion,
    51  		OSFeatures:   p.OSFeatures,
    52  		Variant:      p.Variant,
    53  	}
    54  }
    55  
    56  // Blobs returns the digests for all the blobs referenced by this manifest
    57  func (i ImageManifest) Blobs() []digest.Digest {
    58  	var digests []digest.Digest
    59  	switch {
    60  	case i.SchemaV2Manifest != nil:
    61  		refs := i.SchemaV2Manifest.References()
    62  		digests = make([]digest.Digest, 0, len(refs))
    63  		for _, descriptor := range refs {
    64  			digests = append(digests, descriptor.Digest)
    65  		}
    66  	case i.OCIManifest != nil:
    67  		refs := i.OCIManifest.References()
    68  		digests = make([]digest.Digest, 0, len(refs))
    69  		for _, descriptor := range refs {
    70  			digests = append(digests, descriptor.Digest)
    71  		}
    72  	}
    73  	return digests
    74  }
    75  
    76  // Payload returns the media type and bytes for the manifest
    77  func (i ImageManifest) Payload() (string, []byte, error) {
    78  	// TODO: If available, read content from a content store by digest
    79  	switch {
    80  	case i.SchemaV2Manifest != nil:
    81  		return i.SchemaV2Manifest.Payload()
    82  	case i.OCIManifest != nil:
    83  		return i.OCIManifest.Payload()
    84  	default:
    85  		return "", nil, errors.Errorf("%s has no payload", i.Ref)
    86  	}
    87  }
    88  
    89  // References implements the distribution.Manifest interface. It delegates to
    90  // the underlying manifest.
    91  func (i ImageManifest) References() []distribution.Descriptor {
    92  	switch {
    93  	case i.SchemaV2Manifest != nil:
    94  		return i.SchemaV2Manifest.References()
    95  	case i.OCIManifest != nil:
    96  		return i.OCIManifest.References()
    97  	default:
    98  		return nil
    99  	}
   100  }
   101  
   102  // NewImageManifest returns a new ImageManifest object. The values for Platform
   103  // are initialized from those in the image
   104  func NewImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *schema2.DeserializedManifest) ImageManifest {
   105  	raw, err := manifest.MarshalJSON()
   106  	if err != nil {
   107  		raw = nil
   108  	}
   109  
   110  	return ImageManifest{
   111  		Ref:              &SerializableNamed{Named: ref},
   112  		Descriptor:       desc,
   113  		Raw:              raw,
   114  		SchemaV2Manifest: manifest,
   115  	}
   116  }
   117  
   118  // NewOCIImageManifest returns a new ImageManifest object. The values for
   119  // Platform are initialized from those in the image
   120  func NewOCIImageManifest(ref reference.Named, desc ocispec.Descriptor, manifest *ocischema.DeserializedManifest) ImageManifest {
   121  	raw, err := manifest.MarshalJSON()
   122  	if err != nil {
   123  		raw = nil
   124  	}
   125  
   126  	return ImageManifest{
   127  		Ref:         &SerializableNamed{Named: ref},
   128  		Descriptor:  desc,
   129  		Raw:         raw,
   130  		OCIManifest: manifest,
   131  	}
   132  }
   133  
   134  // SerializableNamed is a reference.Named that can be serialized and deserialized
   135  // from JSON
   136  type SerializableNamed struct {
   137  	reference.Named
   138  }
   139  
   140  // UnmarshalJSON loads the Named reference from JSON bytes
   141  func (s *SerializableNamed) UnmarshalJSON(b []byte) error {
   142  	var raw string
   143  	if err := json.Unmarshal(b, &raw); err != nil {
   144  		return errors.Wrapf(err, "invalid named reference bytes: %s", b)
   145  	}
   146  	var err error
   147  	s.Named, err = reference.ParseNamed(raw)
   148  	return err
   149  }
   150  
   151  // MarshalJSON returns the JSON bytes representation
   152  func (s *SerializableNamed) MarshalJSON() ([]byte, error) {
   153  	return json.Marshal(s.String())
   154  }