@@ -117,11 +117,11 @@ func ImagePartsFromArgs(config, baseManifest, imgTarball string, layers []string
117117 return result , nil
118118}
119119
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
121121// ImageParts object.
122- type reader struct {
122+ type Reader struct {
123123 // parts is the ImageParts being loaded.
124- parts ImageParts
124+ Parts ImageParts
125125 // baseManifest is the manifest of the very first base image in the chain
126126 // of images being loaded.
127127 baseManifest * v1.Manifest
@@ -130,32 +130,35 @@ type reader struct {
130130 // layerLookup is a map from the diffID of a layer to the layer
131131 // itself.
132132 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
133136}
134137
135138// loadMetadata loads the image metadata for the image parts in the given
136139// 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 )
139142 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 )
141144 }
142145 c , err := v1 .ParseConfigFile (cf )
143146 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 )
145148 }
146149 r .config = c
147- if r .parts .BaseManifest == "" {
150+ if r .Parts .BaseManifest == "" {
148151 // Base manifest is optional. It's only needed for images whose base
149152 // manifests have foreign layers.
150153 return nil
151154 }
152- mf , err := os .Open (r .parts .BaseManifest )
155+ mf , err := os .Open (r .Parts .BaseManifest )
153156 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 )
155158 }
156159 m , err := v1 .ParseManifest (mf )
157160 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 )
159162 }
160163 r .baseManifest = m
161164 return nil
@@ -209,7 +212,7 @@ func (l *foreignLayer) MediaType() (types.MediaType, error) {
209212
210213// loadForeignLayers loads the foreign layers from the base manifest in the
211214// given reader into the layer lookup.
212- func (r * reader ) loadForeignLayers () error {
215+ func (r * Reader ) loadForeignLayers () error {
213216 if r .baseManifest == nil {
214217 // No base manifest so no foreign layers to load.
215218 return nil
@@ -237,8 +240,12 @@ func (r *reader) loadForeignLayers() error {
237240
238241// loadImages loads the layers from the given images into the layers lookup
239242// in the given reader.
240- func (r * reader ) loadImages (images []v1.Image ) error {
243+ func (r * Reader ) loadImages (images []v1.Image ) error {
241244 for _ , img := range images {
245+ digest , _ := img .Digest ()
246+ if r .loadedImageCache [digest ] {
247+ continue
248+ }
242249 layers , err := img .Layers ()
243250 if err != nil {
244251 return errors .Wrap (err , "unable to get the layers in image" )
@@ -250,31 +257,32 @@ func (r *reader) loadImages(images []v1.Image) error {
250257 }
251258 r .layerLookup [diffID ] = l
252259 }
260+ r .loadedImageCache [digest ] = true
253261 }
254262 return nil
255263}
256264
257265// loadImgTarball loads the layers from the image tarball in the parts section
258266// of the given reader if one was specified into the layers lookup in the given
259267// reader.
260- func (r * reader ) loadImgTarball () error {
261- if r .parts .ImageTarball == "" {
268+ func (r * Reader ) loadImgTarball () error {
269+ if r .Parts .ImageTarball == "" {
262270 return nil
263271 }
264- img , err := tarball .ImageFromPath (r .parts .ImageTarball , nil )
272+ img , err := tarball .ImageFromPath (r .Parts .ImageTarball , nil )
265273 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 )
267275 }
268276 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 )
270278 }
271279 return nil
272280}
273281
274282// loadLayers loads layers specified as parts in the ImageParts section in the
275283// 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 {
278286 layer , err := l .V1Layer ()
279287 if err != nil {
280288 return errors .Wrap (err , "unable to build a v1.Layer from the specified parts" )
@@ -289,23 +297,27 @@ func (r *reader) loadLayers() error {
289297}
290298
291299// 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 ) {
293301 // Special case: if we only have a tarball, we can instantiate the image
294302 // directly from that. Otherwise, we'll process the image layers
295303 // 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 )
298306 }
299307
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+ }
302314 if err := r .loadMetadata (); err != nil {
303315 return nil , errors .Wrap (err , "unable to load image metadata" )
304316 }
305317 if err := r .loadForeignLayers (); err != nil {
306318 return nil , errors .Wrap (err , "unable to load foreign layers specified in the base manifest" )
307319 }
308- if err := r .loadImages (r .parts .Images ); err != nil {
320+ if err := r .loadImages (r .Parts .Images ); err != nil {
309321 return nil , errors .Wrap (err , "unable to load layers from the images in the given image parts" )
310322 }
311323 if err := r .loadImgTarball (); err != nil {
@@ -318,12 +330,12 @@ func ReadImage(parts ImageParts) (v1.Image, error) {
318330 for _ , diffID := range r .config .RootFS .DiffIDs {
319331 layer , ok := r .layerLookup [diffID ]
320332 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 )
322334 }
323335 layers = append (layers , layer )
324336 }
325337 img := & legacyImage {
326- configPath : parts .Config ,
338+ configPath : r . Parts .Config ,
327339 layers : layers ,
328340 }
329341 if err := img .init (); err != nil {
0 commit comments