123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package dockerfile
- import (
- "github.com/docker/docker/api/types/backend"
- "github.com/docker/docker/builder"
- "github.com/docker/docker/builder/remotecontext"
- dockerimage "github.com/docker/docker/image"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "golang.org/x/net/context"
- )
- type getAndMountFunc func(string, bool) (builder.Image, builder.ReleaseableLayer, error)
- // imageSources mounts images and provides a cache for mounted images. It tracks
- // all images so they can be unmounted at the end of the build.
- type imageSources struct {
- byImageID map[string]*imageMount
- mounts []*imageMount
- getImage getAndMountFunc
- cache pathCache // TODO: remove
- }
- // TODO @jhowardmsft LCOW Support: Eventually, platform can be moved to options.Options.Platform,
- // and removed from builderOptions, but that can't be done yet as it would affect the API.
- func newImageSources(ctx context.Context, options builderOptions) *imageSources {
- getAndMount := func(idOrRef string, localOnly bool) (builder.Image, builder.ReleaseableLayer, error) {
- pullOption := backend.PullOptionNoPull
- if !localOnly {
- if options.Options.PullParent {
- pullOption = backend.PullOptionForcePull
- } else {
- pullOption = backend.PullOptionPreferLocal
- }
- }
- return options.Backend.GetImageAndReleasableLayer(ctx, idOrRef, backend.GetImageAndLayerOptions{
- PullOption: pullOption,
- AuthConfig: options.Options.AuthConfigs,
- Output: options.ProgressWriter.Output,
- Platform: options.Platform,
- })
- }
- return &imageSources{
- byImageID: make(map[string]*imageMount),
- getImage: getAndMount,
- }
- }
- func (m *imageSources) Get(idOrRef string, localOnly bool) (*imageMount, error) {
- if im, ok := m.byImageID[idOrRef]; ok {
- return im, nil
- }
- image, layer, err := m.getImage(idOrRef, localOnly)
- if err != nil {
- return nil, err
- }
- im := newImageMount(image, layer)
- m.Add(im)
- return im, nil
- }
- func (m *imageSources) Unmount() (retErr error) {
- for _, im := range m.mounts {
- if err := im.unmount(); err != nil {
- logrus.Error(err)
- retErr = err
- }
- }
- return
- }
- func (m *imageSources) Add(im *imageMount) {
- switch im.image {
- case nil:
- im.image = &dockerimage.Image{}
- default:
- m.byImageID[im.image.ImageID()] = im
- }
- m.mounts = append(m.mounts, im)
- }
- // imageMount is a reference to an image that can be used as a builder.Source
- type imageMount struct {
- image builder.Image
- source builder.Source
- layer builder.ReleaseableLayer
- }
- func newImageMount(image builder.Image, layer builder.ReleaseableLayer) *imageMount {
- im := &imageMount{image: image, layer: layer}
- return im
- }
- func (im *imageMount) Source() (builder.Source, error) {
- if im.source == nil {
- if im.layer == nil {
- return nil, errors.Errorf("empty context")
- }
- mountPath, err := im.layer.Mount()
- if err != nil {
- return nil, errors.Wrapf(err, "failed to mount %s", im.image.ImageID())
- }
- source, err := remotecontext.NewLazySource(mountPath)
- if err != nil {
- return nil, errors.Wrapf(err, "failed to create lazycontext for %s", mountPath)
- }
- im.source = source
- }
- return im.source, nil
- }
- func (im *imageMount) unmount() error {
- if im.layer == nil {
- return nil
- }
- if err := im.layer.Release(); err != nil {
- return errors.Wrapf(err, "failed to unmount previous build image %s", im.image.ImageID())
- }
- im.layer = nil
- return nil
- }
- func (im *imageMount) Image() builder.Image {
- return im.image
- }
- func (im *imageMount) Layer() builder.ReleaseableLayer {
- return im.layer
- }
- func (im *imageMount) ImageID() string {
- return im.image.ImageID()
- }
|