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