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 }