From ed4103ef52d17fb05f075807d0a855f835ae9415 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Sat, 18 Dec 2021 22:08:43 -0800 Subject: [PATCH] commands: build summary of warnings on build Signed-off-by: Tonis Tiigi --- commands/build.go | 46 +++++++++++++++++++++++++++++++++++ go.mod | 1 + util/logutil/pause.go | 52 ++++++++++++++++++++++++++++++++++++++++ util/progress/printer.go | 17 +++++++++---- vendor/modules.txt | 1 + 5 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 util/logutil/pause.go diff --git a/commands/build.go b/commands/build.go index 4bce23fc..dae6d326 100644 --- a/commands/build.go +++ b/commands/build.go @@ -1,9 +1,11 @@ package commands import ( + "bytes" "context" "encoding/json" "fmt" + "io" "os" "path/filepath" "strings" @@ -22,7 +24,9 @@ import ( "github.com/docker/go-units" "github.com/moby/buildkit/client" "github.com/moby/buildkit/session/auth/authprovider" + "github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/util/appcontext" + "github.com/morikuni/aec" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -245,9 +249,51 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, opts map[string]bu } } + printWarnings(os.Stderr, printer.Warnings(), progressMode) + return resp[defaultTargetName].ExporterResponse["containerimage.digest"], err } +func printWarnings(w io.Writer, warnings []client.VertexWarning, mode string) { + if len(warnings) == 0 || mode == progress.PrinterModeQuiet { + return + } + fmt.Fprintf(w, "\n ") + sb := &bytes.Buffer{} + if len(warnings) == 1 { + fmt.Fprintf(sb, "1 warning found") + } else { + fmt.Fprintf(sb, "%d warnings found", len(warnings)) + } + if logrus.GetLevel() < logrus.DebugLevel { + fmt.Fprintf(sb, " (use --debug to expand)") + } + fmt.Fprintf(sb, ":\n") + fmt.Fprint(w, aec.Apply(sb.String(), aec.YellowF)) + + for _, warn := range warnings { + fmt.Fprintf(w, " - %s\n", warn.Short) + if logrus.GetLevel() < logrus.DebugLevel { + continue + } + for _, d := range warn.Detail { + fmt.Fprintf(w, "%s\n", d) + } + if warn.URL != "" { + fmt.Fprintf(w, "More info: %s\n", warn.URL) + } + if warn.SourceInfo != nil && warn.Range != nil { + src := errdefs.Source{ + Info: warn.SourceInfo, + Ranges: warn.Range, + } + src.Print(w) + } + fmt.Fprintf(w, "\n") + + } +} + func newBuildOptions() buildOptions { ulimits := make(map[string]*units.Ulimit) return buildOptions{ diff --git a/go.mod b/go.mod index dde85209..c2699bfd 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/moby/buildkit v0.9.1-0.20211215010209-539be1708964 + github.com/morikuni/aec v1.0.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.2-0.20210819154149-5ad6f50d6283 github.com/pelletier/go-toml v1.9.4 diff --git a/util/logutil/pause.go b/util/logutil/pause.go new file mode 100644 index 00000000..930dca21 --- /dev/null +++ b/util/logutil/pause.go @@ -0,0 +1,52 @@ +package logutil + +import ( + "bytes" + "io" + "sync" + + "github.com/sirupsen/logrus" +) + +func Pause(l *logrus.Logger) func() { + // initialize formatter with original terminal settings + l.Formatter.Format(logrus.NewEntry(l)) + + bw := newBufferedWriter(l.Out) + l.SetOutput(bw) + return func() { + bw.resume() + } +} + +type bufferedWriter struct { + mu sync.Mutex + buf *bytes.Buffer + w io.Writer +} + +func newBufferedWriter(w io.Writer) *bufferedWriter { + return &bufferedWriter{ + buf: bytes.NewBuffer(nil), + w: w, + } +} + +func (bw *bufferedWriter) Write(p []byte) (int, error) { + bw.mu.Lock() + defer bw.mu.Unlock() + if bw.buf == nil { + return bw.w.Write(p) + } + return bw.buf.Write(p) +} + +func (bw *bufferedWriter) resume() { + bw.mu.Lock() + defer bw.mu.Unlock() + if bw.buf == nil { + return + } + io.Copy(bw.w, bw.buf) + bw.buf = nil +} diff --git a/util/progress/printer.go b/util/progress/printer.go index 7292fda8..ba346b5b 100644 --- a/util/progress/printer.go +++ b/util/progress/printer.go @@ -7,8 +7,10 @@ import ( "os" "github.com/containerd/console" + "github.com/docker/buildx/util/logutil" "github.com/moby/buildkit/client" "github.com/moby/buildkit/util/progress/progressui" + "github.com/sirupsen/logrus" ) const ( @@ -19,9 +21,10 @@ const ( ) type Printer struct { - status chan *client.SolveStatus - done <-chan struct{} - err error + status chan *client.SolveStatus + done <-chan struct{} + err error + warnings []client.VertexWarning } func (p *Printer) Wait() error { @@ -34,6 +37,10 @@ func (p *Printer) Write(s *client.SolveStatus) { p.status <- s } +func (p *Printer) Warnings() []client.VertexWarning { + return p.warnings +} + func NewPrinter(ctx context.Context, out console.File, mode string) *Printer { statusCh := make(chan *client.SolveStatus) doneCh := make(chan struct{}) @@ -58,8 +65,10 @@ func NewPrinter(ctx context.Context, out console.File, mode string) *Printer { c = cons } } + resumeLogs := logutil.Pause(logrus.StandardLogger()) // not using shared context to not disrupt display but let is finish reporting errors - _, pw.err = progressui.DisplaySolveStatus(ctx, "", c, w, statusCh) + pw.warnings, pw.err = progressui.DisplaySolveStatus(ctx, "", c, w, statusCh) + resumeLogs() close(doneCh) }() return pw diff --git a/vendor/modules.txt b/vendor/modules.txt index d99bd463..360b2221 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -354,6 +354,7 @@ github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.1 github.com/modern-go/reflect2 # github.com/morikuni/aec v1.0.0 +## explicit github.com/morikuni/aec # github.com/opencontainers/go-digest v1.0.0 ## explicit