github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/manifest/manifestlist/manifestlist.go (about) 1 package manifestlist 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 8 "github.com/docker/distribution" 9 "github.com/docker/distribution/digest" 10 "github.com/docker/distribution/manifest" 11 ) 12 13 // MediaTypeManifestList specifies the mediaType for manifest lists. 14 const MediaTypeManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" 15 16 // SchemaVersion provides a pre-initialized version structure for this 17 // packages version of the manifest. 18 var SchemaVersion = manifest.Versioned{ 19 SchemaVersion: 2, 20 MediaType: MediaTypeManifestList, 21 } 22 23 func init() { 24 manifestListFunc := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) { 25 m := new(DeserializedManifestList) 26 err := m.UnmarshalJSON(b) 27 if err != nil { 28 return nil, distribution.Descriptor{}, err 29 } 30 31 dgst := digest.FromBytes(b) 32 return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: MediaTypeManifestList}, err 33 } 34 err := distribution.RegisterManifestSchema(MediaTypeManifestList, manifestListFunc) 35 if err != nil { 36 panic(fmt.Sprintf("Unable to register manifest: %s", err)) 37 } 38 } 39 40 // PlatformSpec specifies a platform where a particular image manifest is 41 // applicable. 42 type PlatformSpec struct { 43 // Architecture field specifies the CPU architecture, for example 44 // `amd64` or `ppc64`. 45 Architecture string `json:"architecture"` 46 47 // OS specifies the operating system, for example `linux` or `windows`. 48 OS string `json:"os"` 49 50 // Variant is an optional field specifying a variant of the CPU, for 51 // example `ppc64le` to specify a little-endian version of a PowerPC CPU. 52 Variant string `json:"variant,omitempty"` 53 54 // Features is an optional field specifuing an array of strings, each 55 // listing a required CPU feature (for example `sse4` or `aes`). 56 Features []string `json:"features,omitempty"` 57 } 58 59 // A ManifestDescriptor references a platform-specific manifest. 60 type ManifestDescriptor struct { 61 distribution.Descriptor 62 63 // Platform specifies which platform the manifest pointed to by the 64 // descriptor runs on. 65 Platform PlatformSpec `json:"platform"` 66 } 67 68 // ManifestList references manifests for various platforms. 69 type ManifestList struct { 70 manifest.Versioned 71 72 // Config references the image configuration as a blob. 73 Manifests []ManifestDescriptor `json:"manifests"` 74 } 75 76 // References returnes the distribution descriptors for the referenced image 77 // manifests. 78 func (m ManifestList) References() []distribution.Descriptor { 79 dependencies := make([]distribution.Descriptor, len(m.Manifests)) 80 for i := range m.Manifests { 81 dependencies[i] = m.Manifests[i].Descriptor 82 } 83 84 return dependencies 85 } 86 87 // DeserializedManifestList wraps ManifestList with a copy of the original 88 // JSON. 89 type DeserializedManifestList struct { 90 ManifestList 91 92 // canonical is the canonical byte representation of the Manifest. 93 canonical []byte 94 } 95 96 // FromDescriptors takes a slice of descriptors, and returns a 97 // DeserializedManifestList which contains the resulting manifest list 98 // and its JSON representation. 99 func FromDescriptors(descriptors []ManifestDescriptor) (*DeserializedManifestList, error) { 100 m := ManifestList{ 101 Versioned: SchemaVersion, 102 } 103 104 m.Manifests = make([]ManifestDescriptor, len(descriptors), len(descriptors)) 105 copy(m.Manifests, descriptors) 106 107 deserialized := DeserializedManifestList{ 108 ManifestList: m, 109 } 110 111 var err error 112 deserialized.canonical, err = json.MarshalIndent(&m, "", " ") 113 return &deserialized, err 114 } 115 116 // UnmarshalJSON populates a new ManifestList struct from JSON data. 117 func (m *DeserializedManifestList) UnmarshalJSON(b []byte) error { 118 m.canonical = make([]byte, len(b), len(b)) 119 // store manifest list in canonical 120 copy(m.canonical, b) 121 122 // Unmarshal canonical JSON into ManifestList object 123 var manifestList ManifestList 124 if err := json.Unmarshal(m.canonical, &manifestList); err != nil { 125 return err 126 } 127 128 m.ManifestList = manifestList 129 130 return nil 131 } 132 133 // MarshalJSON returns the contents of canonical. If canonical is empty, 134 // marshals the inner contents. 135 func (m *DeserializedManifestList) MarshalJSON() ([]byte, error) { 136 if len(m.canonical) > 0 { 137 return m.canonical, nil 138 } 139 140 return nil, errors.New("JSON representation not initialized in DeserializedManifestList") 141 } 142 143 // Payload returns the raw content of the manifest list. The contents can be 144 // used to calculate the content identifier. 145 func (m DeserializedManifestList) Payload() (string, []byte, error) { 146 return m.MediaType, m.canonical, nil 147 }