Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/docker/buildx/builder"
"github.com/docker/buildx/driver"
"github.com/docker/buildx/localstate"
"github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/util/dockerutil"
"github.com/docker/buildx/util/imagetools"
"github.com/docker/buildx/util/progress"
Expand Down Expand Up @@ -822,6 +823,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s

for i, dp := range dps {
i, dp, so := i, dp, *dp.so
node := nodes[dp.driverIndex]
if multiDriver {
for i, e := range so.Exports {
switch e.Type {
Expand Down Expand Up @@ -940,6 +942,16 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
} else {
rr, err = c.Build(ctx, so, "buildx", buildFunc, ch)
}
if node.Driver.Features(ctx)[driver.HistoryAPI] && desktop.BuildBackendEnabled() {
buildRef := fmt.Sprintf("%s/%s/%s", node.Builder, node.Name, so.Ref)
if err != nil {
return &desktop.ErrorWithBuildRef{
Ref: buildRef,
Err: err,
}
}
progress.WriteBuildRef(w, k, buildRef)
}
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/buildx/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

"github.com/docker/buildx/commands"
"github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/version"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli-plugins/manager"
Expand Down Expand Up @@ -86,6 +87,9 @@ func main() {
} else {
fmt.Fprintf(cmd.Err(), "ERROR: %v\n", err)
}
if ebr, ok := err.(*desktop.ErrorWithBuildRef); ok {
ebr.Print(cmd.Err())
}

os.Exit(1)
}
10 changes: 10 additions & 0 deletions commands/bake.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import (
"fmt"
"os"

"github.com/containerd/console"
"github.com/containerd/containerd/platforms"
"github.com/docker/buildx/bake"
"github.com/docker/buildx/build"
"github.com/docker/buildx/builder"
"github.com/docker/buildx/util/buildflags"
"github.com/docker/buildx/util/cobrautil/completion"
"github.com/docker/buildx/util/confutil"
"github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/util/dockerutil"
"github.com/docker/buildx/util/progress"
"github.com/docker/buildx/util/tracing"
Expand Down Expand Up @@ -117,6 +119,11 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
progressTextDesc = fmt.Sprintf("building with %q instance using %s driver", b.Name, b.Driver)
}

var term bool
if _, err := console.ConsoleFromFile(os.Stderr); err == nil {
term = true
}

printer, err := progress.NewPrinter(ctx2, os.Stderr, os.Stderr, cFlags.progress,
progress.WithDesc(progressTextDesc, progressConsoleDesc),
)
Expand All @@ -130,6 +137,9 @@ func runBake(dockerCli command.Cli, targets []string, in bakeOptions, cFlags com
if err == nil {
err = err1
}
if err == nil && cFlags.progress != progress.PrinterModeQuiet {
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
}
}
}()

Expand Down
10 changes: 9 additions & 1 deletion commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/docker/buildx/store"
"github.com/docker/buildx/store/storeutil"
"github.com/docker/buildx/util/buildflags"
"github.com/docker/buildx/util/desktop"
"github.com/docker/buildx/util/ioset"
"github.com/docker/buildx/util/progress"
"github.com/docker/buildx/util/tracing"
Expand Down Expand Up @@ -238,6 +239,11 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
return err
}

var term bool
if _, err := console.ConsoleFromFile(os.Stderr); err == nil {
term = true
}

ctx2, cancel := context.WithCancel(context.TODO())
defer cancel()
progressMode, err := options.toProgress()
Expand Down Expand Up @@ -273,7 +279,9 @@ func runBuild(dockerCli command.Cli, options buildOptions) (err error) {
return retErr
}

