...
1 package schema2
2
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7
8 "github.com/docker/distribution"
9 "github.com/docker/distribution/manifest"
10 "github.com/opencontainers/go-digest"
11 )
12
13 const (
14
15 MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
16
17
18 MediaTypeImageConfig = "application/vnd.docker.container.image.v1+json"
19
20
21 MediaTypePluginConfig = "application/vnd.docker.plugin.v1+json"
22
23
24
25 MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
26
27
28
29 MediaTypeForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
30
31
32
33 MediaTypeUncompressedLayer = "application/vnd.docker.image.rootfs.diff.tar"
34 )
35
36 var (
37
38
39 SchemaVersion = manifest.Versioned{
40 SchemaVersion: 2,
41 MediaType: MediaTypeManifest,
42 }
43 )
44
45 func init() {
46 schema2Func := func(b []byte) (distribution.Manifest, distribution.Descriptor, error) {
47 m := new(DeserializedManifest)
48 err := m.UnmarshalJSON(b)
49 if err != nil {
50 return nil, distribution.Descriptor{}, err
51 }
52
53 dgst := digest.FromBytes(b)
54 return m, distribution.Descriptor{Digest: dgst, Size: int64(len(b)), MediaType: MediaTypeManifest}, err
55 }
56 err := distribution.RegisterManifestSchema(MediaTypeManifest, schema2Func)
57 if err != nil {
58 panic(fmt.Sprintf("Unable to register manifest: %s", err))
59 }
60 }
61
62
63 type Manifest struct {
64 manifest.Versioned
65
66
67 Config distribution.Descriptor `json:"config"`
68
69
70
71 Layers []distribution.Descriptor `json:"layers"`
72 }
73
74
75 func (m Manifest) References() []distribution.Descriptor {
76 references := make([]distribution.Descriptor, 0, 1+len(m.Layers))
77 references = append(references, m.Config)
78 references = append(references, m.Layers...)
79 return references
80 }
81
82
83 func (m Manifest) Target() distribution.Descriptor {
84 return m.Config
85 }
86
87
88
89 type DeserializedManifest struct {
90 Manifest
91
92
93 canonical []byte
94 }
95
96
97
98 func FromStruct(m Manifest) (*DeserializedManifest, error) {
99 var deserialized DeserializedManifest
100 deserialized.Manifest = m
101
102 var err error
103 deserialized.canonical, err = json.MarshalIndent(&m, "", " ")
104 return &deserialized, err
105 }
106
107
108 func (m *DeserializedManifest) UnmarshalJSON(b []byte) error {
109 m.canonical = make([]byte, len(b))
110
111 copy(m.canonical, b)
112
113
114 var manifest Manifest
115 if err := json.Unmarshal(m.canonical, &manifest); err != nil {
116 return err
117 }
118
119 if manifest.MediaType != MediaTypeManifest {
120 return fmt.Errorf("mediaType in manifest should be '%s' not '%s'",
121 MediaTypeManifest, manifest.MediaType)
122
123 }
124
125 m.Manifest = manifest
126
127 return nil
128 }
129
130
131
132 func (m *DeserializedManifest) MarshalJSON() ([]byte, error) {
133 if len(m.canonical) > 0 {
134 return m.canonical, nil
135 }
136
137 return nil, errors.New("JSON representation not initialized in DeserializedManifest")
138 }
139
140
141
142 func (m DeserializedManifest) Payload() (string, []byte, error) {
143 return m.MediaType, m.canonical, nil
144 }
145
View as plain text