Skip to content

Commit 77315f9

Browse files
authored
Merge pull request #3410 from jsternberg/dap-file-explorer-on-error
dap: collect references for inputs to ensure the file explorer works on an error
2 parents e540b7a + 17c2e1d commit 77315f9

2 files changed

Lines changed: 94 additions & 55 deletions

File tree

dap/thread.go

Lines changed: 70 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ type thread struct {
4949
// Attributes set when a thread is paused.
5050
cancel context.CancelCauseFunc // invoked when the thread is resumed
5151
rCtx *build.ResultHandle
52-
curPos digest.Digest
5352
stackTrace []int32
5453
}
5554

@@ -74,15 +73,16 @@ func (t *thread) Evaluate(ctx Context, c gateway.Client, headRef gateway.Referen
7473
}
7574

7675
var (
77-
ref gateway.Reference
78-
next = t.entrypoint
79-
err error
76+
ref gateway.Reference
77+
mounts map[string]gateway.Reference
78+
next = t.entrypoint
79+
err error
8080
)
8181
for next != nil {
8282
event := t.needsDebug(next, action, err)
8383
if event.Reason != "" {
8484
select {
85-
case action = <-t.pause(ctx, ref, err, next, event):
85+
case action = <-t.pause(ctx, ref, err, mounts, next, event):
8686
// do nothing here
8787
case <-ctx.Done():
8888
return context.Cause(ctx)
@@ -96,7 +96,7 @@ func (t *thread) Evaluate(ctx Context, c gateway.Client, headRef gateway.Referen
9696
if action == stepContinue {
9797
t.setBreakpoints(ctx)
9898
}
99-
ref, next, err = t.seekNext(ctx, next, action)
99+
ref, next, mounts, err = t.seekNext(ctx, next, action)
100100
}
101101
return nil
102102
}
@@ -285,26 +285,17 @@ func (t *thread) needsDebug(cur *step, step stepType, err error) (e dap.StoppedE
285285
return
286286
}
287287

288-
func (t *thread) pause(c Context, ref gateway.Reference, err error, pos *step, event dap.StoppedEventBody) <-chan stepType {
288+
func (t *thread) pause(c Context, ref gateway.Reference, err error, mounts map[string]gateway.Reference, pos *step, event dap.StoppedEventBody) <-chan stepType {
289289
t.mu.Lock()
290290
defer t.mu.Unlock()
291291

292292
if t.paused != nil {
293293
return t.paused
294294
}
295-
296295
t.paused = make(chan stepType, 1)
297-
if err != nil {
298-
var solveErr *errdefs.SolveError
299-
if errors.As(err, &solveErr) {
300-
if dt, err := solveErr.Op.MarshalVT(); err == nil {
301-
t.curPos = digest.FromBytes(dt)
302-
}
303-
}
304-
}
305296

306297
ctx, cancel := context.WithCancelCause(c)
307-
t.collectStackTrace(ctx, pos, ref)
298+
t.collectStackTrace(ctx, pos, mounts)
308299
t.cancel = cancel
309300

310301
if ref != nil || err != nil {
@@ -435,7 +426,7 @@ func (t *thread) setBreakpoints(ctx Context) {
435426
t.bps = t.breakpointMap.Intersect(ctx, t.def.Source, t.sourcePath)
436427
}
437428

438-
func (t *thread) seekNext(ctx Context, from *step, action stepType) (gateway.Reference, *step, error) {
429+
func (t *thread) seekNext(ctx Context, from *step, action stepType) (gateway.Reference, *step, map[string]gateway.Reference, error) {
439430
// If we're at the end, return no digest to signal that
440431
// we should conclude debugging.
441432
var target *step
@@ -452,12 +443,12 @@ func (t *thread) seekNext(ctx Context, from *step, action stepType) (gateway.Ref
452443
return t.seek(ctx, target)
453444
}
454445

455-
func (t *thread) seek(ctx Context, target *step) (ref gateway.Reference, result *step, err error) {
446+
func (t *thread) seek(ctx Context, target *step) (ref gateway.Reference, result *step, mounts map[string]gateway.Reference, err error) {
456447
if target != nil {
457448
if target.dgst != "" {
458-
ref, err = t.solve(ctx, target.dgst)
449+
ref, err = t.solve(ctx, target.dgst, 0)
459450
if err != nil {
460-
return ref, nil, err
451+
return ref, nil, nil, err
461452
}
462453
}
463454

@@ -468,31 +459,15 @@ func (t *thread) seek(ctx Context, target *step) (ref gateway.Reference, result
468459

469460
if ref != nil {
470461
if err = ref.Evaluate(ctx); err != nil {
471-
// If this is not a solve error, do not return the
472-
// reference and target step.
473-
var solveErr *errdefs.SolveError
474-
if errors.As(err, &solveErr) {
475-
if dt, err := solveErr.Op.MarshalVT(); err == nil {
476-
// Find the error digest.
477-
errDgst := digest.FromBytes(dt)
478-
479-
// Iterate from the first step to find the one
480-
// we failed on.
481-
result = t.entrypoint
482-
for result != nil {
483-
next := result.in
484-
if next != nil && next.dgst == errDgst {
485-
break
486-
}
487-
result = next
488-
}
489-
}
490-
} else {
491-
return nil, nil, err
462+
result, mounts = t.rewind(ctx, err)
463+
if result == nil {
464+
return nil, nil, nil, err
492465
}
466+
} else {
467+
mounts = map[string]gateway.Reference{"/": ref}
493468
}
494469
}
495-
return ref, result, err
470+
return ref, result, mounts, err
496471
}
497472

498473
func (t *thread) continueDigest(from *step) *step {
@@ -523,13 +498,15 @@ func (t *thread) continueDigest(from *step) *step {
523498
return next(from)
524499
}
525500

526-
func (t *thread) solve(ctx context.Context, target digest.Digest) (gateway.Reference, error) {
501+
func (t *thread) solve(ctx context.Context, target digest.Digest, index int64) (gateway.Reference, error) {
527502
if target == t.head {
528503
return t.ref, nil
529504
}
530505

531506
head := &pb.Op{
532-
Inputs: []*pb.Input{{Digest: string(target)}},
507+
Inputs: []*pb.Input{
508+
{Digest: string(target), Index: index},
509+
},
533510
}
534511
dt, err := head.MarshalVT()
535512
if err != nil {
@@ -567,12 +544,12 @@ func (t *thread) releaseState() {
567544
t.variables.Reset()
568545
}
569546

570-
func (t *thread) collectStackTrace(ctx context.Context, pos *step, ref gateway.Reference) {
547+
func (t *thread) collectStackTrace(ctx context.Context, pos *step, mounts map[string]gateway.Reference) {
571548
for pos != nil {
572549
frame := pos.frame
573-
frame.ExportVars(ctx, ref, t.variables)
550+
frame.ExportVars(ctx, mounts, t.variables)
574551
t.stackTrace = append(t.stackTrace, int32(frame.Id))
575-
pos, ref = pos.out, nil
552+
pos, mounts = pos.out, nil
576553
}
577554
}
578555

@@ -587,3 +564,48 @@ func (t *thread) hasFrame(id int) bool {
587564
_, ok := t.frames[int32(id)]
588565
return ok
589566
}
567+
568+
func (t *thread) rewind(ctx context.Context, err error) (result *step, mounts map[string]gateway.Reference) {
569+
var solveErr *errdefs.SolveError
570+
if !errors.As(err, &solveErr) {
571+
// If this is not a solve error, do not return the
572+
// reference and target step.
573+
return nil, nil
574+
}
575+
576+
dt, err := solveErr.Op.MarshalVT()
577+
if err != nil {
578+
return nil, nil
579+
}
580+
581+
// Find the error digest.
582+
errDgst := digest.FromBytes(dt)
583+
584+
// Iterate from the first step to find the one
585+
// we failed on.
586+
result = t.entrypoint
587+
for result != nil {
588+
next := result.in
589+
if next != nil && next.dgst == errDgst {
590+
break
591+
}
592+
result = next
593+
}
594+
595+
if exec, ok := solveErr.Op.GetOp().(*pb.Op_Exec); ok {
596+
mounts = make(map[string]gateway.Reference, len(exec.Exec.Mounts))
597+
for _, m := range exec.Exec.Mounts {
598+
if m.Input < 0 {
599+
continue
600+
}
601+
602+
// TODO: Use the correct input index for this.
603+
input := solveErr.Op.Inputs[m.Input]
604+
target, index := digest.Digest(input.Digest), input.Index
605+
if ref, err := t.solve(ctx, target, index); err == nil {
606+
mounts[m.Dest] = ref
607+
}
608+
}
609+
}
610+
return result, mounts
611+
}

dap/variables.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, ws string,
6767
}
6868
}
6969

70-
func (f *frame) ExportVars(ctx context.Context, ref gateway.Reference, refs *variableReferences) {
70+
func (f *frame) ExportVars(ctx context.Context, mounts map[string]gateway.Reference, refs *variableReferences) {
7171
f.fillVarsFromOp(f.op, refs)
72-
if ref != nil {
73-
f.fillVarsFromResult(ctx, ref, refs)
72+
if len(mounts) > 0 {
73+
f.fillVarsFromResult(ctx, mounts, refs)
7474
}
7575
}
7676

@@ -186,18 +186,23 @@ func execOpVars(exec *pb.ExecOp, refs *variableReferences) dap.Variable {
186186
}
187187
}
188188

189-
func (f *frame) fillVarsFromResult(ctx context.Context, ref gateway.Reference, refs *variableReferences) {
189+
func (f *frame) fillVarsFromResult(ctx context.Context, mounts map[string]gateway.Reference, refs *variableReferences) {
190190
f.scopes = append(f.scopes, dap.Scope{
191191
Name: "File Explorer",
192192
PresentationHint: "locals",
193193
VariablesReference: refs.New(func() []dap.Variable {
194-
return fsVars(ctx, ref, "/", refs)
194+
return fsVars(ctx, mounts, "/", refs)
195195
}),
196196
Expensive: true,
197197
})
198198
}
199199

200-
func fsVars(ctx context.Context, ref gateway.Reference, path string, vars *variableReferences) []dap.Variable {
200+
func fsVars(ctx context.Context, mounts map[string]gateway.Reference, path string, vars *variableReferences) []dap.Variable {
201+
path, ref := lookupPath(path, mounts)
202+
if ref == nil {
203+
return nil
204+
}
205+
201206
files, err := ref.ReadDir(ctx, gateway.ReadDirRequest{
202207
Path: path,
203208
})
@@ -228,7 +233,7 @@ func fsVars(ctx context.Context, ref gateway.Reference, path string, vars *varia
228233
return statVars(file)
229234
}),
230235
}
231-
return append([]dap.Variable{dvar}, fsVars(ctx, ref, fullpath, vars)...)
236+
return append([]dap.Variable{dvar}, fsVars(ctx, mounts, fullpath, vars)...)
232237
})
233238
fv.Value = ""
234239
} else {
@@ -436,3 +441,15 @@ func betterLocation(r *pb.Range, f *frame, next *step) bool {
436441
// Doesn't seem to be a better location.
437442
return false
438443
}
444+
445+
func lookupPath(path string, mounts map[string]gateway.Reference) (remainder string, ref gateway.Reference) {
446+
var prefix string
447+
for p, r := range mounts {
448+
if len(p) > len(prefix) && strings.HasPrefix(path, p) {
449+
prefix = p
450+
remainder, _ = filepath.Rel(prefix, p)
451+
ref = r
452+
}
453+
}
454+
return "/" + remainder, ref
455+
}

0 commit comments

Comments
 (0)