Skip to content

Commit 7a39d38

Browse files
committed
build: display build details link
Signed-off-by: CrazyMax <[email protected]>
1 parent 0758a9b commit 7a39d38

File tree

8 files changed

+137
-41
lines changed

8 files changed

+137
-41
lines changed

build/build.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/docker/buildx/builder"
2727
"github.com/docker/buildx/driver"
2828
"github.com/docker/buildx/localstate"
29+
"github.com/docker/buildx/util/desktop"
2930
"github.com/docker/buildx/util/dockerutil"
3031
"github.com/docker/buildx/util/imagetools"
3132
"github.com/docker/buildx/util/progress"
@@ -663,18 +664,18 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op
663664
return &so, releaseF, nil
664665
}
665666

666-
func Build(ctx context.Context, nodes []builder.Node, opt map[string]Options, docker *dockerutil.Client, configDir string, w progress.Writer) (resp map[string]*client.SolveResponse, err error) {
667+
func Build(ctx context.Context, nodes []builder.Node, opt map[string]Options, docker *dockerutil.Client, configDir string, w progress.Writer) (resp map[string]*client.SolveResponse, bd map[string]desktop.BuildDetails, err error) {
667668
return BuildWithResultHandler(ctx, nodes, opt, docker, configDir, w, nil)
668669
}
669670

670-
func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[string]Options, docker *dockerutil.Client, configDir string, w progress.Writer, resultHandleFunc func(driverIndex int, rCtx *ResultContext)) (resp map[string]*client.SolveResponse, err error) {
671+
func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[string]Options, docker *dockerutil.Client, configDir string, w progress.Writer, resultHandleFunc func(driverIndex int, rCtx *ResultContext)) (resp map[string]*client.SolveResponse, bd map[string]desktop.BuildDetails, err error) {
671672
if len(nodes) == 0 {
672-
return nil, errors.Errorf("driver required for build")
673+
return nil, nil, errors.Errorf("driver required for build")
673674
}
674675

675676
nodes, err = filterAvailableNodes(nodes)
676677
if err != nil {
677-
return nil, errors.Wrapf(err, "no valid drivers found")
678+
return nil, nil, errors.Wrapf(err, "no valid drivers found")
678679
}
679680

680681
var noMobyDriver driver.Driver
@@ -706,7 +707,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
706707

707708
m, clients, err := resolveDrivers(ctx, nodes, opt, w)
708709
if err != nil {
709-
return nil, err
710+
return nil, nil, err
710711
}
711712

712713
defers := make([]func(), 0, 2)
@@ -737,7 +738,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
737738
return docker.LoadImage(ctx, name, w)
738739
})
739740
if err != nil {
740-
return nil, err
741+
return nil, nil, err
741742
}
742743
for k, v := range gitattrs {
743744
so.FrontendAttrs[k] = v
@@ -761,7 +762,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
761762
for _, e := range dp.so.Exports {
762763
if e.Type == "moby" {
763764
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
764-
return nil, errors.Errorf("multi-node push can't currently be performed with the docker driver, please switch to a different driver")
765+
return nil, nil, errors.Errorf("multi-node push can't currently be performed with the docker driver, please switch to a different driver")
765766
}
766767
}
767768
}
@@ -778,7 +779,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
778779
k2 := strings.TrimPrefix(v, "target:")
779780
dps2, ok := m[k2]
780781
if !ok {
781-
return nil, errors.Errorf("failed to find target %s for context %s", k2, strings.TrimPrefix(k, "context:")) // should be validated before already
782+
return nil, nil, errors.Errorf("failed to find target %s for context %s", k2, strings.TrimPrefix(k, "context:")) // should be validated before already
782783
}
783784
var found bool
784785
for _, dp2 := range dps2 {
@@ -788,15 +789,17 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
788789
}
789790
}
790791
if !found {
791-
return nil, errors.Errorf("failed to use %s as context %s for %s because targets build with different drivers", k2, strings.TrimPrefix(k, "context:"), name)
792+
return nil, nil, errors.Errorf("failed to use %s as context %s for %s because targets build with different drivers", k2, strings.TrimPrefix(k, "context:"), name)
792793
}
793794
}
794795
}
795796
}
796797
}
797798

