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 }