github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/builder/dockerfile/imagecontext.go (about) 1 package dockerfile // import "github.com/docker/docker/builder/dockerfile" 2 3 import ( 4 "context" 5 "runtime" 6 7 "github.com/docker/docker/api/types/backend" 8 "github.com/docker/docker/builder" 9 dockerimage "github.com/docker/docker/image" 10 specs "github.com/opencontainers/image-spec/specs-go/v1" 11 "github.com/pkg/errors" 12 "github.com/sirupsen/logrus" 13 ) 14 15 type getAndMountFunc func(string, bool, *specs.Platform) (builder.Image, builder.ROLayer, error) 16 17 // imageSources mounts images and provides a cache for mounted images. It tracks 18 // all images so they can be unmounted at the end of the build. 19 type imageSources struct { 20 byImageID map[string]*imageMount 21 mounts []*imageMount 22 getImage getAndMountFunc 23 } 24 25 func newImageSources(ctx context.Context, options builderOptions) *imageSources { 26 getAndMount := func(idOrRef string, localOnly bool, platform *specs.Platform) (builder.Image, builder.ROLayer, error) { 27 pullOption := backend.PullOptionNoPull 28 if !localOnly { 29 if options.Options.PullParent { 30 pullOption = backend.PullOptionForcePull 31 } else { 32 pullOption = backend.PullOptionPreferLocal 33 } 34 } 35 return options.Backend.GetImageAndReleasableLayer(ctx, idOrRef, backend.GetImageAndLayerOptions{ 36 PullOption: pullOption, 37 AuthConfig: options.Options.AuthConfigs, 38 Output: options.ProgressWriter.Output, 39 Platform: platform, 40 }) 41 } 42 43 return &imageSources{ 44 byImageID: make(map[string]*imageMount), 45 getImage: getAndMount, 46 } 47 } 48 49 func (m *imageSources) Get(idOrRef string, localOnly bool, platform *specs.Platform) (*imageMount, error) { 50 if im, ok := m.byImageID[idOrRef]; ok { 51 return im, nil 52 } 53 54 image, layer, err := m.getImage(idOrRef, localOnly, platform) 55 if err != nil { 56 return nil, err 57 } 58 im := newImageMount(image, layer) 59 m.Add(im) 60 return im, nil 61 } 62 63 func (m *imageSources) Unmount() (retErr error) { 64 for _, im := range m.mounts { 65 if err := im.unmount(); err != nil { 66 logrus.Error(err) 67 retErr = err 68 } 69 } 70 return 71 } 72 73 func (m *imageSources) Add(im *imageMount) { 74 switch im.image { 75 case nil: 76 // set the OS for scratch images 77 os := runtime.GOOS 78 // Windows does not support scratch except for LCOW 79 if runtime.GOOS == "windows" { 80 os = "linux" 81 } 82 im.image = &dockerimage.Image{V1Image: dockerimage.V1Image{OS: os}} 83 default: 84 m.byImageID[im.image.ImageID()] = im 85 } 86 m.mounts = append(m.mounts, im) 87 } 88 89 // imageMount is a reference to an image that can be used as a builder.Source 90 type imageMount struct { 91 image builder.Image 92 source builder.Source 93 layer builder.ROLayer 94 } 95 96 func newImageMount(image builder.Image, layer builder.ROLayer) *imageMount { 97 im := &imageMount{image: image, layer: layer} 98 return im 99 } 100 101 func (im *imageMount) unmount() error { 102 if im.layer == nil { 103 return nil 104 } 105 if err := im.layer.Release(); err != nil { 106 return errors.Wrapf(err, "failed to unmount previous build image %s", im.image.ImageID()) 107 } 108 im.layer = nil 109 return nil 110 } 111 112 func (im *imageMount) Image() builder.Image { 113 return im.image 114 } 115 116 func (im *imageMount) NewRWLayer() (builder.RWLayer, error) { 117 return im.layer.NewRWLayer() 118 } 119 120 func (im *imageMount) ImageID() string { 121 return im.image.ImageID() 122 }