github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/builder/dockerfile/imagecontext.go (about) 1 package dockerfile // import "github.com/demonoid81/moby/builder/dockerfile" 2 3 import ( 4 "context" 5 "runtime" 6 7 "github.com/containerd/containerd/platforms" 8 "github.com/demonoid81/moby/api/types/backend" 9 "github.com/demonoid81/moby/builder" 10 dockerimage "github.com/demonoid81/moby/image" 11 specs "github.com/opencontainers/image-spec/specs-go/v1" 12 "github.com/pkg/errors" 13 "github.com/sirupsen/logrus" 14 ) 15 16 type getAndMountFunc func(string, bool, *specs.Platform) (builder.Image, builder.ROLayer, 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, platform *specs.Platform) (builder.Image, builder.ROLayer, 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 return options.Backend.GetImageAndReleasableLayer(ctx, idOrRef, backend.GetImageAndLayerOptions{ 37 PullOption: pullOption, 38 AuthConfig: options.Options.AuthConfigs, 39 Output: options.ProgressWriter.Output, 40 Platform: platform, 41 }) 42 } 43 44 return &imageSources{ 45 byImageID: make(map[string]*imageMount), 46 getImage: getAndMount, 47 } 48 } 49 50 func (m *imageSources) Get(idOrRef string, localOnly bool, platform *specs.Platform) (*imageMount, error) { 51 if im, ok := m.byImageID[idOrRef]; ok { 52 return im, nil 53 } 54 55 image, layer, err := m.getImage(idOrRef, localOnly, platform) 56 if err != nil { 57 return nil, err 58 } 59 im := newImageMount(image, layer) 60 m.Add(im, platform) 61 return im, nil 62 } 63 64 func (m *imageSources) Unmount() (retErr error) { 65 for _, im := range m.mounts { 66 if err := im.unmount(); err != nil { 67 logrus.Error(err) 68 retErr = err 69 } 70 } 71 return 72 } 73 74 func (m *imageSources) Add(im *imageMount, platform *specs.Platform) { 75 switch im.image { 76 case nil: 77 // Set the platform for scratch images 78 if platform == nil { 79 p := platforms.DefaultSpec() 80 platform = &p 81 } 82 83 // Windows does not support scratch except for LCOW 84 os := platform.OS 85 if runtime.GOOS == "windows" { 86 os = "linux" 87 } 88 89 im.image = &dockerimage.Image{V1Image: dockerimage.V1Image{ 90 OS: os, 91 Architecture: platform.Architecture, 92 Variant: platform.Variant, 93 }} 94 default: 95 m.byImageID[im.image.ImageID()] = im 96 } 97 m.mounts = append(m.mounts, im) 98 } 99 100 // imageMount is a reference to an image that can be used as a builder.Source 101 type imageMount struct { 102 image builder.Image 103 layer builder.ROLayer 104 } 105 106 func newImageMount(image builder.Image, layer builder.ROLayer) *imageMount { 107 im := &imageMount{image: image, layer: layer} 108 return im 109 } 110 111 func (im *imageMount) unmount() error { 112 if im.layer == nil { 113 return nil 114 } 115 if err := im.layer.Release(); err != nil { 116 return errors.Wrapf(err, "failed to unmount previous build image %s", im.image.ImageID()) 117 } 118 im.layer = nil 119 return nil 120 } 121 122 func (im *imageMount) Image() builder.Image { 123 return im.image 124 } 125 126 func (im *imageMount) NewRWLayer() (builder.RWLayer, error) { 127 return im.layer.NewRWLayer() 128 } 129 130 func (im *imageMount) ImageID() string { 131 return im.image.ImageID() 132 }