Merge pull request #3709 from jsternberg/dap-loaded-source-path

dap: properly map source paths to client side paths
This commit is contained in:
Tõnis Tiigi
2026-03-10 18:08:19 -07:00
committed by GitHub
6 changed files with 182 additions and 76 deletions
+5 -6
View File
@@ -7,7 +7,6 @@ import (
"fmt"
"io"
"path"
"path/filepath"
"slices"
"strings"
"sync"
@@ -605,14 +604,14 @@ func (b *breakpointMap) Set(fname string, sbps []dap.SourceBreakpoint) (breakpoi
return breakpoints
}
func (b *breakpointMap) Intersect(ctx Context, src *pb.Source, ws string) map[digest.Digest]int {
func (b *breakpointMap) Intersect(ctx Context, src *pb.Source) map[digest.Digest]int {
b.mu.Lock()
defer b.mu.Unlock()
digests := make(map[digest.Digest]int)
for dgst, locs := range src.Locations {
if id := b.intersect(ctx, src, locs, ws); id > 0 {
if id := b.intersect(ctx, src, locs); id > 0 {
digests[digest.Digest(dgst)] = id
}
}
@@ -620,7 +619,7 @@ func (b *breakpointMap) Intersect(ctx Context, src *pb.Source, ws string) map[di
// Mark unverified breakpoints as failed at this point since we couldn't find an area
// in the source where they applied.
for _, info := range src.Infos {
fname := filepath.Join(ws, info.Filename)
fname := info.Filename
bps := b.getByPath(fname)
for _, bp := range bps {
@@ -640,7 +639,7 @@ func (b *breakpointMap) Intersect(ctx Context, src *pb.Source, ws string) map[di
return digests
}
func (b *breakpointMap) intersect(ctx Context, src *pb.Source, locs *pb.Locations, ws string) int {
func (b *breakpointMap) intersect(ctx Context, src *pb.Source, locs *pb.Locations) int {
overlaps := func(r *pb.Range, bp *dap.Breakpoint) bool {
if bp.Line < int(r.Start.Line) || bp.Line > int(r.End.Line) {
return false
@@ -661,7 +660,7 @@ func (b *breakpointMap) intersect(ctx Context, src *pb.Source, locs *pb.Location
r := loc.Ranges[0]
info := src.Infos[loc.SourceIndex]
fname := filepath.Join(ws, info.Filename)
fname := info.Filename
bps := b.getByPath(fname)
if len(bps) == 0 {
+2 -2
View File
@@ -187,12 +187,12 @@ func TestBreakpointMapIntersectVerified(t *testing.T) {
src := &pb.Source{
Locations: srcLocs,
Infos: []*pb.SourceInfo{
{Filename: filename},
{Filename: fpath},
},
}
ctx := newBreakpointTestContext(t)
digests := bm.Intersect(ctx, src, ws)
digests := bm.Intersect(ctx, src)
wantMatches := 0
for _, bc := range breakpointCases {
if bc.expectVerified {
+25 -16
View File
@@ -2,9 +2,9 @@ package dap
import (
"context"
"path"
"path/filepath"
"slices"
"strings"
"sync"
"github.com/docker/buildx/build"
@@ -31,10 +31,10 @@ type thread struct {
variables *variableReferences
// Inputs to the evaluate call.
c gateway.Client
ref gateway.Reference
meta map[string][]byte
sourcePath string
c gateway.Client
ref gateway.Reference
meta map[string][]byte
sourceInfoMap func(*pb.Source) *pb.Source
// LLB state for the evaluate call.
def *llb.Definition
@@ -107,14 +107,21 @@ func (t *thread) init(ctx Context, c gateway.Client, ref gateway.Reference, meta
t.c = c
t.ref = ref
t.meta = meta
t.sourceInfoMap = func(s *pb.Source) *pb.Source {
s = s.CloneVT()
for _, sinfo := range s.Infos {
// Map the filename from the source info from the frontend location to the
// client location.
fname := strings.Replace(sinfo.Filename, inputs.DockerfileMappingDst, inputs.DockerfileMappingSrc, 1)
// Combine the dockerfile directory with the context path to find the
// real base path. The frontend will report the base path as the filename.
dir := path.Dir(inputs.DockerfilePath)
if !path.IsAbs(dir) {
dir = path.Join(inputs.ContextPath, dir)
// Convert to an absolute path.
if abspath, err := filepath.Abs(fname); err == nil {
fname = abspath
}
sinfo.Filename = fname
}
return s
}
t.sourcePath = dir
if err := t.getLLBState(ctx); err != nil {
return err
@@ -252,7 +259,7 @@ func (t *thread) getStackFrame(dgst digest.Digest, next *step) *frame {
f.setNameFromMeta(meta)
}
if loc, ok := t.def.Source.Locations[string(dgst)]; ok {
f.fillLocation(t.def, loc, t.sourcePath, next)
f.fillLocation(t.def, loc, next)
}
t.frames[int32(f.Id)] = f
return f
@@ -296,7 +303,6 @@ func (t *thread) reset() {
t.c = nil
t.ref = nil
t.meta = nil
t.sourcePath = ""
t.ops = nil
}
@@ -462,9 +468,12 @@ func (t *thread) getLLBState(ctx Context) error {
return err
}
if t.sourceInfoMap != nil {
t.def.Source = t.sourceInfoMap(t.def.Source)
}
for _, src := range t.def.Source.Infos {
fname := filepath.Join(t.sourcePath, src.Filename)
t.sourceMap.Put(ctx, fname, src.Data)
t.sourceMap.Put(ctx, src.Filename, src.Data)
}
t.ops = make(map[digest.Digest]*pb.Op, len(t.def.Def))
@@ -483,7 +492,7 @@ func (t *thread) getLLBState(ctx Context) error {
}
func (t *thread) setBreakpoints(ctx Context) {
t.bps = t.breakpointMap.Intersect(ctx, t.def.Source, t.sourcePath)
t.bps = t.breakpointMap.Intersect(ctx, t.def.Source)
}
func (t *thread) seekNext(ctx Context, from *step, action stepType) (string, *step, map[string]gateway.Reference, error) {
+2 -2
View File
@@ -38,7 +38,7 @@ func (f *frame) setNameFromMeta(meta llb.OpMetadata) {
// TODO: should we infer the name from somewhere else?
}
func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, ws string, next *step) {
func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, next *step) {
for _, l := range loc.Locations {
for _, r := range l.Ranges {
if next != nil && f.Line != 0 {
@@ -57,7 +57,7 @@ func (f *frame) fillLocation(def *llb.Definition, loc *pb.Locations, ws string,
info := def.Source.Infos[l.SourceIndex]
f.Source = &dap.Source{
Name: path.Base(info.Filename),
Path: filepath.Join(ws, info.Filename),
Path: info.Filename,
}
// If we do not have a next operation, then we don't have