github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/api/server/backend/build/backend.go (about)

     1  package build // import "github.com/docker/docker/api/server/backend/build"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/docker/distribution/reference"
     8  	"github.com/docker/docker/api/types"
     9  	"github.com/docker/docker/api/types/backend"
    10  	"github.com/docker/docker/builder"
    11  	buildkit "github.com/docker/docker/builder/builder-next"
    12  	"github.com/docker/docker/image"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/pkg/errors"
    15  	"google.golang.org/grpc"
    16  )
    17  
    18  // ImageComponent provides an interface for working with images
    19  type ImageComponent interface {
    20  	SquashImage(from string, to string) (string, error)
    21  	TagImageWithReference(image.ID, reference.Named) error
    22  }
    23  
    24  // Builder defines interface for running a build
    25  type Builder interface {
    26  	Build(context.Context, backend.BuildConfig) (*builder.Result, error)
    27  }
    28  
    29  // Backend provides build functionality to the API router
    30  type Backend struct {
    31  	builder        Builder
    32  	imageComponent ImageComponent
    33  	buildkit       *buildkit.Builder
    34  }
    35  
    36  // NewBackend creates a new build backend from components
    37  func NewBackend(components ImageComponent, builder Builder, buildkit *buildkit.Builder) (*Backend, error) {
    38  	return &Backend{imageComponent: components, builder: builder, buildkit: buildkit}, nil
    39  }
    40  
    41  // RegisterGRPC registers buildkit controller to the grpc server.
    42  func (b *Backend) RegisterGRPC(s *grpc.Server) {
    43  	if b.buildkit != nil {
    44  		b.buildkit.RegisterGRPC(s)
    45  	}
    46  }
    47  
    48  // Build builds an image from a Source
    49  func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
    50  	options := config.Options
    51  	useBuildKit := options.Version == types.BuilderBuildKit
    52  
    53  	tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
    54  	if err != nil {
    55  		return "", err
    56  	}
    57  
    58  	var build *builder.Result
    59  	if useBuildKit {
    60  		build, err = b.buildkit.Build(ctx, config)
    61  		if err != nil {
    62  			return "", err
    63  		}
    64  	} else {
    65  		build, err = b.builder.Build(ctx, config)
    66  		if err != nil {
    67  			return "", err
    68  		}
    69  	}
    70  
    71  	if build == nil {
    72  		return "", nil
    73  	}
    74  
    75  	var imageID = build.ImageID
    76  	if options.Squash {
    77  		if imageID, err = squashBuild(build, b.imageComponent); err != nil {
    78  			return "", err
    79  		}
    80  		if config.ProgressWriter.AuxFormatter != nil {
    81  			if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
    82  				return "", err
    83  			}
    84  		}
    85  	}
    86  
    87  	if !useBuildKit {
    88  		stdout := config.ProgressWriter.StdoutFormatter
    89  		fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
    90  	}
    91  	if imageID != "" {
    92  		err = tagger.TagImages(image.ID(imageID))
    93  	}
    94  	return imageID, err
    95  }
    96  
    97  // PruneCache removes all cached build sources
    98  func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
    99  	buildCacheSize, cacheIDs, err := b.buildkit.Prune(ctx, opts)
   100  	if err != nil {
   101  		return nil, errors.Wrap(err, "failed to prune build cache")
   102  	}
   103  	return &types.BuildCachePruneReport{SpaceReclaimed: uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
   104  }
   105  
   106  // Cancel cancels the build by ID
   107  func (b *Backend) Cancel(ctx context.Context, id string) error {
   108  	return b.buildkit.Cancel(ctx, id)
   109  }
   110  
   111  func squashBuild(build *builder.Result, imageComponent ImageComponent) (string, error) {
   112  	var fromID string
   113  	if build.FromImage != nil {
   114  		fromID = build.FromImage.ImageID()
   115  	}
   116  	imageID, err := imageComponent.SquashImage(build.ImageID, fromID)
   117  	if err != nil {
   118  		return "", errors.Wrap(err, "error squashing image")
   119  	}
   120  	return imageID, nil
   121  }