From abbda4e94136cf69b84e175c2d9d8f17ed4a8195 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 21 Apr 2020 21:40:44 -0700 Subject: [PATCH] errdefs: attach source to an error Signed-off-by: Tonis Tiigi --- cmd/buildctl/build.go | 4 +++ frontend/dockerfile/builder/build.go | 40 +++++++++++++++++++++++++++- solver/errdefs/grpc.go | 10 ++++++- solver/errdefs/source.go | 29 ++++++++++++++++++++ 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 solver/errdefs/source.go diff --git a/cmd/buildctl/build.go b/cmd/buildctl/build.go index b88df2117..716ab1f3b 100644 --- a/cmd/buildctl/build.go +++ b/cmd/buildctl/build.go @@ -304,6 +304,10 @@ func buildAction(clicontext *cli.Context) error { if errors.As(err, &ve) { log.Printf("error-vertex: %s", ve.Digest) } + + for _, s := range errdefs.Sources(err) { + log.Printf("source: %+v", s) + } } return err diff --git a/frontend/dockerfile/builder/build.go b/frontend/dockerfile/builder/build.go index efcf7d851..89e5056dd 100644 --- a/frontend/dockerfile/builder/build.go +++ b/frontend/dockerfile/builder/build.go @@ -19,8 +19,10 @@ import ( "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb" + "github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/moby/buildkit/frontend/gateway/client" gwpb "github.com/moby/buildkit/frontend/gateway/pb" + "github.com/moby/buildkit/solver/errdefs" "github.com/moby/buildkit/solver/pb" "github.com/moby/buildkit/util/apicaps" specs "github.com/opencontainers/image-spec/specs-go/v1" @@ -132,9 +134,11 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { var buildContext *llb.State isNotLocalContext := false + isNotLocalDockerfile := false if st, ok := detectGitContext(opts[localNameContext], opts[keyContextKeepGitDir]); ok { if !forceLocalDockerfile { src = *st + isNotLocalDockerfile = true } buildContext = st } else if httpPrefix.MatchString(opts[localNameContext]) { @@ -184,6 +188,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { bc := unpack.AddMount("/out", llb.Scratch()) if !forceLocalDockerfile { src = bc + isNotLocalDockerfile = true } buildContext = &bc } @@ -191,6 +196,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { filename = "context" if !forceLocalDockerfile { src = httpContext + isNotLocalDockerfile = true } buildContext = &httpContext isNotLocalContext = true @@ -205,6 +211,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { inputDockerfile, ok := inputs[DefaultLocalNameDockerfile] if ok { src = inputDockerfile + isNotLocalDockerfile = true } } @@ -338,7 +345,16 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { for i, tp := range targetPlatforms { func(i int, tp *specs.Platform) { - eg.Go(func() error { + eg.Go(func() (err error) { + defer func() { + var el *parser.ErrorLocation + if errors.As(err, &el) { + if isNotLocalDockerfile { + localNameDockerfile = "" + } + err = wrapSource(err, dtDockerfile, filename, localNameDockerfile, el.Ranges) + } + }() st, img, err := dockerfile2llb.Dockerfile2LLB(ctx, dtDockerfile, dockerfile2llb.ConvertOpt{ Target: opts[keyTarget], MetaResolver: c, @@ -639,3 +655,25 @@ func scopeToSubDir(c *llb.State, fileop bool, dir string) *llb.State { bc := unpack.AddMount("/out", llb.Scratch()) return &bc } + +func wrapSource(err error, dt []byte, filename, local string, locations []parser.Range) error { + s := errdefs.Source{ + Data: dt, + Filename: filename, + Local: local, + Locations: make([]*errdefs.Range, 0, len(locations)), + } + for _, l := range locations { + s.Locations = append(s.Locations, &errdefs.Range{ + Start: &errdefs.Position{ + Line: int32(l.Start.Line), + Character: int32(l.Start.Character), + }, + End: &errdefs.Position{ + Line: int32(l.End.Line), + Character: int32(l.End.Character), + }, + }) + } + return errdefs.WithSource(err, s) +} diff --git a/solver/errdefs/grpc.go b/solver/errdefs/grpc.go index 374545eab..e6de6968d 100644 --- a/solver/errdefs/grpc.go +++ b/solver/errdefs/grpc.go @@ -30,6 +30,10 @@ func ToGRPC(err error) error { details = append(details, st) } + for _, st := range Sources(err) { + details = append(details, st) + } + var ve *VertexError if errors.As(err, &ve) { details = append(details, &ve.Vertex) @@ -111,7 +115,7 @@ func FromGRPC(err error) error { continue } switch detail.Message.(type) { - case *Stack, *Vertex: + case *Stack, *Vertex, *Source: details = append(details, detail.Message) default: n.Details = append(n.Details, d) @@ -128,6 +132,10 @@ func FromGRPC(err error) error { } case *Vertex: err = WrapVertex(err, digest.Digest(v.Digest)) + case *Source: + if v != nil { + err = WithSource(err, *v) + } } } diff --git a/solver/errdefs/source.go b/solver/errdefs/source.go new file mode 100644 index 000000000..be0cddbed --- /dev/null +++ b/solver/errdefs/source.go @@ -0,0 +1,29 @@ +package errdefs + +import "github.com/pkg/errors" + +func WithSource(err error, src Source) error { + if err == nil { + return nil + } + return &ErrorSource{Source: src, error: err} +} + +type ErrorSource struct { + Source + error +} + +func (e *ErrorSource) Unwrap() error { + return e.error +} + +func Sources(err error) []*Source { + var out []*Source + var es *ErrorSource + if errors.As(err, &es) { + out = Sources(es.Unwrap()) + out = append(out, &es.Source) + } + return out +}