798799
resp = map[string]*client.SolveResponse{}
800+
bd = map[string]desktop.BuildDetails{}
799801
var respMu sync.Mutex
802+
var bdMu sync.Mutex
800803
results := waitmap.New()
801804

802805
multiTarget := len(opt) > 1
@@ -822,6 +825,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
822825

823826
for i, dp := range dps {
824827
i, dp, so := i, dp, *dp.so
828+
node := nodes[dp.driverIndex]
825829
if multiDriver {
826830
for i, e := range so.Exports {
827831
switch e.Type {
@@ -925,6 +929,15 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
925929
}
926930
return nil, err
927931
}
932+
if node.Driver.Features(ctx)[driver.HistoryAPI] && desktop.BuildBackendEnabled() {
933+
bdMu.Lock()
934+
bd[k] = desktop.BuildDetails{
935+
Builder: node.Builder,
936+
Node: node.Name,
937+
Ref: so.Ref,
938+
}
939+
bdMu.Unlock()
940+
}
928941
if opt.PrintFunc != nil {
929942
printRes = res.Metadata
930943
}
@@ -1114,15 +1127,15 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
11141127
return nil
11151128
}(k)
11161129
if err != nil {
1117-
return nil, err
1130+
return nil, bd, err
11181131
}
11191132
}
11201133

11211134
if err := eg.Wait(); err != nil {
1122-
return nil, err
1135+
return nil, bd, err
11231136
}
11241137

1125-
return resp, nil
1138+
return resp, bd, nil
11261139
}
11271140

11281141
func pushWithMoby(ctx context.Context, d driver.Driver, name string, l progress.SubLogger) error {

commands/bake.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/docker/buildx/util/buildflags"
1414
"github.com/docker/buildx/util/cobrautil/completion"
1515
"github.com/docker/buildx/util/confutil"
16+
"github.com/docker/buildx/util/desktop"
1617
"github.com/docker/buildx/util/dockerutil"
1718
"github.com/docker/buildx/util/progress"
1819
"github.com/docker/buildx/util/tracing"
@@ -191,7 +192,10 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
191192
return nil
192193
}
193194

194-
resp, err := build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), printer)
195+
resp, bd, err := build.Build(ctx, nodes, bo, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), printer)
196+
if cFlags.progress != progress.PrinterModeQuiet {
197+
desktop.PrintBuildDetails(bd)
198+
}
195199
if err != nil {
196200
return wrapBuildError(err, true)
197201
}

commands/build.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/docker/buildx/store"
2727
"github.com/docker/buildx/store/storeutil"
2828
"github.com/docker/buildx/util/buildflags"
29+
"github.com/docker/buildx/util/desktop"
2930
"github.com/docker/buildx/util/ioset"
3031
"github.com/docker/buildx/util/progress"
3132
"github.com/docker/buildx/util/tracing"
@@ -259,23 +260,28 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
259260
}
260261

261262
var resp *client.SolveResponse
263+
var bd map[string]desktop.BuildDetails
262264
var retErr error
263265
if isExperimental() {
264266
resp, retErr = runControllerBuild(ctx, dockerCli, opts, options, printer)
265267
} else {
266-
resp, retErr = runBasicBuild(ctx, dockerCli, opts, options, printer)
268+
resp, bd, retErr = runBasicBuild(ctx, dockerCli, opts, options, printer)
267269
}
268270

269271
if err := printer.Wait(); retErr == nil {
270272
retErr = err
271273
}
274+
if progressMode != progress.PrinterModeQuiet {
275+
desktop.PrintBuildDetails(bd)
276+
}
272277
if retErr != nil {
273278
return retErr
274279
}
275280

