Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions build/invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
gateway "github.com/moby/buildkit/frontend/gateway/client"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/tonistiigi/fsutil/types"
)

type InvokeConfig struct {
Expand Down Expand Up @@ -145,6 +146,18 @@ func (c *Container) Exec(ctx context.Context, cfg *InvokeConfig, stdin io.ReadCl
return err
}

func (c *Container) ReadFile(ctx context.Context, req gateway.ReadContainerRequest) ([]byte, error) {
return c.container.ReadFile(ctx, req)
}

func (c *Container) ReadDir(ctx context.Context, req gateway.ReadDirContainerRequest) ([]*types.Stat, error) {
return c.container.ReadDir(ctx, req)
}

func (c *Container) StatFile(ctx context.Context, req gateway.StatContainerRequest) (*types.Stat, error) {
return c.container.StatFile(ctx, req)
}

func exec(ctx context.Context, resultCtx *ResultHandle, cfg *InvokeConfig, ctr gateway.Container, stdin io.ReadCloser, stdout io.WriteCloser, stderr io.WriteCloser) error {
processCfg, err := resultCtx.getProcessConfig(cfg, stdin, stdout, stderr)
if err != nil {
Expand Down
94 changes: 87 additions & 7 deletions dap/thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import (
"github.com/google/go-dap"
"github.com/moby/buildkit/client/llb"
gateway "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/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/tonistiigi/fsutil/types"
"golang.org/x/sync/errgroup"
)

Expand Down Expand Up @@ -323,16 +325,12 @@ func (t *thread) pause(c Context, k string, refs map[string]gateway.Reference, e
}
t.paused = make(chan stepType, 1)

t.prepareResultHandle(c, k, refs, err)

ctx, cancel := context.WithCancelCause(c)
t.collectStackTrace(ctx, pos, refs)
t.cancel = cancel

// Used for exec. Only works if there was an error or if the step returns
// a root mount.
if ref, ok := refs[k]; ok || err != nil {
t.prepareResultHandle(c, ref, err)
}

event.ThreadId = t.id
c.C() <- &dap.StoppedEvent{
Event: dap.Event{Event: "stopped"},
Expand All @@ -341,7 +339,15 @@ func (t *thread) pause(c Context, k string, refs map[string]gateway.Reference, e
return t.paused
}

func (t *thread) prepareResultHandle(c Context, ref gateway.Reference, err error) {
func (t *thread) prepareResultHandle(c Context, k string, refs map[string]gateway.Reference, err error) {
var ref gateway.Reference
if err == nil {
var ok bool
if ref, ok = refs[k]; !ok {
return
}
}

// Create a context for cancellations and make the cancel function
// block on the wait group.
var wg sync.WaitGroup
Expand All @@ -353,6 +359,31 @@ func (t *thread) prepareResultHandle(c Context, ref gateway.Reference, err error

t.rCtx = build.NewResultHandle(ctx, t.c, ref, t.meta, err)

if err != nil {
gwcaps := t.c.BuildOpts().Caps

var solveErr *errdefs.SolveError
// If we had a solve error and the exec filesystem capability, we can
// get the filesystem mounts used in the actual build rather than only the input
// mounts.
if gwcaps.Supports(gwpb.CapGatewayExecFilesystem) == nil && errors.As(err, &solveErr) {
if exec, ok := solveErr.Op.Op.(*pb.Op_Exec); ok {
rCtx := t.rCtx

getContainer := sync.OnceValues(func() (*build.Container, error) {
return build.NewContainer(c, rCtx, &build.InvokeConfig{})
})

for i, m := range exec.Exec.Mounts {
refs[m.Dest] = &mountReference{
getContainer: getContainer,
index: i,
}
}
}
}
}

// Start the attach. Use the context we created and perform it in
// a goroutine. We aren't necessarily assuming this will actually work.
wg.Go(func() {
Expand Down Expand Up @@ -678,3 +709,52 @@ func (t *thread) rewind(ctx Context, inErr error) (k string, result *step, mount
}
return k, result, mounts, inErr
}

type mountReference struct {
getContainer func() (*build.Container, error)
index int
}

func (r *mountReference) ToState() (llb.State, error) {
return llb.State{}, errors.New("unimplemented")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add method name to unimplemented message

}

func (r *mountReference) Evaluate(ctx context.Context) error {
return nil
}

func (r *mountReference) ReadFile(ctx context.Context, req gateway.ReadRequest) ([]byte, error) {
ctr, err := r.getContainer()
if err != nil {
return nil, err
}

return ctr.ReadFile(ctx, gateway.ReadContainerRequest{
ReadRequest: req,
MountIndex: r.index,
})
}

func (r *mountReference) StatFile(ctx context.Context, req gateway.StatRequest) (*types.Stat, error) {
ctr, err := r.getContainer()
if err != nil {
return nil, err
}

return ctr.StatFile(ctx, gateway.StatContainerRequest{
StatRequest: req,
MountIndex: r.index,
})
}

func (r *mountReference) ReadDir(ctx context.Context, req gateway.ReadDirRequest) ([]*types.Stat, error) {
ctr, err := r.getContainer()
if err != nil {
return nil, err
}

return ctr.ReadDir(ctx, gateway.ReadDirContainerRequest{
ReadDirRequest: req,
MountIndex: r.index,
})
}