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 }