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