Merge pull request #3450 from jsternberg/dap-container-fs-requests
dap: utilize the container filesystem for the file explorer
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
|||||||
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/tonistiigi/fsutil/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InvokeConfig struct {
|
type InvokeConfig struct {
|
||||||
@@ -145,6 +146,18 @@ func (c *Container) Exec(ctx context.Context, cfg *InvokeConfig, stdin io.ReadCl
|
|||||||
return err
|
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 {
|
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)
|
processCfg, err := resultCtx.getProcessConfig(cfg, stdin, stdout, stderr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+87
-7
@@ -12,10 +12,12 @@ import (
|
|||||||
"github.com/google/go-dap"
|
"github.com/google/go-dap"
|
||||||
"github.com/moby/buildkit/client/llb"
|
"github.com/moby/buildkit/client/llb"
|
||||||
gateway "github.com/moby/buildkit/frontend/gateway/client"
|
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/errdefs"
|
||||||
"github.com/moby/buildkit/solver/pb"
|
"github.com/moby/buildkit/solver/pb"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tonistiigi/fsutil/types"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -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.paused = make(chan stepType, 1)
|
||||||
|
|
||||||
|
t.prepareResultHandle(c, k, refs, err)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancelCause(c)
|
ctx, cancel := context.WithCancelCause(c)
|
||||||
t.collectStackTrace(ctx, pos, refs)
|
t.collectStackTrace(ctx, pos, refs)
|
||||||
t.cancel = cancel
|
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
|
event.ThreadId = t.id
|
||||||
c.C() <- &dap.StoppedEvent{
|
c.C() <- &dap.StoppedEvent{
|
||||||
Event: dap.Event{Event: "stopped"},
|
Event: dap.Event{Event: "stopped"},
|
||||||
@@ -341,7 +339,15 @@ func (t *thread) pause(c Context, k string, refs map[string]gateway.Reference, e
|
|||||||
return t.paused
|
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
|
// Create a context for cancellations and make the cancel function
|
||||||
// block on the wait group.
|
// block on the wait group.
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -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)
|
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
|
// Start the attach. Use the context we created and perform it in
|
||||||
// a goroutine. We aren't necessarily assuming this will actually work.
|
// a goroutine. We aren't necessarily assuming this will actually work.
|
||||||
wg.Go(func() {
|
wg.Go(func() {
|
||||||
@@ -689,3 +720,52 @@ func (t *thread) rewind(ctx Context, inErr error) (k string, result *step, mount
|
|||||||
}
|
}
|
||||||
return k, result, mounts, inErr
|
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, cannot use ToState with mount reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user