276-
if options.quiet {
281+
if progressMode == progress.PrinterModeQuiet {
277282
fmt.Println(getImageID(resp.ExporterResponse))
278283
}
284+
279285
if options.imageIDFile != "" {
280286
if err := os.WriteFile(options.imageIDFile, []byte(getImageID(resp.ExporterResponse)), 0644); err != nil {
281287
return errors.Wrap(err, "writing image ID file")
@@ -303,9 +309,9 @@ func getImageID(resp map[string]string) string {
303309
return dgst
304310
}
305311

306-
func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, error) {
307-
resp, _, err := cbuild.RunBuild(ctx, dockerCli, *opts, os.Stdin, printer, false)
308-
return resp, err
312+
func runBasicBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, map[string]desktop.BuildDetails, error) {
313+
resp, bd, _, err := cbuild.RunBuild(ctx, dockerCli, *opts, os.Stdin, printer, false)
314+
return resp, bd, err
309315
}
310316

311317
func runControllerBuild(ctx context.Context, dockerCli command.Cli, opts *controllerapi.BuildOptions, options buildOptions, printer *progress.Printer) (*client.SolveResponse, error) {

controller/build/build.go

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/docker/buildx/store/storeutil"
1616
"github.com/docker/buildx/util/buildflags"
1717
"github.com/docker/buildx/util/confutil"
18+
"github.com/docker/buildx/util/desktop"
1819
"github.com/docker/buildx/util/dockerutil"
1920
"github.com/docker/buildx/util/platformutil"
2021
"github.com/docker/buildx/util/progress"
@@ -36,9 +37,9 @@ const defaultTargetName = "default"
3637
// NOTE: When an error happens during the build and this function acquires the debuggable *build.ResultContext,
3738
// this function returns it in addition to the error (i.e. it does "return nil, res, err"). The caller can
3839
// inspect the result and debug the cause of that error.
39-
func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.BuildOptions, inStream io.Reader, progress progress.Writer, generateResult bool) (*client.SolveResponse, *build.ResultContext, error) {
40+
func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.BuildOptions, inStream io.Reader, progress progress.Writer, generateResult bool) (*client.SolveResponse, map[string]desktop.BuildDetails, *build.ResultContext, error) {
4041
if in.NoCache && len(in.NoCacheFilter) > 0 {
41-
return nil, nil, errors.Errorf("--no-cache and --no-cache-filter cannot currently be used together")
42+
return nil, nil, nil, errors.Errorf("--no-cache and --no-cache-filter cannot currently be used together")
4243
}
4344

4445
contexts := map[string]build.NamedContext{}
@@ -68,7 +69,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
6869

6970
platforms, err := platformutil.Parse(in.Platforms)
7071
if err != nil {
71-
return nil, nil, err
72+
return nil, nil, nil, err
7273
}
7374
opts.Platforms = platforms
7475

@@ -77,7 +78,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
7778

7879
secrets, err := controllerapi.CreateSecrets(in.Secrets)
7980
if err != nil {
80-
return nil, nil, err
81+
return nil, nil, nil, err
8182
}
8283
opts.Session = append(opts.Session, secrets)
8384

@@ -87,17 +88,17 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
8788
}
8889
ssh, err := controllerapi.CreateSSH(sshSpecs)
8990
if err != nil {
90-
return nil, nil, err
91+
return nil, nil, nil, err
9192
}
9293
opts.Session = append(opts.Session, ssh)
9394

9495
outputs, err := controllerapi.CreateExports(in.Exports)
9596
if err != nil {
96-
return nil, nil, err
97+
return nil, nil, nil, err
9798
}
9899
if in.ExportPush {
99100
if in.ExportLoad {
100-
return nil, nil, errors.Errorf("push and load may not be set together at the moment")
101+
return nil, nil, nil, errors.Errorf("push and load may not be set together at the moment")
101102
}
102103
if len(outputs) == 0 {
103104
outputs = []client.ExportEntry{{
@@ -111,7 +112,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
111112
case "image":
112113
outputs[0].Attrs["push"] = "true"
113114
default:
114-
return nil, nil, errors.Errorf("push and %q output can't be used together", outputs[0].Type)
115+
return nil, nil, nil, errors.Errorf("push and %q output can't be used together", outputs[0].Type)
115116
}
116117
}
117118
}
@@ -125,7 +126,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
125126
switch outputs[0].Type {
126127
case "docker":
127128
default:
128-
return nil, nil, errors.Errorf("load and %q output can't be used together", outputs[0].Type)
129+
return nil, nil, nil, errors.Errorf("load and %q output can't be used together", outputs[0].Type)
129130
}
130131
}
131132
}
@@ -140,7 +141,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
140141

141142
allow, err := buildflags.ParseEntitlements(in.Allow)
142143
if err != nil {
143-
return nil, nil, err
144+
return nil, nil, nil, err
144145
}
145146
opts.Allow = allow
146147

@@ -163,51 +164,52 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in controllerapi.Build
163164
builder.WithContextPathHash(contextPathHash),
164165
)
165166
if err != nil {
166-
return nil, nil, err
167+
return nil, nil, nil, err
167168
}
168169
if err = updateLastActivity(dockerCli, b.NodeGroup); err != nil {
169-
return nil, nil, errors.Wrapf(err, "failed to update builder last activity time")
170+
return nil, nil, nil, errors.Wrapf(err, "failed to update builder last activity time")
170171
}
171172
nodes, err := b.LoadNodes(ctx, false)
172173
if err != nil {
173-
return nil, nil, err
174+
return nil, nil, nil, err
174175
}
175176

