dap: properly map source paths to client side paths
Properly map the source paths from the metadata in the solve to the client side paths. The source path returns is relative to the context that gets uploaded which is usually a subdirectory. The original code noticed this when mapping the paths but made the invalid assumption that the dockerfile would always be in the context path so it combined the dockerfile name with the context path. It is possible for the dockerfile to be in a subdirectory of the context. In which case, we computed the paths incorrectly. This modifies DAP to instead use the `DockerfileMappingDst` and `DockerfileMappingSrc` which are special included variables to the inputs that get filled in during the build for the purpose of mapping the source path to the client side path. Tests have also been added for this functionality to ensure it doesn't break again. This should work with both absolute and relative paths although absolute paths should probably be preferred for usage just because they're less likely to result in weird things happening. The sources are also normalized to always convert the source filenames to absolute paths and DAP itself will accept relative paths but will only ever communicate in absolute paths. When you set a breakpoint, it will convert it to an absolute path and reference it in that way rather than a relative path. Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
This commit is contained in:
+5
-6
@@ -7,7 +7,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -598,14 +597,14 @@ func (b *breakpointMap) Set(fname string, sbps []dap.SourceBreakpoint) (breakpoi
|
|||||||
return breakpoints
|
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()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
digests := make(map[digest.Digest]int)
|
digests := make(map[digest.Digest]int)
|
||||||
|
|
||||||
for dgst, locs := range src.Locations {
|
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
|
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
|
// Mark unverified breakpoints as failed at this point since we couldn't find an area
|
||||||
// in the source where they applied.
|
// in the source where they applied.
|
||||||
for _, info := range src.Infos {
|
for _, info := range src.Infos {
|
||||||
fname := filepath.Join(ws, info.Filename)
|
fname := info.Filename
|
||||||
|
|
||||||
bps := b.byPath[fname]
|
bps := b.byPath[fname]
|
||||||
for _, bp := range bps {
|
for _, bp := range bps {
|
||||||
@@ -633,7 +632,7 @@ func (b *breakpointMap) Intersect(ctx Context, src *pb.Source, ws string) map[di
|
|||||||
return digests
|
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 {
|
overlaps := func(r *pb.Range, bp *dap.Breakpoint) bool {
|
||||||
if bp.Line < int(r.Start.Line) || bp.Line > int(r.End.Line) {
|
if bp.Line < int(r.Start.Line) || bp.Line > int(r.End.Line) {
|
||||||
return false
|
return false
|
||||||
@@ -654,7 +653,7 @@ func (b *breakpointMap) intersect(ctx Context, src *pb.Source, locs *pb.Location
|
|||||||
r := loc.Ranges[0]
|
r := loc.Ranges[0]
|
||||||
|
|
||||||
info := src.Infos[loc.SourceIndex]
|
info := src.Infos[loc.SourceIndex]
|
||||||
fname := filepath.Join(ws, info.Filename)
|
fname := info.Filename
|
||||||
|
|
||||||
bps := b.byPath[fname]
|
bps := b.byPath[fname]
|
||||||
if len(bps) == 0 {
|
if len(bps) == 0 {
|
||||||
|
|||||||
+2
-2
@@ -187,12 +187,12 @@ func TestBreakpointMapIntersectVerified(t *testing.T) {
|
|||||||
src := &pb.Source{
|
src := &pb.Source{
|
||||||
Locations: srcLocs,
|
Locations: srcLocs,
|
||||||
Infos: []*pb.SourceInfo{
|
Infos: []*pb.SourceInfo{
|
||||||
{Filename: filename},
|
{Filename: fpath},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := newBreakpointTestContext(t)
|
ctx := newBreakpointTestContext(t)
|
||||||
digests := bm.Intersect(ctx, src, ws)
|
digests := bm.Intersect(ctx, src)
|
||||||
wantMatches := 0
|
wantMatches := 0
|
||||||
for _, bc := range breakpointCases {
|
for _, bc := range breakpointCases {
|
||||||
if bc.expectVerified {
|
if bc.expectVerified {
|
||||||
|
|||||||
+25
-16
@@ -2,9 +2,9 @@ package dap
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/buildx/build"
|
"github.com/docker/buildx/build"
|
||||||
@@ -31,10 +31,10 @@ type thread struct {
|
|||||||
variables *variableReferences
|
variables *variableReferences
|
||||||
|
|
||||||
// Inputs to the evaluate call.
|
// Inputs to the evaluate call.
|
||||||
c gateway.Client
|
c gateway.Client
|
||||||
ref gateway.Reference
|
ref gateway.Reference
|
||||||
meta map[string][]byte
|
meta map[string][]byte
|
||||||
sourcePath string
|
sourceInfoMap func(*pb.Source) *pb.Source
|
||||||
|
|
||||||
// LLB state for the evaluate call.
|
// LLB state for the evaluate call.
|
||||||
def *llb.Definition
|
def *llb.Definition
|
||||||
@@ -107,14 +107,21 @@ func (t *thread) init(ctx Context, c gateway.Client, ref gateway.Reference, meta
|
|||||||
t.c = c
|
t.c = c
|
||||||
t.ref = ref
|
t.ref = ref
|
||||||
t.meta = meta
|
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
|
// Convert to an absolute path.
|
||||||
// real base path. The frontend will report the base path as the filename.
|
if abspath, err := filepath.Abs(fname); err == nil {
|
||||||
dir := path.Dir(inputs.DockerfilePath)
|
fname = abspath
|
||||||
if !path.IsAbs(dir) {
|
}
|
||||||
dir = path.Join(inputs.ContextPath, dir)
|
sinfo.Filename = fname
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
t.sourcePath = dir
|
|
||||||
|
|
||||||
if err := t.getLLBState(ctx); err != nil {
|
if err := t.getLLBState(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -252,7 +259,7 @@ func (t *thread) getStackFrame(dgst digest.Digest, next *step) *frame {
|
|||||||
f.setNameFromMeta(meta)
|
f.setNameFromMeta(meta)
|
||||||
}
|
}
|
||||||
if loc, ok := t.def.Source.Locations[string(dgst)]; ok {
|
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
|
t.frames[int32(f.Id)] = f
|
||||||
return f
|
return f
|
||||||
@@ -296,7 +303,6 @@ func (t *thread) reset() {
|
|||||||
t.c = nil
|
t.c = nil
|
||||||
t.ref = nil
|
t.ref = nil
|
||||||
t.meta = nil
|
t.meta = nil
|
||||||
t.sourcePath = ""
|
|
||||||
t.ops = nil
|
t.ops = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,9 +468,12 @@ func (t *thread) getLLBState(ctx Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if t.sourceInfoMap != nil {
|
||||||
|
t.def.Source = t.sourceInfoMap(t.def.Source)
|
||||||
|
}
|
||||||
|
|
||||||
for _, src := range t.def.Source.Infos {
|
for _, src := range t.def.Source.Infos {
|
||||||
fname := filepath.Join(t.sourcePath, src.Filename)
|
t.sourceMap.Put(ctx, src.Filename, src.Data)
|
||||||
t.sourceMap.Put(ctx, fname, src.Data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.ops = make(map[digest.Digest]*pb.Op, len(t.def.Def))
|
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) {
|
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) {
|
func (t *thread) seekNext(ctx Context, from *step, action stepType) (string, *step, map[string]gateway.Reference, error) {
|
||||||
|
|||||||
+2
-2
@@ -38,7 +38,7 @@ func (f *frame) setNameFromMeta(meta llb.OpMetadata) {
|
|||||||
// TODO: should we infer the name from somewhere else?
|
// 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 _, l := range loc.Locations {
|
||||||
for _, r := range l.Ranges {
|
for _, r := range l.Ranges {
|
||||||
if next != nil && f.Line != 0 {
|
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]
|
info := def.Source.Infos[l.SourceIndex]
|
||||||
f.Source = &dap.Source{
|
f.Source = &dap.Source{
|
||||||
Name: path.Base(info.Filename),
|
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
|
// If we do not have a next operation, then we don't have
|
||||||
|
|||||||
+49
-50
@@ -107,7 +107,7 @@ COPY --from=base /etc/bar /bar
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withDir(dir), withArgs("build", "--progress=quiet", "-f-", dir))
|
cmd := buildxCmd(sb, withDir(dir), withArgs("build", "--progress=quiet", "-f-", dir))
|
||||||
@@ -124,8 +124,8 @@ COPY foo /foo
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -149,8 +149,8 @@ COPY foo /foo
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -176,8 +176,8 @@ COPY foo /foo
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -209,8 +209,8 @@ COPY foo /foo
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -242,8 +242,8 @@ COPY foo /foo
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -275,8 +275,8 @@ COPY foo /foo
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -314,8 +314,8 @@ COPY --from=base /etc/bar /bar
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("build.Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("build.Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
out, err := buildCmd(sb, withDir(dir), withArgs(
|
out, err := buildCmd(sb, withDir(dir), withArgs(
|
||||||
@@ -359,7 +359,7 @@ COPY --from=base /etc/bar /bar
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
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))
|
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(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("build.Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("build.Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
dirDest := t.TempDir()
|
dirDest := t.TempDir()
|
||||||
|
|
||||||
@@ -534,7 +534,7 @@ func testImageIDOutput(t *testing.T, sb integration.Sandbox) {
|
|||||||
dockerfile := []byte(`FROM busybox:latest`)
|
dockerfile := []byte(`FROM busybox:latest`)
|
||||||
|
|
||||||
dir := tmpdir(t,
|
dir := tmpdir(t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
targetDir := t.TempDir()
|
targetDir := t.TempDir()
|
||||||
|
|
||||||
@@ -607,7 +607,7 @@ func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) {
|
|||||||
|
|
||||||
// build image
|
// build image
|
||||||
dockerfile := []byte(`FROM buildx-test:busybox`)
|
dockerfile := []byte(`FROM buildx-test:busybox`)
|
||||||
dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0600))
|
dir := tmpdir(t, fstest.CreateFile("Dockerfile", dockerfile, 0o600))
|
||||||
cmd = buildxCmd(
|
cmd = buildxCmd(
|
||||||
sb,
|
sb,
|
||||||
withArgs("build", "-q", "--output=type=cacheonly", dir),
|
withArgs("build", "-q", "--output=type=cacheonly", dir),
|
||||||
@@ -626,7 +626,7 @@ func testBuildMobyFromLocalImage(t *testing.T, sb integration.Sandbox) {
|
|||||||
FROM busybox:1.35
|
FROM busybox:1.35
|
||||||
RUN busybox | head -1 | grep v1.36.1
|
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(
|
cmd = buildxCmd(
|
||||||
sb,
|
sb,
|
||||||
withArgs("build", "-q", "--output=type=cacheonly", dir),
|
withArgs("build", "-q", "--output=type=cacheonly", dir),
|
||||||
@@ -642,7 +642,7 @@ func testBuildDetailsLink(t *testing.T, sb integration.Sandbox) {
|
|||||||
// build simple dockerfile
|
// build simple dockerfile
|
||||||
dockerfile := []byte(`FROM busybox:latest
|
dockerfile := []byte(`FROM busybox:latest
|
||||||
RUN echo foo > /bar`)
|
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))
|
cmd := buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir))
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
require.NoError(t, err, string(out))
|
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
|
home, err := os.UserHomeDir() // TODO: sandbox should create a temp home dir and expose it through its interface
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dbDir := path.Join(home, ".docker", "desktop-build")
|
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"))
|
dblaFile, err := os.Create(path.Join(dbDir, ".lastaccess"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -671,7 +671,7 @@ RUN echo foo > /bar`)
|
|||||||
// build erroneous dockerfile
|
// build erroneous dockerfile
|
||||||
dockerfile = []byte(`FROM busybox:latest
|
dockerfile = []byte(`FROM busybox:latest
|
||||||
RUN exit 1`)
|
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))
|
cmd = buildxCmd(sb, withArgs("build", "--output=type=cacheonly", dir))
|
||||||
out, err = cmd.CombinedOutput()
|
out, err = cmd.CombinedOutput()
|
||||||
require.Error(t, err, string(out))
|
require.Error(t, err, string(out))
|
||||||
@@ -802,8 +802,8 @@ func testBuildMultiPlatform(t *testing.T, sb integration.Sandbox) {
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
registry, err := sb.NewRegistry()
|
registry, err := sb.NewRegistry()
|
||||||
if errors.Is(err, integration.ErrRequirements) {
|
if errors.Is(err, integration.ErrRequirements) {
|
||||||
@@ -838,7 +838,7 @@ func testDockerHostGateway(t *testing.T, sb integration.Sandbox) {
|
|||||||
FROM busybox
|
FROM busybox
|
||||||
RUN ping -c 1 buildx.host-gateway-ip.local
|
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))
|
cmd := buildxCmd(sb, withArgs("build", "--add-host=buildx.host-gateway-ip.local:host-gateway", "--output=type=cacheonly", dir))
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if !isDockerWorker(sb) {
|
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
|
RUN --network=host ip a show eth0 | awk '/inet / {split($2, a, "/"); print a[1]}' > /ip-host.txt
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=build /ip*.txt /`)
|
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 := buildxCmd(sb, withArgs("build", "--allow=network.host", fmt.Sprintf("--output=type=local,dest=%s", dir), dir))
|
||||||
cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName)
|
cmd.Env = append(cmd.Env, "BUILDX_BUILDER="+builderName)
|
||||||
@@ -912,7 +912,7 @@ COPY --from=build /shmsize /
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
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))
|
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(
|
dir := tmpdir(
|
||||||
t,
|
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))
|
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(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
registry, err := sb.NewRegistry()
|
registry, err := sb.NewRegistry()
|
||||||
@@ -1122,7 +1122,7 @@ COPy --from=base \
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(
|
cmd := buildxCmd(
|
||||||
@@ -1258,8 +1258,8 @@ COPY --from=build /token /
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("tokenfile", []byte(token), 0600),
|
fstest.CreateFile("tokenfile", []byte(token), 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
t.Run("env", func(t *testing.T) {
|
t.Run("env", func(t *testing.T) {
|
||||||
@@ -1347,7 +1347,7 @@ COPy --from=base \
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("build", "--call=check,format=json", dir))
|
cmd := buildxCmd(sb, withArgs("build", "--call=check,format=json", dir))
|
||||||
@@ -1382,7 +1382,7 @@ FROM second
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
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))
|
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(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
runOutline := func(args ...string) string {
|
runOutline := func(args ...string) string {
|
||||||
@@ -1459,7 +1459,7 @@ FROM second AS binary
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("build", "--call=targets,format=json", dir))
|
cmd := buildxCmd(sb, withArgs("build", "--call=targets,format=json", dir))
|
||||||
@@ -1501,7 +1501,7 @@ COPy --from=base \
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
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))
|
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(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("build", "--call=check", dir))
|
cmd := buildxCmd(sb, withArgs("build", "--call=check", dir))
|
||||||
@@ -1556,7 +1556,7 @@ COPY Dockerfile .
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("build", "--call=check", dir))
|
cmd := buildxCmd(sb, withArgs("build", "--call=check", dir))
|
||||||
@@ -1575,7 +1575,7 @@ cOpy Dockerfile .
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := buildxCmd(sb, withArgs("build", "--call=check", dir))
|
cmd := buildxCmd(sb, withArgs("build", "--call=check", dir))
|
||||||
@@ -1594,8 +1594,8 @@ cOpy Dockerfile .
|
|||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(
|
||||||
t,
|
t,
|
||||||
fstest.CreateDir("subdir", 0700),
|
fstest.CreateDir("subdir", 0o700),
|
||||||
fstest.CreateFile("subdir/Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("subdir/Dockerfile", dockerfile, 0o600),
|
||||||
)
|
)
|
||||||
dockerfilePath := filepath.Join(dir, "subdir", "Dockerfile")
|
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.81
|
||||||
RUN cat /etc/hosts | grep myhostmulti | grep 162.242.195.82
|
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",
|
cmd := buildxCmd(sb, withArgs("build",
|
||||||
"--add-host=myhost=1.2.3.4",
|
"--add-host=myhost=1.2.3.4",
|
||||||
"--add-host=myhostmulti=162.242.195.81",
|
"--add-host=myhostmulti=162.242.195.81",
|
||||||
@@ -1649,10 +1649,9 @@ RUN cp /etc/foo /etc/bar
|
|||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=base /etc/bar /bar
|
COPY --from=base /etc/bar /bar
|
||||||
`)
|
`)
|
||||||
dir := tmpdir(
|
dir := tmpdir(t,
|
||||||
t,
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
fstest.CreateFile("Dockerfile", dockerfile, 0600),
|
fstest.CreateFile("foo", []byte("foo"), 0o600),
|
||||||
fstest.CreateFile("foo", []byte("foo"), 0600),
|
|
||||||
)
|
)
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/continuity/fs/fstest"
|
||||||
"github.com/docker/buildx/commands"
|
"github.com/docker/buildx/commands"
|
||||||
debug "github.com/docker/buildx/dap"
|
debug "github.com/docker/buildx/dap"
|
||||||
"github.com/docker/buildx/dap/common"
|
"github.com/docker/buildx/dap/common"
|
||||||
@@ -78,6 +79,7 @@ var dapBuildTests = []func(t *testing.T, sb integration.Sandbox){
|
|||||||
testDapBuildStopOnEntry,
|
testDapBuildStopOnEntry,
|
||||||
testDapBuildSetBreakpoints,
|
testDapBuildSetBreakpoints,
|
||||||
testDapBuildVerifiedBreakpoints,
|
testDapBuildVerifiedBreakpoints,
|
||||||
|
testDapBuildLoadedSource,
|
||||||
testDapBuildStepIn,
|
testDapBuildStepIn,
|
||||||
testDapBuildStepNext,
|
testDapBuildStepNext,
|
||||||
testDapBuildStepOut,
|
testDapBuildStepOut,
|
||||||
@@ -250,6 +252,103 @@ func testDapBuildVerifiedBreakpoints(t *testing.T, sb integration.Sandbox) {
|
|||||||
require.ErrorAs(t, done(true), &exitErr)
|
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) {
|
func testDapBuildStepIn(t *testing.T, sb integration.Sandbox) {
|
||||||
dir := createTestProject(t)
|
dir := createTestProject(t)
|
||||||
client, done, err := dapBuildCmd(t, sb, withArgs(dir))
|
client, done, err := dapBuildCmd(t, sb, withArgs(dir))
|
||||||
|
|||||||
Reference in New Issue
Block a user