github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/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/containerd/containerd/platforms"
     8  	"github.com/docker/docker/api/types/backend"
     9  	"github.com/docker/docker/builder"
    10  	dockerimage "github.com/docker/docker/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  }