feat: improve docker build and push output (#1364)

Signed-off-by: Matej Vasek <mvasek@redhat.com>

Signed-off-by: Matej Vasek <mvasek@redhat.com>
This commit is contained in:
Matej Vasek 2022-10-21 16:10:17 +02:00 committed by GitHub
parent fe81e235d3
commit cc063f79fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 81 deletions

View File

@ -17,11 +17,13 @@ import (
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/daemon" "github.com/google/go-containerregistry/pkg/v1/daemon"
"github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote"
"golang.org/x/term"
) )
type Opt func(*Pusher) type Opt func(*Pusher)
@ -176,34 +178,19 @@ func (n *Pusher) daemonPush(ctx context.Context, f fn.Function, credentials Cred
var outBuff bytes.Buffer var outBuff bytes.Buffer
output = io.MultiWriter(&outBuff, output) output = io.MultiWriter(&outBuff, output)
decoder := json.NewDecoder(r) var isTerminal bool
li := logItem{} var fd uintptr
for { if outF, ok := output.(*os.File); ok {
err = decoder.Decode(&li) fd = outF.Fd()
isTerminal = term.IsTerminal(int(outF.Fd()))
}
err = jsonmessage.DisplayJSONMessagesStream(r, output, fd, isTerminal, nil)
if err != nil { if err != nil {
if errors.Is(err, io.EOF) { return "", err
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)
} }
digest = ParseDigest(outBuff.String()) return ParseDigest(outBuff.String()), nil
return digest, nil
} }
var digestRE = regexp.MustCompile(`digest:\s+(sha256:\w{64})`) var digestRE = regexp.MustCompile(`digest:\s+(sha256:\w{64})`)
@ -219,24 +206,6 @@ func ParseDigest(output string) string {
return "" 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) { func (n *Pusher) push(ctx context.Context, f fn.Function, credentials Credentials, output io.Writer) (digest string, err error) {
auth := &authn.Basic{ auth := &authn.Basic{
Username: credentials.Username, Username: credentials.Username,

View File

@ -3,7 +3,6 @@ package s2i
import ( import (
"archive/tar" "archive/tar"
"context" "context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -15,6 +14,7 @@ import (
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
dockerClient "github.com/docker/docker/client" dockerClient "github.com/docker/docker/client"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote"
@ -24,6 +24,7 @@ import (
"github.com/openshift/source-to-image/pkg/build/strategies" "github.com/openshift/source-to-image/pkg/build/strategies"
s2idocker "github.com/openshift/source-to-image/pkg/docker" s2idocker "github.com/openshift/source-to-image/pkg/docker"
"github.com/openshift/source-to-image/pkg/scm/git" "github.com/openshift/source-to-image/pkg/scm/git"
"golang.org/x/term"
fn "knative.dev/func" fn "knative.dev/func"
"knative.dev/func/builders" "knative.dev/func/builders"
@ -281,45 +282,14 @@ func (b *Builder) Build(ctx context.Context, f fn.Function) (err error) {
out = os.Stderr out = os.Stderr
} }
errMsg, err := parseBuildResponse(resp.Body, out) var isTerminal bool
if err != nil { var fd uintptr
return fmt.Errorf("cannot parse response body: %w", err) if outF, ok := out.(*os.File); ok {
} fd = outF.Fd()
if errMsg != "" { isTerminal = term.IsTerminal(int(outF.Fd()))
return fmt.Errorf("cannot build the app: %s", errMsg)
} }
return nil return jsonmessage.DisplayJSONMessagesStream(resp.Body, out, fd, isTerminal, 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
} }
func s2iScriptURL(ctx context.Context, cli DockerClient, image string) (string, error) { func s2iScriptURL(ctx context.Context, cli DockerClient, image string) (string, error) {