1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package partial
16
17 import (
18 "bytes"
19 "encoding/json"
20 "fmt"
21 "io"
22
23 v1 "github.com/google/go-containerregistry/pkg/v1"
24 "github.com/google/go-containerregistry/pkg/v1/types"
25 )
26
27
28 type WithRawConfigFile interface {
29
30 RawConfigFile() ([]byte, error)
31 }
32
33
34 func ConfigFile(i WithRawConfigFile) (*v1.ConfigFile, error) {
35 b, err := i.RawConfigFile()
36 if err != nil {
37 return nil, err
38 }
39 return v1.ParseConfigFile(bytes.NewReader(b))
40 }
41
42
43 func ConfigName(i WithRawConfigFile) (v1.Hash, error) {
44 b, err := i.RawConfigFile()
45 if err != nil {
46 return v1.Hash{}, err
47 }
48 h, _, err := v1.SHA256(bytes.NewReader(b))
49 return h, err
50 }
51
52 type configLayer struct {
53 hash v1.Hash
54 content []byte
55 }
56
57
58 func (cl *configLayer) Digest() (v1.Hash, error) {
59 return cl.hash, nil
60 }
61
62
63 func (cl *configLayer) DiffID() (v1.Hash, error) {
64 return cl.hash, nil
65 }
66
67
68 func (cl *configLayer) Uncompressed() (io.ReadCloser, error) {
69 return io.NopCloser(bytes.NewBuffer(cl.content)), nil
70 }
71
72
73 func (cl *configLayer) Compressed() (io.ReadCloser, error) {
74 return io.NopCloser(bytes.NewBuffer(cl.content)), nil
75 }
76
77
78 func (cl *configLayer) Size() (int64, error) {
79 return int64(len(cl.content)), nil
80 }
81
82 func (cl *configLayer) MediaType() (types.MediaType, error) {
83
84
85 return types.OCIConfigJSON, nil
86 }
87
88 var _ v1.Layer = (*configLayer)(nil)
89
90
91
92 type withConfigLayer interface {
93 ConfigLayer() (v1.Layer, error)
94 }
95
96
97
98
99
100
101 func ConfigLayer(i WithRawConfigFile) (v1.Layer, error) {
102 if wcl, ok := unwrap(i).(withConfigLayer); ok {
103 return wcl.ConfigLayer()
104 }
105
106 h, err := ConfigName(i)
107 if err != nil {
108 return nil, err
109 }
110 rcfg, err := i.RawConfigFile()
111 if err != nil {
112 return nil, err
113 }
114 return &configLayer{
115 hash: h,
116 content: rcfg,
117 }, nil
118 }
119
120
121 type WithConfigFile interface {
122
123 ConfigFile() (*v1.ConfigFile, error)
124 }
125
126
127 func DiffIDs(i WithConfigFile) ([]v1.Hash, error) {
128 cfg, err := i.ConfigFile()
129 if err != nil {
130 return nil, err
131 }
132 return cfg.RootFS.DiffIDs, nil
133 }
134
135
136 func RawConfigFile(i WithConfigFile) ([]byte, error) {
137 cfg, err := i.ConfigFile()
138 if err != nil {
139 return nil, err
140 }
141 return json.Marshal(cfg)
142 }
143
144
145 type WithRawManifest interface {
146
147 RawManifest() ([]byte, error)
148 }
149
150
151 func Digest(i WithRawManifest) (v1.Hash, error) {
152 mb, err := i.RawManifest()
153 if err != nil {
154 return v1.Hash{}, err
155 }
156 digest, _, err := v1.SHA256(bytes.NewReader(mb))
157 return digest, err
158 }
159
160
161 func Manifest(i WithRawManifest) (*v1.Manifest, error) {
162 b, err := i.RawManifest()
163 if err != nil {
164 return nil, err
165 }
166 return v1.ParseManifest(bytes.NewReader(b))
167 }
168
169
170 type WithManifest interface {
171
172 Manifest() (*v1.Manifest, error)
173 }
174
175
176 func RawManifest(i WithManifest) ([]byte, error) {
177 m, err := i.Manifest()
178 if err != nil {
179 return nil, err
180 }
181 return json.Marshal(m)
182 }
183
184
185 func Size(i WithRawManifest) (int64, error) {
186 b, err := i.RawManifest()
187 if err != nil {
188 return -1, err
189 }
190 return int64(len(b)), nil
191 }
192
193
194 func FSLayers(i WithManifest) ([]v1.Hash, error) {
195 m, err := i.Manifest()
196 if err != nil {
197 return nil, err
198 }
199 fsl := make([]v1.Hash, len(m.Layers))
200 for i, l := range m.Layers {
201 fsl[i] = l.Digest
202 }
203 return fsl, nil
204 }
205
206
207 func BlobSize(i WithManifest, h v1.Hash) (int64, error) {
208 d, err := BlobDescriptor(i, h)
209 if err != nil {
210 return -1, err
211 }
212 return d.Size, nil
213 }
214
215
216 func BlobDescriptor(i WithManifest, h v1.Hash) (*v1.Descriptor, error) {
217 m, err := i.Manifest()
218 if err != nil {
219 return nil, err
220 }
221
222 if m.Config.Digest == h {
223 return &m.Config, nil
224 }
225
226 for _, l := range m.Layers {
227 if l.Digest == h {
228 return &l, nil
229 }
230 }
231 return nil, fmt.Errorf("blob %v not found", h)
232 }
233
234
235 type WithManifestAndConfigFile interface {
236 WithConfigFile
237
238
239 Manifest() (*v1.Manifest, error)
240 }
241
242
243
244 func BlobToDiffID(i WithManifestAndConfigFile, h v1.Hash) (v1.Hash, error) {
245 blobs, err := FSLayers(i)
246 if err != nil {
247 return v1.Hash{}, err
248 }
249 diffIDs, err := DiffIDs(i)
250 if err != nil {
251 return v1.Hash{}, err
252 }
253 if len(blobs) != len(diffIDs) {
254 return v1.Hash{}, fmt.Errorf("mismatched fs layers (%d) and diff ids (%d)", len(blobs), len(diffIDs))
255 }
256 for i, blob := range blobs {
257 if blob == h {
258 return diffIDs[i], nil
259 }
260 }
261 return v1.Hash{}, fmt.Errorf("unknown blob %v", h)
262 }
263
264
265
266 func DiffIDToBlob(wm WithManifestAndConfigFile, h v1.Hash) (v1.Hash, error) {
267 blobs, err := FSLayers(wm)
268 if err != nil {
269 return v1.Hash{}, err
270 }
271 diffIDs, err := DiffIDs(wm)
272 if err != nil {
273 return v1.Hash{}, err
274 }
275 if len(blobs) != len(diffIDs) {
276 return v1.Hash{}, fmt.Errorf("mismatched fs layers (%d) and diff ids (%d)", len(blobs), len(diffIDs))
277 }
278 for i, diffID := range diffIDs {
279 if diffID == h {
280 return blobs[i], nil
281 }
282 }
283 return v1.Hash{}, fmt.Errorf("unknown diffID %v", h)
284 }
285
286
287 type WithDiffID interface {
288 DiffID() (v1.Hash, error)
289 }
290
291
292
293
294
295 type withDescriptor interface {
296 Descriptor() (*v1.Descriptor, error)
297 }
298
299
300 type Describable interface {
301 Digest() (v1.Hash, error)
302 MediaType() (types.MediaType, error)
303 Size() (int64, error)
304 }
305
306
307
308
309
310 func Descriptor(d Describable) (*v1.Descriptor, error) {
311
312 if wd, ok := unwrap(d).(withDescriptor); ok {
313 return wd.Descriptor()
314 }
315
316
317 var (
318 desc v1.Descriptor
319 err error
320 )
321
322 if desc.Size, err = d.Size(); err != nil {
323 return nil, err
324 }
325 if desc.Digest, err = d.Digest(); err != nil {
326 return nil, err
327 }
328 if desc.MediaType, err = d.MediaType(); err != nil {
329 return nil, err
330 }
331 if wat, ok := d.(withArtifactType); ok {
332 if desc.ArtifactType, err = wat.ArtifactType(); err != nil {
333 return nil, err
334 }
335 } else {
336 if wrm, ok := d.(WithRawManifest); ok && desc.MediaType.IsImage() {
337 mf, _ := Manifest(wrm)
338
339
340 if mf != nil && !mf.Config.MediaType.IsConfig() {
341 desc.ArtifactType = string(mf.Config.MediaType)
342 }
343 }
344 }
345
346 return &desc, nil
347 }
348
349 type withArtifactType interface {
350 ArtifactType() (string, error)
351 }
352
353 type withUncompressedSize interface {
354 UncompressedSize() (int64, error)
355 }
356
357
358
359
360
361
362 func UncompressedSize(l v1.Layer) (int64, error) {
363
364 if wus, ok := unwrap(l).(withUncompressedSize); ok {
365 return wus.UncompressedSize()
366 }
367
368
369 rc, err := l.Uncompressed()
370 if err != nil {
371 return -1, err
372 }
373 defer rc.Close()
374
375 return io.Copy(io.Discard, rc)
376 }
377
378 type withExists interface {
379 Exists() (bool, error)
380 }
381
382
383
384 func Exists(l v1.Layer) (bool, error) {
385
386 if we, ok := unwrap(l).(withExists); ok {
387 return we.Exists()
388 }
389
390
391
392 rc, err := l.Compressed()
393 if err != nil {
394 return false, err
395 }
396 defer rc.Close()
397
398
399
400 return true, nil
401 }
402
403
404
405 func unwrap(i any) any {
406 if ule, ok := i.(*uncompressedLayerExtender); ok {
407 return unwrap(ule.UncompressedLayer)
408 }
409 if cle, ok := i.(*compressedLayerExtender); ok {
410 return unwrap(cle.CompressedLayer)
411 }
412 if uie, ok := i.(*uncompressedImageExtender); ok {
413 return unwrap(uie.UncompressedImageCore)
414 }
415 if cie, ok := i.(*compressedImageExtender); ok {
416 return unwrap(cie.CompressedImageCore)
417 }
418 return i
419 }
420
421
422
423
424
425 func ArtifactType(w WithManifest) (string, error) {
426 if wat, ok := w.(withArtifactType); ok {
427 return wat.ArtifactType()
428 }
429 mf, _ := w.Manifest()
430
431
432 if mf != nil && !mf.Config.MediaType.IsConfig() {
433 return string(mf.Config.MediaType), nil
434 }
435 return "", nil
436 }
437
View as plain text