mirror of
https://github.com/docker/buildx.git
synced 2024-11-22 15:37:16 +08:00
a50e89c38e
The NewPrinter function is mostly borrowed from buildkit. However, at some point, it seems that the implementations drifted. This patch updates buildx to be more similar in behavior to it's buildkit counterpart, specifically, it will explicitly fail if a TTY output is requested using "--progress=tty", but the output is not available. To gracefully fallback to plain progress in this scenario, "--progress=plain" is required. Signed-off-by: Justin Chadwell <me@jedevc.com>
110 lines
2.3 KiB
Go
110 lines
2.3 KiB
Go
package progress
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/containerd/console"
|
|
"github.com/docker/buildx/util/logutil"
|
|
"github.com/moby/buildkit/client"
|
|
"github.com/moby/buildkit/util/progress/progressui"
|
|
"github.com/opencontainers/go-digest"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
PrinterModeAuto = "auto"
|
|
PrinterModeTty = "tty"
|
|
PrinterModePlain = "plain"
|
|
PrinterModeQuiet = "quiet"
|
|
)
|
|
|
|
type Printer struct {
|
|
status chan *client.SolveStatus
|
|
done <-chan struct{}
|
|
err error
|
|
warnings []client.VertexWarning
|
|
logMu sync.Mutex
|
|
logSourceMap map[digest.Digest]interface{}
|
|
}
|
|
|
|
func (p *Printer) Wait() error {
|
|
close(p.status)
|
|
<-p.done
|
|
return p.err
|
|
}
|
|
|
|
func (p *Printer) Write(s *client.SolveStatus) {
|
|
p.status <- s
|
|
}
|
|
|
|
func (p *Printer) Warnings() []client.VertexWarning {
|
|
return p.warnings
|
|
}
|
|
|
|
func (p *Printer) ValidateLogSource(dgst digest.Digest, v interface{}) bool {
|
|
p.logMu.Lock()
|
|
defer p.logMu.Unlock()
|
|
src, ok := p.logSourceMap[dgst]
|
|
if ok {
|
|
if src == v {
|
|
return true
|
|
}
|
|
} else {
|
|
p.logSourceMap[dgst] = v
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (p *Printer) ClearLogSource(v interface{}) {
|
|
p.logMu.Lock()
|
|
defer p.logMu.Unlock()
|
|
for d := range p.logSourceMap {
|
|
if p.logSourceMap[d] == v {
|
|
delete(p.logSourceMap, d)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewPrinter(ctx context.Context, w io.Writer, out console.File, mode string) (*Printer, error) {
|
|
statusCh := make(chan *client.SolveStatus)
|
|
doneCh := make(chan struct{})
|
|
|
|
pw := &Printer{
|
|
status: statusCh,
|
|
done: doneCh,
|
|
logSourceMap: map[digest.Digest]interface{}{},
|
|
}
|
|
|
|
if v := os.Getenv("BUILDKIT_PROGRESS"); v != "" && mode == PrinterModeAuto {
|
|
mode = v
|
|
}
|
|
|
|
var c console.Console
|
|
switch mode {
|
|
case PrinterModeQuiet:
|
|
w = io.Discard
|
|
case PrinterModeAuto, PrinterModeTty:
|
|
if cons, err := console.ConsoleFromFile(out); err == nil {
|
|
c = cons
|
|
} else {
|
|
if mode == PrinterModeTty {
|
|
return nil, errors.Wrap(err, "failed to get console")
|
|
}
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
resumeLogs := logutil.Pause(logrus.StandardLogger())
|
|
// not using shared context to not disrupt display but let is finish reporting errors
|
|
pw.warnings, pw.err = progressui.DisplaySolveStatus(ctx, "", c, w, statusCh)
|
|
resumeLogs()
|
|
close(doneCh)
|
|
}()
|
|
return pw, nil
|
|
}
|