176-
resp, res, err := buildTargets(ctx, dockerCli, b.NodeGroup, nodes, map[string]build.Options{defaultTargetName: opts}, progress, generateResult)
177+
resp, bd, res, err := buildTargets(ctx, dockerCli, b.NodeGroup, nodes, map[string]build.Options{defaultTargetName: opts}, progress, generateResult)
177178
err = wrapBuildError(err, false)
178179
if err != nil {
179180
// NOTE: buildTargets can return *build.ResultContext even on error.
180-
return nil, res, err
181+
return nil, bd, res, err
181182
}
182-
return resp, res, nil
183+
return resp, bd, res, nil
183184
}
184185

185186
// buildTargets runs the specified build and returns the result.
186187
//
187188
// NOTE: When an error happens during the build and this function acquires the debuggable *build.ResultContext,
188189
// this function returns it in addition to the error (i.e. it does "return nil, res, err"). The caller can
189190
// inspect the result and debug the cause of that error.
190-
func buildTargets(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, nodes []builder.Node, opts map[string]build.Options, progress progress.Writer, generateResult bool) (*client.SolveResponse, *build.ResultContext, error) {
191+
func buildTargets(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, nodes []builder.Node, opts map[string]build.Options, progress progress.Writer, generateResult bool) (*client.SolveResponse, map[string]desktop.BuildDetails, *build.ResultContext, error) {
191192
var res *build.ResultContext
192193
var resp map[string]*client.SolveResponse
194+
var bd map[string]desktop.BuildDetails
193195
var err error
194196
if generateResult {
195197
var mu sync.Mutex
196198
var idx int
197-
resp, err = build.BuildWithResultHandler(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), progress, func(driverIndex int, gotRes *build.ResultContext) {
199+
resp, bd, err = build.BuildWithResultHandler(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), progress, func(driverIndex int, gotRes *build.ResultContext) {
198200
mu.Lock()
199201
defer mu.Unlock()
200202
if res == nil || driverIndex < idx {
201203
idx, res = driverIndex, gotRes
202204
}
203205
})
204206
} else {
205-
resp, err = build.Build(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), progress)
207+
resp, bd, err = build.Build(ctx, nodes, opts, dockerutil.NewClient(dockerCli), confutil.ConfigDir(dockerCli), progress)
206208
}
207209
if err != nil {
208-
return nil, res, err
210+
return nil, bd, res, err
209211
}
210-
return resp[defaultTargetName], res, err
212+
return resp[defaultTargetName], bd, res, err
211213
}
212214

213215
func wrapBuildError(err error, bake bool) error {

controller/local/controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (b *localController) Build(ctx context.Context, options controllerapi.Build
4848
}
4949
defer b.buildOnGoing.Store(false)
5050

51-
resp, res, buildErr := cbuild.RunBuild(ctx, b.dockerCli, options, in, progress, true)
51+
resp, _, res, buildErr := cbuild.RunBuild(ctx, b.dockerCli, options, in, progress, true)
5252
// NOTE: RunBuild can return *build.ResultContext even on error.
5353
if res != nil {
5454
b.buildConfig = buildConfig{

controller/remote/controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ func serveCmd(dockerCli command.Cli) *cobra.Command {
149149

150150
// prepare server
151151
b := NewServer(func(ctx context.Context, options *controllerapi.BuildOptions, stdin io.Reader, progress progress.Writer) (*client.SolveResponse, *build.ResultContext, error) {
152-
return cbuild.RunBuild(ctx, dockerCli, *options, stdin, progress, true)
152+
resp, _, res, buildErr := cbuild.RunBuild(ctx, dockerCli, *options, stdin, progress, true)
153+
return resp, res, buildErr
153154
})
154155
defer b.Close()
155156

0 commit comments

Comments
 (0)