@@ -16,9 +16,11 @@ import (
16
16
"github.com/docker/docker/pkg/chrootarchive"
17
17
"github.com/docker/docker/pkg/symlink"
18
18
"github.com/docker/docker/reference"
19
+ digest "github.com/opencontainers/go-digest"
20
+ ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
19
21
)
20
22
21
- func (l * tarexporter ) Load (inTar io.ReadCloser , outStream io.Writer ) error {
23
+ func (l * tarexporter ) Load (inTar io.ReadCloser , name string , refs map [ string ] string , outStream io.Writer ) error {
22
24
tmpDir , err := ioutil .TempDir ("" , "docker-import-" )
23
25
if err != nil {
24
26
return err
@@ -28,6 +30,18 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
28
30
if err := chrootarchive .Untar (inTar , tmpDir , nil ); err != nil {
29
31
return err
30
32
}
33
+
34
+ // check and try to load an OCI image layout
35
+ ociLayoutPath , err := safePath (tmpDir , "oci-layout" )
36
+ if err != nil {
37
+ return err
38
+ }
39
+ ociLayoutFile , err := os .Open (ociLayoutPath )
40
+ if err == nil {
41
+ ociLayoutFile .Close ()
42
+ return l .ociLoad (tmpDir , name , refs , outStream )
43
+ }
44
+
31
45
// read manifest, if no file then load in legacy mode
32
46
manifestPath , err := safePath (tmpDir , manifestFileName )
33
47
if err != nil {
@@ -47,7 +61,11 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
47
61
return err
48
62
}
49
63
50
- for _ , m := range manifest {
64
+ return l .loadHelper (tmpDir , manifest , outStream )
65
+ }
66
+
67
+ func (l * tarexporter ) loadHelper (tmpDir string , manifests []manifestItem , outStream io.Writer ) error {
68
+ for _ , m := range manifests {
51
69
configPath , err := safePath (tmpDir , m .Config )
52
70
if err != nil {
53
71
return err
@@ -105,7 +123,6 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
105
123
}
106
124
l .setLoadedTag (ref , imgID , outStream )
107
125
}
108
-
109
126
}
110
127
111
128
return nil
@@ -139,6 +156,84 @@ func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, ou
139
156
return nil
140
157
}
141
158
159
+ func (l * tarexporter ) ociLoad (tmpDir , name string , refs map [string ]string , outStream io.Writer ) error {
160
+ if name != "" && len (refs ) != 0 {
161
+ return fmt .Errorf ("cannot load with either name and refs" )
162
+ }
163
+
164
+ if name == "" && len (refs ) == 0 {
165
+ return fmt .Errorf ("no OCI image name mapping provided" )
166
+ }
167
+
168
+ var manifests []manifestItem
169
+ indexJSON , err := os .Open (filepath .Join (tmpDir , "index.json" ))
170
+ if err != nil {
171
+ return err
172
+ }
173
+ defer indexJSON .Close ()
174
+ index := ociv1.ImageIndex {}
175
+ if err := json .NewDecoder (indexJSON ).Decode (& index ); err != nil {
176
+ return err
177
+ }
178
+ for _ , md := range index .Manifests {
179
+ if md .MediaType != ociv1 .MediaTypeImageManifest {
180
+ continue
181
+ }
182
+ d := digest .Digest (md .Digest )
183
+ manifestPath := filepath .Join (tmpDir , "blobs" , d .Algorithm ().String (), d .Hex ())
184
+ f , err := os .Open (manifestPath )
185
+ if err != nil {
186
+ return err
187
+ }
188
+ defer f .Close ()
189
+ man := ociv1.Manifest {}
190
+ if err := json .NewDecoder (f ).Decode (& man ); err != nil {
191
+ return err
192
+ }
193
+ layers := make ([]string , len (man .Layers ))
194
+ for i , l := range man .Layers {
195
+ layerDigest := digest .Digest (l .Digest )
196
+ layers [i ] = filepath .Join ("blobs" , layerDigest .Algorithm ().String (), layerDigest .Hex ())
197
+ }
198
+ tag := ""
199
+ refName , ok := md .Annotations ["org.opencontainers.ref.name" ]
200
+ if ! ok {
201
+ return fmt .Errorf ("no ref name annotation" )
202
+ }
203
+ if name != "" {
204
+ named , err := reference .ParseNamed (name )
205
+ if err != nil {
206
+ return err
207
+ }
208
+ withTag , err := reference .WithTag (named , refName )
209
+ if err != nil {
210
+ return err
211
+ }
212
+ tag = withTag .String ()
213
+ } else {
214
+ _ , rs , err := getRefs (refs )
215
+ if err != nil {
216
+ return err
217
+ }
218
+ r , ok := rs [refName ]
219
+ if ! ok {
220
+ return fmt .Errorf ("no naming provided for %q" , refName )
221
+ }
222
+ tag = r .String ()
223
+ }
224
+ configDigest := digest .Digest (man .Config .Digest )
225
+ manifests = append (manifests , manifestItem {
226
+ Config : filepath .Join ("blobs" , configDigest .Algorithm ().String (), configDigest .Hex ()),
227
+ RepoTags : []string {tag },
228
+ Layers : layers ,
229
+ // TODO(runcom): foreign srcs?
230
+ // See https://github.com/docker/docker/pull/22866/files#r96125181
231
+ })
232
+ }
233
+
234
+ return l .loadHelper (tmpDir , manifests , outStream )
235
+ }
236
+
142
237
func (l * tarexporter ) legacyLoad (tmpDir string , outStream io.Writer ) error {
143
238
legacyLoadedMap := make (map [string ]image.ID )
144
239
0 commit comments