From cc063f79fcedb3597fd762e1426438442cc7d47a Mon Sep 17 00:00:00 2001 From: Matej Vasek Date: Fri, 21 Oct 2022 16:10:17 +0200 Subject: [PATCH] feat: improve docker build and push output (#1364) Signed-off-by: Matej Vasek Signed-off-by: Matej Vasek --- docker/pusher.go | 55 +++++++++++------------------------------------- s2i/builder.go | 46 +++++++--------------------------------- 2 files changed, 20 insertions(+), 81 deletions(-) diff --git a/docker/pusher.go b/docker/pusher.go index 29262774d..c16cad562 100644 --- a/docker/pusher.go +++ b/docker/pusher.go @@ -17,11 +17,13 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/client" + "github.com/docker/docker/pkg/jsonmessage" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/daemon" "github.com/google/go-containerregistry/pkg/v1/remote" + "golang.org/x/term" ) type Opt func(*Pusher) @@ -176,34 +178,19 @@ func (n *Pusher) daemonPush(ctx context.Context, f fn.Function, credentials Cred var outBuff bytes.Buffer output = io.MultiWriter(&outBuff, output) - decoder := json.NewDecoder(r) - li := logItem{} - for { - err = decoder.Decode(&li) - if err != nil { - if errors.Is(err, io.EOF) { - err = nil - } - break - } - if li.Error != "" { - return "", errors.New(li.ErrorDetail.Message) - } - if li.Id != "" { - fmt.Fprintf(output, "%s: ", li.Id) - } - var percent int - if li.ProgressDetail.Total == 0 { - percent = 100 - } else { - percent = (li.ProgressDetail.Current * 100) / li.ProgressDetail.Total - } - fmt.Fprintf(output, "%s (%d%%)\n", li.Status, percent) + var isTerminal bool + var fd uintptr + if outF, ok := output.(*os.File); ok { + fd = outF.Fd() + isTerminal = term.IsTerminal(int(outF.Fd())) } - digest = ParseDigest(outBuff.String()) + err = jsonmessage.DisplayJSONMessagesStream(r, output, fd, isTerminal, nil) + if err != nil { + return "", err + } - return digest, nil + return ParseDigest(outBuff.String()), nil } var digestRE = regexp.MustCompile(`digest:\s+(sha256:\w{64})`) @@ -219,24 +206,6 @@ func ParseDigest(output string) string { return "" } -type errorDetail struct { - Message string `json:"message"` -} - -type progressDetail struct { - Current int `json:"current"` - Total int `json:"total"` -} - -type logItem struct { - Id string `json:"id"` - Status string `json:"status"` - Error string `json:"error"` - ErrorDetail errorDetail `json:"errorDetail"` - Progress string `json:"progress"` - ProgressDetail progressDetail `json:"progressDetail"` -} - func (n *Pusher) push(ctx context.Context, f fn.Function, credentials Credentials, output io.Writer) (digest string, err error) { auth := &authn.Basic{ Username: credentials.Username, diff --git a/s2i/builder.go b/s2i/builder.go index ac8511688..38aae095d 100644 --- a/s2i/builder.go +++ b/s2i/builder.go @@ -3,7 +3,6 @@ package s2i import ( "archive/tar" "context" - "encoding/json" "errors" "fmt" "io" @@ -15,6 +14,7 @@ import ( "github.com/docker/docker/api/types" dockerClient "github.com/docker/docker/client" + "github.com/docker/docker/pkg/jsonmessage" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" @@ -24,6 +24,7 @@ import ( "github.com/openshift/source-to-image/pkg/build/strategies" s2idocker "github.com/openshift/source-to-image/pkg/docker" "github.com/openshift/source-to-image/pkg/scm/git" + "golang.org/x/term" fn "knative.dev/func" "knative.dev/func/builders" @@ -281,45 +282,14 @@ func (b *Builder) Build(ctx context.Context, f fn.Function) (err error) { out = os.Stderr } - errMsg, err := parseBuildResponse(resp.Body, out) - if err != nil { - return fmt.Errorf("cannot parse response body: %w", err) - } - if errMsg != "" { - return fmt.Errorf("cannot build the app: %s", errMsg) + var isTerminal bool + var fd uintptr + if outF, ok := out.(*os.File); ok { + fd = outF.Fd() + isTerminal = term.IsTerminal(int(outF.Fd())) } - return nil -} - -func parseBuildResponse(r io.Reader, w io.Writer) (errorMessage string, err error) { - obj := struct { - ErrorDetail struct { - Message string `json:"message"` - } `json:"errorDetail"` - Stream string `json:"stream"` - }{} - d := json.NewDecoder(r) - for { - err = d.Decode(&obj) - if err != nil { - if errors.Is(err, io.EOF) { - break - } - return "", err - } - if obj.ErrorDetail.Message != "" { - errorMessage = obj.ErrorDetail.Message - return errorMessage, nil - } - if obj.Stream != "" { - _, err = w.Write([]byte(obj.Stream)) - if err != nil { - return "", err - } - } - } - return "", nil + return jsonmessage.DisplayJSONMessagesStream(resp.Body, out, fd, isTerminal, nil) } func s2iScriptURL(ctx context.Context, cli DockerClient, image string) (string, error) {