@@ -117,11 +117,11 @@ func ImagePartsFromArgs(config, baseManifest, imgTarball string, layers []string
117
117
return result , nil
118
118
}
119
119
120
- // reader maintains the state necessary to build a legacyImage object from an
120
+ // Reader maintains the state necessary to build a legacyImage object from an
121
121
// ImageParts object.
122
- type reader struct {
122
+ type Reader struct {
123
123
// parts is the ImageParts being loaded.
124
- parts ImageParts
124
+ Parts ImageParts
125
125
// baseManifest is the manifest of the very first base image in the chain
126
126
// of images being loaded.
127
127
baseManifest * v1.Manifest
@@ -130,32 +130,35 @@ type reader struct {
130
130
// layerLookup is a map from the diffID of a layer to the layer
131
131
// itself.
132
132
layerLookup map [v1.Hash ]v1.Layer
133
+ // loadedImageCache is a cache of all images that have been loaded into memory,
134
+ // to prevent costly reloads.
135
+ loadedImageCache map [v1.Hash ]bool
133
136
}
134
137
135
138
// loadMetadata loads the image metadata for the image parts in the given
136
139
// reader.
137
- func (r * reader ) loadMetadata () error {
138
- cf , err := os .Open (r .parts .Config )
140
+ func (r * Reader ) loadMetadata () error {
141
+ cf , err := os .Open (r .Parts .Config )
139
142
if err != nil {
140
- return errors .Wrapf (err , "unable to open image config file %s" , r .parts .Config )
143
+ return errors .Wrapf (err , "unable to open image config file %s" , r .Parts .Config )
141
144
}
142
145
c , err := v1 .ParseConfigFile (cf )
143
146
if err != nil {
144
- return errors .Wrapf (err , "unable to parse image config from %s" , r .parts .Config )
147
+ return errors .Wrapf (err , "unable to parse image config from %s" , r .Parts .Config )
145
148
}
146
149
r .config = c
147
- if r .parts .BaseManifest == "" {
150
+ if r .Parts .BaseManifest == "" {
148
151
// Base manifest is optional. It's only needed for images whose base
149
152
// manifests have foreign layers.
150
153
return nil
151
154
}
152
- mf , err := os .Open (r .parts .BaseManifest )
155
+ mf , err := os .Open (r .Parts .BaseManifest )
153
156
if err != nil {
154
- return errors .Wrapf (err , "unable to open base image manifest file %s" , r .parts .BaseManifest )
157
+ return errors .Wrapf (err , "unable to open base image manifest file %s" , r .Parts .BaseManifest )
155
158
}
156
159
m , err := v1 .ParseManifest (mf )
157
160
if err != nil {
158
- return errors .Wrapf (err , "unable to parse base image manifest from %s" , r .parts .BaseManifest )
161
+ return errors .Wrapf (err , "unable to parse base image manifest from %s" , r .Parts .BaseManifest )
159
162
}
160
163
r .baseManifest = m
161
164
return nil
@@ -209,7 +212,7 @@ func (l *foreignLayer) MediaType() (types.MediaType, error) {
209
212
210
213
// loadForeignLayers loads the foreign layers from the base manifest in the
211
214
// given reader into the layer lookup.
212
- func (r * reader ) loadForeignLayers () error {
215
+ func (r * Reader ) loadForeignLayers () error {
213
216
if r .baseManifest == nil {
214
217
// No base manifest so no foreign layers to load.
215
218
return nil
@@ -237,8 +240,12 @@ func (r *reader) loadForeignLayers() error {
237
240
238
241
// loadImages loads the layers from the given images into the layers lookup
239
242
// in the given reader.
240
- func (r * reader ) loadImages (images []v1.Image ) error {
243
+ func (r * Reader ) loadImages (images []v1.Image ) error {
241
244
for _ , img := range images {
245
+ digest , _ := img .Digest ()
246
+ if r .loadedImageCache [digest ] {
247
+ continue
248
+ }
242
249
layers , err := img .Layers ()
243
250
if err != nil {
244
251
return errors .Wrap (err , "unable to get the layers in image" )
@@ -250,31 +257,32 @@ func (r *reader) loadImages(images []v1.Image) error {
250
257
}
251
258
r .layerLookup [diffID ] = l
252
259
}
260
+ r .loadedImageCache [digest ] = true
253
261
}
254
262
return nil
255
263
}
256
264
257
265
// loadImgTarball loads the layers from the image tarball in the parts section
258
266
// of the given reader if one was specified into the layers lookup in the given
259
267
// reader.
260
- func (r * reader ) loadImgTarball () error {
261
- if r .parts .ImageTarball == "" {
268
+ func (r * Reader ) loadImgTarball () error {
269
+ if r .Parts .ImageTarball == "" {
262
270
return nil
263
271
}
264
- img , err := tarball .ImageFromPath (r .parts .ImageTarball , nil )
272
+ img , err := tarball .ImageFromPath (r .Parts .ImageTarball , nil )
265
273
if err != nil {
266
- return errors .Wrapf (err , "unable to load image from tarball %s" , r .parts .ImageTarball )
274
+ return errors .Wrapf (err , "unable to load image from tarball %s" , r .Parts .ImageTarball )
267
275
}
268
276
if err := r .loadImages ([]v1.Image {img }); err != nil {
269
- return errors .Wrapf (err , "unable to load the layers from image loaded from tarball %s" , r .parts .ImageTarball )
277
+ return errors .Wrapf (err , "unable to load the layers from image loaded from tarball %s" , r .Parts .ImageTarball )
270
278
}
271
279
return nil
272
280
}
273
281
274
282
// loadLayers loads layers specified as parts in the ImageParts section in the
275
283
// given reader.
276
- func (r * reader ) loadLayers () error {
277
- for _ , l := range r .parts .Layers {
284
+ func (r * Reader ) loadLayers () error {
285
+ for _ , l := range r .Parts .Layers {
278
286
layer , err := l .V1Layer ()
279
287
if err != nil {
280
288
return errors .Wrap (err , "unable to build a v1.Layer from the specified parts" )
@@ -289,23 +297,27 @@ func (r *reader) loadLayers() error {
289
297
}
290
298
291
299
// ReadImage loads a v1.Image from the given ImageParts
292
- func ReadImage ( parts ImageParts ) (v1.Image , error ) {
300
+ func ( r * Reader ) ReadImage ( ) (v1.Image , error ) {
293
301
// Special case: if we only have a tarball, we can instantiate the image
294
302
// directly from that. Otherwise, we'll process the image layers
295
303
// individually as specified in the config.
296
- if parts . ImageTarball != "" && parts .Config == "" {
297
- return tarball .ImageFromPath (parts .ImageTarball , nil )
304
+ if r . Parts . ImageTarball != "" && r . Parts .Config == "" {
305
+ return tarball .ImageFromPath (r . Parts .ImageTarball , nil )
298
306
}
299
307
300
- r := reader {parts : parts }
301
- r .layerLookup = make (map [v1.Hash ]v1.Layer )
308
+ if r .layerLookup == nil {
309
+ r .layerLookup = make (map [v1.Hash ]v1.Layer )
310
+ }
311
+ if r .loadedImageCache == nil {
312
+ r .loadedImageCache = make (map [v1.Hash ]bool )
313
+ }
302
314
if err := r .loadMetadata (); err != nil {
303
315
return nil , errors .Wrap (err , "unable to load image metadata" )
304
316
}
305
317
if err := r .loadForeignLayers (); err != nil {
306
318
return nil , errors .Wrap (err , "unable to load foreign layers specified in the base manifest" )
307
319
}
308
- if err := r .loadImages (r .parts .Images ); err != nil {
320
+ if err := r .loadImages (r .Parts .Images ); err != nil {
309
321
return nil , errors .Wrap (err , "unable to load layers from the images in the given image parts" )
310
322
}
311
323
if err := r .loadImgTarball (); err != nil {
@@ -318,12 +330,12 @@ func ReadImage(parts ImageParts) (v1.Image, error) {
318
330
for _ , diffID := range r .config .RootFS .DiffIDs {
319
331
layer , ok := r .layerLookup [diffID ]
320
332
if ! ok {
321
- return nil , errors .Errorf ("unable to locate layer with diffID %v as indicated in image config %s" , diffID , parts .Config )
333
+ return nil , errors .Errorf ("unable to locate layer with diffID %v as indicated in image config %s" , diffID , r . Parts .Config )
322
334
}
323
335
layers = append (layers , layer )
324
336
}
325
337
img := & legacyImage {
326
- configPath : parts .Config ,
338
+ configPath : r . Parts .Config ,
327
339
layers : layers ,
328
340
}
329
341
if err := img .init (); err != nil {
0 commit comments