1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package layout
16
17 import (
18 "encoding/json"
19 "errors"
20 "fmt"
21 "io"
22 "os"
23
24 v1 "github.com/google/go-containerregistry/pkg/v1"
25 "github.com/google/go-containerregistry/pkg/v1/partial"
26 "github.com/google/go-containerregistry/pkg/v1/types"
27 )
28
29 var _ v1.ImageIndex = (*layoutIndex)(nil)
30
31 type layoutIndex struct {
32 mediaType types.MediaType
33 path Path
34 rawIndex []byte
35 }
36
37
38 func ImageIndexFromPath(path string) (v1.ImageIndex, error) {
39 lp, err := FromPath(path)
40 if err != nil {
41 return nil, err
42 }
43 return lp.ImageIndex()
44 }
45
46
47 func (l Path) ImageIndex() (v1.ImageIndex, error) {
48 rawIndex, err := os.ReadFile(l.path("index.json"))
49 if err != nil {
50 return nil, err
51 }
52
53 idx := &layoutIndex{
54 mediaType: types.OCIImageIndex,
55 path: l,
56 rawIndex: rawIndex,
57 }
58
59 return idx, nil
60 }
61
62 func (i *layoutIndex) MediaType() (types.MediaType, error) {
63 return i.mediaType, nil
64 }
65
66 func (i *layoutIndex) Digest() (v1.Hash, error) {
67 return partial.Digest(i)
68 }
69
70 func (i *layoutIndex) Size() (int64, error) {
71 return partial.Size(i)
72 }
73
74 func (i *layoutIndex) IndexManifest() (*v1.IndexManifest, error) {
75 var index v1.IndexManifest
76 err := json.Unmarshal(i.rawIndex, &index)
77 return &index, err
78 }
79
80 func (i *layoutIndex) RawManifest() ([]byte, error) {
81 return i.rawIndex, nil
82 }
83
84 func (i *layoutIndex) Image(h v1.Hash) (v1.Image, error) {
85
86 desc, err := i.findDescriptor(h)
87 if err != nil {
88 return nil, err
89 }
90
91 if !isExpectedMediaType(desc.MediaType, types.OCIManifestSchema1, types.DockerManifestSchema2) {
92 return nil, fmt.Errorf("unexpected media type for %v: %s", h, desc.MediaType)
93 }
94
95 img := &layoutImage{
96 path: i.path,
97 desc: *desc,
98 }
99 return partial.CompressedToImage(img)
100 }
101
102 func (i *layoutIndex) ImageIndex(h v1.Hash) (v1.ImageIndex, error) {
103
104 desc, err := i.findDescriptor(h)
105 if err != nil {
106 return nil, err
107 }
108
109 if !isExpectedMediaType(desc.MediaType, types.OCIImageIndex, types.DockerManifestList) {
110 return nil, fmt.Errorf("unexpected media type for %v: %s", h, desc.MediaType)
111 }
112
113 rawIndex, err := i.path.Bytes(h)
114 if err != nil {
115 return nil, err
116 }
117
118 return &layoutIndex{
119 mediaType: desc.MediaType,
120 path: i.path,
121 rawIndex: rawIndex,
122 }, nil
123 }
124
125 func (i *layoutIndex) Blob(h v1.Hash) (io.ReadCloser, error) {
126 return i.path.Blob(h)
127 }
128
129 func (i *layoutIndex) findDescriptor(h v1.Hash) (*v1.Descriptor, error) {
130 im, err := i.IndexManifest()
131 if err != nil {
132 return nil, err
133 }
134
135 if h == (v1.Hash{}) {
136 if len(im.Manifests) != 1 {
137 return nil, errors.New("oci layout must contain only a single image to be used with layout.Image")
138 }
139 return &(im.Manifests)[0], nil
140 }
141
142 for _, desc := range im.Manifests {
143 if desc.Digest == h {
144 return &desc, nil
145 }
146 }
147
148 return nil, fmt.Errorf("could not find descriptor in index: %s", h)
149 }
150
151
152
153
154 func isExpectedMediaType(mt types.MediaType, expected ...types.MediaType) bool {
155 for _, allowed := range expected {
156 if mt == allowed {
157 return true
158 }
159 }
160 return false
161 }
162
View as plain text