mirror of https://github.com/knative/func.git
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:
parent
fe81e235d3
commit
cc063f79fc
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue