diff --git a/dap/adapter.go b/dap/adapter.go index 7ced02dce..d795532d2 100644 --- a/dap/adapter.go +++ b/dap/adapter.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "path" - "path/filepath" "slices" "sync" "sync/atomic" @@ -598,14 +597,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 } } @@ -613,7 +612,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.byPath[fname] for _, bp := range bps { @@ -633,7 +632,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 @@ -654,7 +653,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.byPath[fname] if len(bps) == 0 { diff --git a/dap/adapter_test.go b/dap/adapter_test.go index cf2f1db15..dd70ecfbd 100644 --- a/dap/adapter_test.go +++ b/dap/adapter_test.go @@ -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 { diff --git a/dap/thread.go b/dap/thread.go index 8eb26f653..c477be95c 100644 --- a/dap/thread.go +++ b/dap/thread.go @@ -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) { diff --git a/dap/variables.go b/dap/variables.go index 8c19857ab..322a78ce7 100644 --- a/dap/variables.go +++ b/dap/variables.go @@ -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 diff --git a/tests/build.go b/tests/build.go index 562b7a599..5cab89329 100644 --- a/tests/build.go +++ b/tests/build.go @@ -107,7 +107,7 @@ COPY --from=base /etc/bar /bar `) dir := tmpdir( t, - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) cmd := buildxCmd(sb, withDir(dir), withArgs("build", "--progress=quiet", "-f-", dir)) @@ -124,8 +124,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -149,8 +149,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -176,8 +176,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -209,8 +209,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -242,8 +242,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -275,8 +275,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -314,8 +314,8 @@ COPY --from=base /etc/bar /bar `) dir := tmpdir( t, - fstest.CreateFile("build.Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("build.Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) out, err := buildCmd(sb, withDir(dir), withArgs( @@ -359,7 +359,7 @@ COPY --from=base /etc/bar /bar `) dir := tmpdir( t, - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) cmd := buildxCmd(sb, withDir(dir), withArgs("build", "--progress=quiet", "--metadata-file", filepath.Join(dir, "md.json"), "-f-", dir)) @@ -397,8 +397,8 @@ COPY foo /foo `) dir := tmpdir( t, - fstest.CreateFile("build.Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("build.Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) dirDest := t.TempDir() @@ -534,7 +534,7 @@ func testImageIDOutput(t *testing.T, sb integration.Sandbox) { dockerfile := []byte(`FROM busybox:latest`) dir := tmpdir(t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) targetDir := t.TempDir() @@ -607,7 +607,7 @@ func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) { // build image dockerfile := []byte(`FROM buildx-test:busybox`) - dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd = buildxCmd( sb, withArgs("build", "-q", "--output=type=cacheonly", dir), @@ -626,7 +626,7 @@ func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) { FROM busybox:1.35 RUN busybox | head -1 | grep v1.36.1 `) - dir = tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir = tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd = buildxCmd( sb, withArgs("build", "-q", "--output=type=cacheonly", dir), @@ -642,7 +642,7 @@ func testBuildDetailsLink(t *testing.T, sb integration.Sandbox) { // build simple dockerfile dockerfile := []byte(`FROM busybox:latest RUN echo foo > /bar`) - dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd := buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir)) out, err := cmd.CombinedOutput() require.NoError(t, err, string(out)) @@ -652,7 +652,7 @@ RUN echo foo > /bar`) home, err := os.UserHomeDir() // TODO: sandbox should create a temp home dir and expose it through its interface require.NoError(t, err) dbDir := path.Join(home, ".docker", "desktop-build") - require.NoError(t, os.MkdirAll(dbDir, 0755)) + require.NoError(t, os.MkdirAll(dbDir, 0o755)) dblaFile, err := os.Create(path.Join(dbDir, ".lastaccess")) require.NoError(t, err) defer func() { @@ -671,7 +671,7 @@ RUN echo foo > /bar`) // build erroneous dockerfile dockerfile = []byte(`FROM busybox:latest RUN exit 1`) - dir = tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir = tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd = buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir)) out, err = cmd.CombinedOutput() require.Error(t, err, string(out)) @@ -802,8 +802,8 @@ func testBuildMultiPlatform(t *testing.T, sb integration.Sandbox) { `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) registry, err := sb.NewRegistry() if errors.Is(err, integration.ErrRequirements) { @@ -838,7 +838,7 @@ func testDockerHostGateway(t *testing.T, sb integration.Sandbox) { FROM busybox RUN ping -c 1 buildx.host-gateway-ip.local `) - dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd := buildxCmd(sb, withArgs("build", "--add-host=buildx.host-gateway-ip.local:host-gateway", "--output=type=cacheonly", dir)) out, err := cmd.CombinedOutput() if !isDockerWorker(sb) { @@ -877,7 +877,7 @@ RUN ip a show eth0 | awk '/inet / {split($2, a, "/"); print a[1]}' > /ip-bridge. RUN --network=host ip a show eth0 | awk '/inet / {split($2, a, "/"); print a[1]}' > /ip-host.txt FROM scratch COPY --from=build /ip*.txt /`) - dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd := buildxCmd(sb, withArgs("build", "--allow=network.host", fmt.Sprintf("--output=type=local,dest=%s", dir), dir)) cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName) @@ -912,7 +912,7 @@ COPY --from=build /shmsize / `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--shm-size=128m", fmt.Sprintf("--output=type=local,dest=%s", dir), dir)) @@ -933,7 +933,7 @@ COPY --from=build /ulimit / `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--ulimit=nofile=1024:1024", fmt.Sprintf("--output=type=local,dest=%s", dir), dir)) @@ -1034,8 +1034,8 @@ func buildMetadataProvenanceMultiplatform(t *testing.T, sb integration.Sandbox, `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) registry, err := sb.NewRegistry() @@ -1122,7 +1122,7 @@ COPy --from=base \ `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd( @@ -1258,8 +1258,8 @@ COPY --from=build /token / `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("tokenfile", []byte(token), 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("tokenfile", []byte(token), 0o600), ) t.Run("env", func(t *testing.T) { @@ -1347,7 +1347,7 @@ COPy --from=base \ `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--call=check,format=json", dir)) @@ -1382,7 +1382,7 @@ FROM second `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--build-arg=BAR=678", "--target=target", "--call=outline,format=json", dir)) @@ -1423,7 +1423,7 @@ ARG FOO=bar `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) runOutline := func(args ...string) string { @@ -1459,7 +1459,7 @@ FROM second AS binary `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--call=targets,format=json", dir)) @@ -1501,7 +1501,7 @@ COPy --from=base \ `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--call=check,format=json", "--metadata-file", filepath.Join(dir, "md.json"), dir)) @@ -1537,7 +1537,7 @@ COPY Dockerfile . `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--call=check", dir)) @@ -1556,7 +1556,7 @@ COPY Dockerfile . `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--call=check", dir)) @@ -1575,7 +1575,7 @@ cOpy Dockerfile . `) dir := tmpdir( t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("Dockerfile", dockerfile, 0o600), ) cmd := buildxCmd(sb, withArgs("build", "--call=check", dir)) @@ -1594,8 +1594,8 @@ cOpy Dockerfile . `) dir := tmpdir( t, - fstest.CreateDir("subdir", 0700), - fstest.CreateFile("subdir/Dockerfile", dockerfile, 0600), + fstest.CreateDir("subdir", 0o700), + fstest.CreateFile("subdir/Dockerfile", dockerfile, 0o600), ) dockerfilePath := filepath.Join(dir, "subdir", "Dockerfile") @@ -1618,7 +1618,7 @@ RUN cat /etc/hosts | grep myhost | grep 1.2.3.4 RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.81 RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.82 `) - dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600)) + dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600)) cmd := buildxCmd(sb, withArgs("build", "--add-host=myhost=1.2.3.4", "--add-host=myhostmulti=162.242.195.81", @@ -1649,10 +1649,9 @@ RUN cp /etc/foo /etc/bar FROM scratch COPY --from=base /etc/bar /bar `) - dir := tmpdir( - t, - fstest.CreateFile("Dockerfile", dockerfile, 0600), - fstest.CreateFile("foo", []byte("foo"), 0600), + dir := tmpdir(t, + fstest.CreateFile("Dockerfile", dockerfile, 0o600), + fstest.CreateFile("foo", []byte("foo"), 0o600), ) return dir } diff --git a/tests/dap_build.go b/tests/dap_build.go index ce7f169b6..a4bd73db5 100644 --- a/tests/dap_build.go +++ b/tests/dap_build.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/containerd/continuity/fs/fstest" "github.com/docker/buildx/commands" debug "github.com/docker/buildx/dap" "github.com/docker/buildx/dap/common" @@ -78,6 +79,7 @@ var dapBuildTests = []func(t *testing.T, sb integration.Sandbox){ testDapBuildStopOnEntry, testDapBuildSetBreakpoints, testDapBuildVerifiedBreakpoints, + testDapBuildLoadedSource, testDapBuildStepIn, testDapBuildStepNext, testDapBuildStepOut, @@ -250,6 +252,103 @@ func testDapBuildVerifiedBreakpoints(t *testing.T, sb integration.Sandbox) { require.ErrorAs(t, done(true), &exitErr) } +func testDapBuildLoadedSource(t *testing.T, sb integration.Sandbox) { + type test struct { + Name string + ContextPath string + DockerfilePath string + } + + runTest := func(t *testing.T, tt test, abspath bool) string { + dockerfile := []byte(` +FROM busybox:latest AS base +COPY foo /etc/foo +RUN cp /etc/foo /etc/bar + +FROM scratch +COPY --from=base /etc/bar /bar +`) + + appliers := []fstest.Applier{} + if tt.ContextPath != "" { + appliers = append(appliers, fstest.CreateDir(tt.ContextPath, 0o700)) + } + if tt.DockerfilePath != "" { + appliers = append(appliers, fstest.CreateDir(path.Join(tt.ContextPath, tt.DockerfilePath), 0o700)) + } + appliers = append(appliers, + fstest.CreateFile(path.Join(tt.ContextPath, tt.DockerfilePath, "Dockerfile"), dockerfile, 0o600), + fstest.CreateFile(path.Join(tt.ContextPath, "foo"), []byte("foo"), 0o600), + ) + dir := tmpdir(t, appliers...) + + client, done, err := dapBuildCmd(t, sb, withDir(dir)) + require.NoError(t, err) + + var source *dap.Source + client.RegisterEvent("loadedSource", func(em dap.EventMessage) { + e := em.(*dap.LoadedSourceEvent) + source = &e.Body.Source + }) + + launchCfg := commands.LaunchConfig{ + Config: common.Config{ + StopOnEntry: true, + }, + } + if abspath { + launchCfg.ContextPath = path.Join(dir, tt.ContextPath) + } else { + launchCfg.ContextPath = tt.ContextPath + } + launchCfg.Dockerfile = path.Join(launchCfg.ContextPath, tt.DockerfilePath, "Dockerfile") + doLaunch(t, client, launchCfg) + + interruptCh := pollInterruptEvents(client) + stopped := waitForInterrupt[*dap.StoppedEvent](t, interruptCh) + require.NotNil(t, stopped) + + expected := path.Join(dir, tt.ContextPath, tt.DockerfilePath, "Dockerfile") + require.NotNil(t, source) + require.Equal(t, expected, source.Path) + require.Equal(t, "Dockerfile", source.Name) + + var exitErr *exec.ExitError + require.ErrorAs(t, done(true), &exitErr) + return dir + } + + for _, tt := range []test{ + { + Name: "base path", + ContextPath: ".", + }, + { + Name: "nested context", + ContextPath: "nested", + }, + { + Name: "nested dockerfile", + ContextPath: ".", + DockerfilePath: "nested", + }, + { + Name: "both nested", + ContextPath: "nested", + DockerfilePath: "subdir", + }, + } { + t.Run(tt.Name, func(t *testing.T) { + t.Run("absolute paths", func(t *testing.T) { + runTest(t, tt, true) + }) + t.Run("relative paths", func(t *testing.T) { + runTest(t, tt, false) + }) + }) + } +} + func testDapBuildStepIn(t *testing.T, sb integration.Sandbox) { dir := createTestProject(t) client, done, err := dapBuildCmd(t, sb, withArgs(dir))