if options.quiet {
if progressMode != progress.PrinterModeQuiet {
desktop.PrintBuildDetails(os.Stderr, printer.BuildRefs(), term)
} else {
fmt.Println(getImageID(resp.ExporterResponse))
}
if options.imageIDFile != "" {
Expand Down
4 changes: 4 additions & 0 deletions controller/pb/progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func (w *writer) Write(status *client.SolveStatus) {
w.ch <- ToControlStatus(status)
}

func (w *writer) WriteBuildRef(target string, ref string) {
return
}

func (w *writer) ValidateLogSource(digest.Digest, interface{}) bool {
return true
}
Expand Down
86 changes: 86 additions & 0 deletions util/desktop/desktop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package desktop

import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"sync"

"github.com/containerd/console"
)

var (
bbEnabledOnce sync.Once
bbEnabled bool
)

func BuildBackendEnabled() bool {
bbEnabledOnce.Do(func() {
home, err := os.UserHomeDir()
if err != nil {
return
}
_, err = os.Stat(filepath.Join(home, ".docker", "desktop-build", ".lastaccess"))
bbEnabled = err == nil
})
return bbEnabled
}

func BuildDetailsOutput(refs map[string]string, term bool) string {
if len(refs) == 0 {
return ""
}
refURL := func(ref string) string {
return fmt.Sprintf("docker-desktop://dashboard/build/%s", ref)
}
var out bytes.Buffer
out.WriteString("View build details: ")
multiTargets := len(refs) > 1
for target, ref := range refs {
if multiTargets {
out.WriteString(fmt.Sprintf("\n %s: ", target))
}
if term {
out.WriteString(hyperlink(refURL(ref)))
} else {
out.WriteString(refURL(ref))
}
}
return out.String()
}

func PrintBuildDetails(w io.Writer, refs map[string]string, term bool) {
if out := BuildDetailsOutput(refs, term); out != "" {
fmt.Fprintf(w, "\n%s\n", out)
}
}

func hyperlink(url string) string {
// create an escape sequence using the OSC 8 format: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
return fmt.Sprintf("\033]8;;%s\033\\%s\033]8;;\033\\", url, url)
}

type ErrorWithBuildRef struct {
Ref string
Err error
Msg string
}

func (e *ErrorWithBuildRef) Error() string {
return e.Err.Error()
}

func (e *ErrorWithBuildRef) Unwrap() error {
return e.Err
}

func (e *ErrorWithBuildRef) Print(w io.Writer) error {
var term bool
if _, err := console.ConsoleFromFile(os.Stderr); err == nil {
term = true
}
fmt.Fprintf(w, "\n%s", BuildDetailsOutput(map[string]string{"default": e.Ref}, term))
return nil
}
18 changes: 18 additions & 0 deletions util/progress/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ type Printer struct {
warnings []client.VertexWarning
logMu sync.Mutex
logSourceMap map[digest.Digest]interface{}

// TODO: remove once we can use result context to pass build ref
// see https://github.com/docker/buildx/pull/1861
buildRefsMu sync.Mutex
buildRefs map[string]string
}

func (p *Printer) Wait() error {
Expand Down Expand Up @@ -143,6 +148,19 @@ func NewPrinter(ctx context.Context, w io.Writer, out console.File, mode string,
return pw, nil
}

func (p *Printer) WriteBuildRef(target string, ref string) {
p.buildRefsMu.Lock()
defer p.buildRefsMu.Unlock()
if p.buildRefs == nil {
p.buildRefs = map[string]string{}
}
p.buildRefs[target] = ref
}

func (p *Printer) BuildRefs() map[string]string {
return p.buildRefs
}

type printerOpts struct {
displayOpts []progressui.DisplaySolveStatusOpt

Expand Down
5 changes: 5 additions & 0 deletions util/progress/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

type Writer interface {
Write(*client.SolveStatus)
WriteBuildRef(string, string)
ValidateLogSource(digest.Digest, interface{}) bool
ClearLogSource(interface{})
}
Expand Down Expand Up @@ -41,6 +42,10 @@ func Write(w Writer, name string, f func() error) {
})
}

func WriteBuildRef(w Writer, target string, ref string) {
w.WriteBuildRef(target, ref)
}

func NewChannel(w Writer) (chan *client.SolveStatus, chan struct{}) {
ch := make(chan *client.SolveStatus)
done := make(chan struct{})
Expand Down