github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+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/builder/fscache"
    13  	"github.com/docker/docker/image"
    14  	"github.com/docker/docker/pkg/stringid"
    15  	"github.com/pkg/errors"
    16  	"golang.org/x/sync/errgroup"
    17  	"google.golang.org/grpc"
    18  )
    19  
    20  // ImageComponent provides an interface for working with images
    21  type ImageComponent interface {
    22  	SquashImage(from string, to string) (string, error)
    23  	TagImageWithReference(image.ID, reference.Named) error
    24  }
    25  
    26  // Builder defines interface for running a build
    27  type Builder interface {
    28  	Build(context.Context, backend.BuildConfig) (*builder.Result, error)
    29  }
    30  
    31  // Backend provides build functionality to the API router
    32  type Backend struct {
    33  	builder        Builder
    34  	fsCache        *fscache.FSCache
    35  	imageComponent ImageComponent
    36  	buildkit       *buildkit.Builder
    37  }
    38  
    39  // NewBackend creates a new build backend from components
    40  func NewBackend(components ImageComponent, builder Builder, fsCache *fscache.FSCache, buildkit *buildkit.Builder) (*Backend, error) {
    41  	return &Backend{imageComponent: components, builder: builder, fsCache: fsCache, buildkit: buildkit}, nil
    42  }
    43  
    44  // RegisterGRPC registers buildkit controller to the grpc server.
    45  func (b *Backend) RegisterGRPC(s *grpc.Server) {
    46  	if b.buildkit != nil {
    47  		b.buildkit.RegisterGRPC(s)
    48  	}
    49  }
    50  
    51  // Build builds an image from a Source
    52  func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
    53  	options := config.Options
    54  	useBuildKit := options.Version == types.BuilderBuildKit
    55  
    56  	tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
    57  	if err != nil {
    58  		return "", err
    59  	}
    60  
    61  	var build *builder.Result
    62  	if useBuildKit {
    63  		build, err = b.buildkit.Build(ctx, config)
    64  		if err != nil {
    65  			return "", err
    66  		}
    67  	} else {
    68  		build, err = b.builder.Build(ctx, config)
    69  		if err != nil {
    70  			return "", err
    71  		}
    72  	}
    73  
    74  	if build == nil {
    75  		return "", nil
    76  	}
    77  
    78  	var imageID = build.ImageID
    79  	if options.Squash {
    80  		if imageID, err = squashBuild(build, b.imageComponent); err != nil {
    81  			return "", err
    82  		}
    83  		if config.ProgressWriter.AuxFormatter != nil {
    84  			if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
    85  				return "", err
    86  			}
    87  		}
    88  	}
    89  
    90  	if !useBuildKit {
    91  		stdout := config.ProgressWriter.StdoutFormatter
    92  		fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
    93  	}
    94  	if imageID != "" {
    95  		err = tagger.TagImages(image.ID(imageID))
    96  	}
    97  	return imageID, err
    98  }
    99  
   100  // PruneCache removes all cached build sources
   101  func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
   102  	eg, ctx := errgroup.WithContext(ctx)
   103  
   104  	var fsCacheSize uint64
   105  	eg.Go(func() error {
   106  		var err error
   107  		fsCacheSize, err = b.fsCache.Prune(ctx)
   108  		if err != nil {
   109  			return errors.Wrap(err, "failed to prune fscache")
   110  		}
   111  		return nil
   112  	})
   113  
   114  	var buildCacheSize int64
   115  	var cacheIDs []string
   116  	eg.Go(func() error {
   117  		var err error
   118  		buildCacheSize, cacheIDs, err = b.buildkit.Prune(ctx, opts)
   119  		if err != nil {
   120  			return errors.Wrap(err, "failed to prune build cache")
   121  		}
   122  		return nil
   123  	})
   124  
   125  	if err := eg.Wait(); err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
   130  }
   131  
   132  // Cancel cancels the build by ID
   133  func (b *Backend) Cancel(ctx context.Context, id string) error {
   134  	return b.buildkit.Cancel(ctx, id)
   135  }
   136  
   137  func squashBuild(build *builder.Result, imageComponent ImageComponent) (string, error) {
   138  	var fromID string
   139  	if build.FromImage != nil {
   140  		fromID = build.FromImage.ImageID()
   141  	}
   142  	imageID, err := imageComponent.SquashImage(build.ImageID, fromID)
   143  	if err != nil {
   144  		return "", errors.Wrap(err, "error squashing image")
   145  	}
   146  	return imageID, nil
   147  }