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  }