service,terminal,cmd/dlv: automatically guessing substitute-path config (#3781)
Add command, API calls and launch.json option to automatically guess substitute-path configuration.
This commit is contained in:
parent
ac14553fda
commit
822014b8e8
@ -256,10 +256,13 @@ Changes the value of a configuration parameter.
|
|||||||
config substitute-path <from> <to>
|
config substitute-path <from> <to>
|
||||||
config substitute-path <from>
|
config substitute-path <from>
|
||||||
config substitute-path -clear
|
config substitute-path -clear
|
||||||
|
config substitute-path -guess
|
||||||
|
|
||||||
Adds or removes a path substitution rule, if -clear is used all
|
Adds or removes a path substitution rule, if -clear is used all
|
||||||
substitute-path rules are removed. Without arguments shows the current list
|
substitute-path rules are removed. Without arguments shows the current list
|
||||||
of substitute-path rules.
|
of substitute-path rules.
|
||||||
|
The -guess option causes Delve to try to guess your substitute-path
|
||||||
|
configuration automatically.
|
||||||
See also [Documentation/cli/substitutepath.md](//github.com/go-delve/delve/tree/master/Documentation/cli/substitutepath.md) for how the rules are applied.
|
See also [Documentation/cli/substitutepath.md](//github.com/go-delve/delve/tree/master/Documentation/cli/substitutepath.md) for how the rules are applied.
|
||||||
|
|
||||||
config alias <command> <alias>
|
config alias <command> <alias>
|
||||||
|
@ -44,6 +44,7 @@ function_return_locations(FnName) | Equivalent to API call [FunctionReturnLocati
|
|||||||
get_breakpoint(Id, Name) | Equivalent to API call [GetBreakpoint](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GetBreakpoint)
|
get_breakpoint(Id, Name) | Equivalent to API call [GetBreakpoint](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GetBreakpoint)
|
||||||
get_buffered_tracepoints() | Equivalent to API call [GetBufferedTracepoints](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GetBufferedTracepoints)
|
get_buffered_tracepoints() | Equivalent to API call [GetBufferedTracepoints](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GetBufferedTracepoints)
|
||||||
get_thread(Id) | Equivalent to API call [GetThread](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GetThread)
|
get_thread(Id) | Equivalent to API call [GetThread](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GetThread)
|
||||||
|
guess_substitute_path(Args) | Equivalent to API call [GuessSubstitutePath](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.GuessSubstitutePath)
|
||||||
is_multiclient() | Equivalent to API call [IsMulticlient](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.IsMulticlient)
|
is_multiclient() | Equivalent to API call [IsMulticlient](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.IsMulticlient)
|
||||||
last_modified() | Equivalent to API call [LastModified](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.LastModified)
|
last_modified() | Equivalent to API call [LastModified](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.LastModified)
|
||||||
breakpoints(All) | Equivalent to API call [ListBreakpoints](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.ListBreakpoints)
|
breakpoints(All) | Equivalent to API call [ListBreakpoints](https://pkg.go.dev/github.com/go-delve/delve/service/rpc2#RPCServer.ListBreakpoints)
|
||||||
|
@ -24,7 +24,9 @@ func main() {
|
|||||||
|
|
||||||
cmdnames := []string{}
|
cmdnames := []string{}
|
||||||
for _, subcmd := range root.Commands() {
|
for _, subcmd := range root.Commands() {
|
||||||
cmdnames = append(cmdnames, subcmd.Name())
|
if !subcmd.Hidden {
|
||||||
|
cmdnames = append(cmdnames, subcmd.Name())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
helphelpers.Prepare(root)
|
helphelpers.Prepare(root)
|
||||||
doc.GenMarkdownTree(root, usageDir)
|
doc.GenMarkdownTree(root, usageDir)
|
||||||
|
@ -130,6 +130,9 @@ This option can only be specified if testset is basic or a single package.`)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkCert() bool {
|
func checkCert() bool {
|
||||||
|
if os.Getenv("NOCERT") != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
// If we're on OSX make sure the proper CERT env var is set.
|
// If we're on OSX make sure the proper CERT env var is set.
|
||||||
if runtime.GOOS != "darwin" || os.Getenv("CERT") != "" {
|
if runtime.GOOS != "darwin" || os.Getenv("CERT") != "" {
|
||||||
return true
|
return true
|
||||||
@ -326,7 +329,7 @@ func buildFlags() []string {
|
|||||||
} else {
|
} else {
|
||||||
ldFlags = "-X main.Build=" + buildSHA
|
ldFlags = "-X main.Build=" + buildSHA
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" && os.Getenv("CERT") != "" {
|
||||||
ldFlags = "-s " + ldFlags
|
ldFlags = "-s " + ldFlags
|
||||||
}
|
}
|
||||||
return []string{fmt.Sprintf("-ldflags=%s", ldFlags)}
|
return []string{fmt.Sprintf("-ldflags=%s", ldFlags)}
|
||||||
|
@ -513,6 +513,24 @@ File redirects can also be changed using the 'restart' command.
|
|||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rootCommand.AddCommand(&cobra.Command{
|
||||||
|
Use: "substitute-path-guess-helper",
|
||||||
|
Hidden: true,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
gsp, err := rpc2.MakeGuessSusbtitutePathIn()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(os.Stdout).Encode(gsp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
rootCommand.DisableAutoGenTag = true
|
rootCommand.DisableAutoGenTag = true
|
||||||
|
|
||||||
configUsageFunc(rootCommand)
|
configUsageFunc(rootCommand)
|
||||||
|
@ -31,11 +31,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var testBackend string
|
var testBackend string
|
||||||
var ldFlags string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
ldFlags = os.Getenv("CGO_LDFLAGS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
flag.StringVar(&testBackend, "backend", "", "selects backend")
|
flag.StringVar(&testBackend, "backend", "", "selects backend")
|
||||||
@ -61,30 +56,10 @@ func assertNoError(err error, t testing.TB, s string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func projectRoot() string {
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
gopaths := strings.FieldsFunc(os.Getenv("GOPATH"), func(r rune) bool { return r == os.PathListSeparator })
|
|
||||||
for _, curpath := range gopaths {
|
|
||||||
// Detects "gopath mode" when GOPATH contains several paths ex. "d:\\dir\\gopath;f:\\dir\\gopath2"
|
|
||||||
if strings.Contains(wd, curpath) {
|
|
||||||
return filepath.Join(curpath, "src", "github.com", "go-delve", "delve")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val, err := exec.Command("go", "list", "-mod=", "-m", "-f", "{{ .Dir }}").Output()
|
|
||||||
if err != nil {
|
|
||||||
panic(err) // the Go tool was tested to work earlier
|
|
||||||
}
|
|
||||||
return strings.TrimSuffix(string(val), "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40573"
|
const listenAddr = "127.0.0.1:40573"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
defer os.Remove(dlvbin)
|
defer os.Remove(dlvbin)
|
||||||
|
|
||||||
fixtures := protest.FindFixturesDir()
|
fixtures := protest.FindFixturesDir()
|
||||||
@ -194,46 +169,10 @@ func testOutput(t *testing.T, dlvbin, output string, delveCmds []string) (stdout
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDlvBin(t *testing.T) string {
|
|
||||||
// In case this was set in the environment
|
|
||||||
// from getDlvBinEBPF lets clear it here, so
|
|
||||||
// we can ensure we don't get build errors
|
|
||||||
// depending on the test ordering.
|
|
||||||
t.Setenv("CGO_LDFLAGS", ldFlags)
|
|
||||||
var tags string
|
|
||||||
if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
|
|
||||||
tags = "-tags=exp.winarm64"
|
|
||||||
}
|
|
||||||
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
|
|
||||||
tags = "-tags=exp.linuxppc64le"
|
|
||||||
}
|
|
||||||
if runtime.GOOS == "linux" && runtime.GOARCH == "riscv64" {
|
|
||||||
tags = "-tags=exp.linuxriscv64"
|
|
||||||
}
|
|
||||||
return getDlvBinInternal(t, tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDlvBinEBPF(t *testing.T) string {
|
|
||||||
return getDlvBinInternal(t, "-tags", "ebpf")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDlvBinInternal(t *testing.T, goflags ...string) string {
|
|
||||||
dlvbin := filepath.Join(t.TempDir(), "dlv.exe")
|
|
||||||
args := append([]string{"build", "-o", dlvbin}, goflags...)
|
|
||||||
args = append(args, "github.com/go-delve/delve/cmd/dlv")
|
|
||||||
|
|
||||||
out, err := exec.Command("go", args...).CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("go build -o %v github.com/go-delve/delve/cmd/dlv: %v\n%s", dlvbin, err, string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
return dlvbin
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestOutput verifies that the debug executable is created in the correct path
|
// TestOutput verifies that the debug executable is created in the correct path
|
||||||
// and removed after exit.
|
// and removed after exit.
|
||||||
func TestOutput(t *testing.T) {
|
func TestOutput(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
for _, output := range []string{"__debug_bin", "myownname", filepath.Join(t.TempDir(), "absolute.path")} {
|
for _, output := range []string{"__debug_bin", "myownname", filepath.Join(t.TempDir(), "absolute.path")} {
|
||||||
testOutput(t, dlvbin, output, []string{"exit"})
|
testOutput(t, dlvbin, output, []string{"exit"})
|
||||||
@ -252,7 +191,7 @@ func TestUnattendedBreakpoint(t *testing.T) {
|
|||||||
const listenAddr = "127.0.0.1:40573"
|
const listenAddr = "127.0.0.1:40573"
|
||||||
|
|
||||||
fixturePath := filepath.Join(protest.FindFixturesDir(), "panic.go")
|
fixturePath := filepath.Join(protest.FindFixturesDir(), "panic.go")
|
||||||
cmd := exec.Command(getDlvBin(t), "debug", "--continue", "--headless", "--accept-multiclient", "--listen", listenAddr, fixturePath)
|
cmd := exec.Command(protest.GetDlvBinary(t), "debug", "--continue", "--headless", "--accept-multiclient", "--listen", listenAddr, fixturePath)
|
||||||
stderr, err := cmd.StderrPipe()
|
stderr, err := cmd.StderrPipe()
|
||||||
assertNoError(err, t, "stdout pipe")
|
assertNoError(err, t, "stdout pipe")
|
||||||
defer stderr.Close()
|
defer stderr.Close()
|
||||||
@ -279,7 +218,7 @@ func TestUnattendedBreakpoint(t *testing.T) {
|
|||||||
func TestContinue(t *testing.T) {
|
func TestContinue(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40573"
|
const listenAddr = "127.0.0.1:40573"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
||||||
cmd := exec.Command(dlvbin, "debug", "--headless", "--continue", "--accept-multiclient", "--listen", listenAddr)
|
cmd := exec.Command(dlvbin, "debug", "--headless", "--continue", "--accept-multiclient", "--listen", listenAddr)
|
||||||
@ -311,7 +250,7 @@ func TestContinue(t *testing.T) {
|
|||||||
func TestRedirect(t *testing.T) {
|
func TestRedirect(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40573"
|
const listenAddr = "127.0.0.1:40573"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
catfixture := filepath.Join(protest.FindFixturesDir(), "cat.go")
|
catfixture := filepath.Join(protest.FindFixturesDir(), "cat.go")
|
||||||
cmd := exec.Command(dlvbin, "debug", "--headless", "--continue", "--accept-multiclient", "--listen", listenAddr, "-r", catfixture, catfixture)
|
cmd := exec.Command(dlvbin, "debug", "--headless", "--continue", "--accept-multiclient", "--listen", listenAddr, "-r", catfixture, catfixture)
|
||||||
@ -339,7 +278,7 @@ func TestRedirect(t *testing.T) {
|
|||||||
const checkAutogenDocLongOutput = false
|
const checkAutogenDocLongOutput = false
|
||||||
|
|
||||||
func checkAutogenDoc(t *testing.T, filename, gencommand string, generated []byte) {
|
func checkAutogenDoc(t *testing.T, filename, gencommand string, generated []byte) {
|
||||||
saved := slurpFile(t, filepath.Join(projectRoot(), filename))
|
saved := slurpFile(t, filepath.Join(protest.ProjectRoot(), filename))
|
||||||
|
|
||||||
saved = bytes.ReplaceAll(saved, []byte("\r\n"), []byte{'\n'})
|
saved = bytes.ReplaceAll(saved, []byte("\r\n"), []byte{'\n'})
|
||||||
generated = bytes.ReplaceAll(generated, []byte("\r\n"), []byte{'\n'})
|
generated = bytes.ReplaceAll(generated, []byte("\r\n"), []byte{'\n'})
|
||||||
@ -377,7 +316,7 @@ func diffMaybe(t *testing.T, filename string, generated []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
cmd := exec.Command("diff", filename, "-")
|
cmd := exec.Command("diff", filename, "-")
|
||||||
cmd.Dir = projectRoot()
|
cmd.Dir = protest.ProjectRoot()
|
||||||
stdin, _ := cmd.StdinPipe()
|
stdin, _ := cmd.StdinPipe()
|
||||||
go func() {
|
go func() {
|
||||||
stdin.Write(generated)
|
stdin.Write(generated)
|
||||||
@ -410,7 +349,7 @@ func TestGeneratedDoc(t *testing.T) {
|
|||||||
// Checks gen-usage-docs.go
|
// Checks gen-usage-docs.go
|
||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
cmd := exec.Command("go", "run", "_scripts/gen-usage-docs.go", tempDir)
|
cmd := exec.Command("go", "run", "_scripts/gen-usage-docs.go", tempDir)
|
||||||
cmd.Dir = projectRoot()
|
cmd.Dir = protest.ProjectRoot()
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
assertNoError(err, t, "go run _scripts/gen-usage-docs.go")
|
assertNoError(err, t, "go run _scripts/gen-usage-docs.go")
|
||||||
entries, err := os.ReadDir(tempDir)
|
entries, err := os.ReadDir(tempDir)
|
||||||
@ -424,7 +363,7 @@ func TestGeneratedDoc(t *testing.T) {
|
|||||||
a := []string{"run"}
|
a := []string{"run"}
|
||||||
a = append(a, args...)
|
a = append(a, args...)
|
||||||
cmd := exec.Command("go", a...)
|
cmd := exec.Command("go", a...)
|
||||||
cmd.Dir = projectRoot()
|
cmd.Dir = protest.ProjectRoot()
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not run script %v: %v (output: %q)", args, err, string(out))
|
t.Fatalf("could not run script %v: %v (output: %q)", args, err, string(out))
|
||||||
@ -443,7 +382,7 @@ func TestGeneratedDoc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExitInInit(t *testing.T) {
|
func TestExitInInit(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
||||||
exitInit := filepath.Join(protest.FindFixturesDir(), "exit.init")
|
exitInit := filepath.Join(protest.FindFixturesDir(), "exit.init")
|
||||||
@ -643,7 +582,7 @@ func TestTypecheckRPC(t *testing.T) {
|
|||||||
func TestDAPCmd(t *testing.T) {
|
func TestDAPCmd(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40575"
|
const listenAddr = "127.0.0.1:40575"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--listen", listenAddr)
|
cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--listen", listenAddr)
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
@ -706,7 +645,7 @@ func newDAPRemoteClient(t *testing.T, addr string, isDlvAttach bool, isMulti boo
|
|||||||
func TestRemoteDAPClient(t *testing.T) {
|
func TestRemoteDAPClient(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40576"
|
const listenAddr = "127.0.0.1:40576"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
||||||
cmd := exec.Command(dlvbin, "debug", "--headless", "--log-output=dap", "--log", "--listen", listenAddr)
|
cmd := exec.Command(dlvbin, "debug", "--headless", "--log-output=dap", "--log", "--listen", listenAddr)
|
||||||
@ -759,7 +698,7 @@ func closeDAPRemoteMultiClient(t *testing.T, c *daptest.Client, expectStatus str
|
|||||||
func TestRemoteDAPClientMulti(t *testing.T) {
|
func TestRemoteDAPClientMulti(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40577"
|
const listenAddr = "127.0.0.1:40577"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
|
||||||
cmd := exec.Command(dlvbin, "debug", "--headless", "--accept-multiclient", "--log-output=debugger", "--log", "--listen", listenAddr)
|
cmd := exec.Command(dlvbin, "debug", "--headless", "--accept-multiclient", "--log-output=debugger", "--log", "--listen", listenAddr)
|
||||||
@ -826,7 +765,7 @@ func TestRemoteDAPClientMulti(t *testing.T) {
|
|||||||
func TestRemoteDAPClientAfterContinue(t *testing.T) {
|
func TestRemoteDAPClientAfterContinue(t *testing.T) {
|
||||||
const listenAddr = "127.0.0.1:40578"
|
const listenAddr = "127.0.0.1:40578"
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
fixture := protest.BuildFixture("loopprog", 0)
|
fixture := protest.BuildFixture("loopprog", 0)
|
||||||
cmd := exec.Command(dlvbin, "exec", fixture.Path, "--headless", "--continue", "--accept-multiclient", "--log-output=debugger,dap", "--log", "--listen", listenAddr)
|
cmd := exec.Command(dlvbin, "exec", fixture.Path, "--headless", "--continue", "--accept-multiclient", "--log-output=debugger,dap", "--log", "--listen", listenAddr)
|
||||||
@ -887,7 +826,7 @@ func TestDAPCmdWithClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--client-addr", listener.Addr().String())
|
cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--client-addr", listener.Addr().String())
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
@ -934,7 +873,7 @@ func TestDAPCmdWithUnixClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--client-addr=unix:"+listener.Addr().String())
|
cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--client-addr=unix:"+listener.Addr().String())
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
@ -968,7 +907,7 @@ func TestDAPCmdWithUnixClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTrace(t *testing.T) {
|
func TestTrace(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
expected := []byte("> goroutine(1): main.foo(99, 9801)\n>> goroutine(1): main.foo => (9900)\n")
|
expected := []byte("> goroutine(1): main.foo(99, 9801)\n>> goroutine(1): main.foo => (9900)\n")
|
||||||
|
|
||||||
@ -992,7 +931,7 @@ func TestTrace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTrace2(t *testing.T) {
|
func TestTrace2(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
expected := []byte("> goroutine(1): main.callme(2)\n>> goroutine(1): main.callme => (4)\n")
|
expected := []byte("> goroutine(1): main.callme(2)\n>> goroutine(1): main.callme => (4)\n")
|
||||||
|
|
||||||
@ -1016,7 +955,7 @@ func TestTrace2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTraceDirRecursion(t *testing.T) {
|
func TestTraceDirRecursion(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
expected := []byte("> goroutine(1):frame(1) main.A(5, 5)\n > goroutine(1):frame(2) main.A(4, 4)\n > goroutine(1):frame(3) main.A(3, 3)\n > goroutine(1):frame(4) main.A(2, 2)\n > goroutine(1):frame(5) main.A(1, 1)\n >> goroutine(1):frame(5) main.A => (1)\n >> goroutine(1):frame(4) main.A => (2)\n >> goroutine(1):frame(3) main.A => (6)\n >> goroutine(1):frame(2) main.A => (24)\n>> goroutine(1):frame(1) main.A => (120)\n")
|
expected := []byte("> goroutine(1):frame(1) main.A(5, 5)\n > goroutine(1):frame(2) main.A(4, 4)\n > goroutine(1):frame(3) main.A(3, 3)\n > goroutine(1):frame(4) main.A(2, 2)\n > goroutine(1):frame(5) main.A(1, 1)\n >> goroutine(1):frame(5) main.A => (1)\n >> goroutine(1):frame(4) main.A => (2)\n >> goroutine(1):frame(3) main.A => (6)\n >> goroutine(1):frame(2) main.A => (24)\n>> goroutine(1):frame(1) main.A => (120)\n")
|
||||||
|
|
||||||
@ -1049,7 +988,7 @@ func TestTraceDirRecursion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTraceMultipleGoroutines(t *testing.T) {
|
func TestTraceMultipleGoroutines(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
// TODO(derekparker) this test has to be a bit vague to avoid flakiness.
|
// TODO(derekparker) this test has to be a bit vague to avoid flakiness.
|
||||||
// I think a future improvement could be to use regexp captures to match the
|
// I think a future improvement could be to use regexp captures to match the
|
||||||
@ -1088,7 +1027,7 @@ func TestTracePid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
expected := []byte("goroutine(1): main.A()\n>> goroutine(1): main.A => ()\n")
|
expected := []byte("goroutine(1): main.A()\n>> goroutine(1): main.A => ()\n")
|
||||||
|
|
||||||
@ -1121,7 +1060,7 @@ func TestTracePid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTraceBreakpointExists(t *testing.T) {
|
func TestTraceBreakpointExists(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
fixtures := protest.FindFixturesDir()
|
fixtures := protest.FindFixturesDir()
|
||||||
// We always set breakpoints on some runtime functions at startup, so this would return with
|
// We always set breakpoints on some runtime functions at startup, so this would return with
|
||||||
@ -1147,7 +1086,7 @@ func TestTraceBreakpointExists(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTracePrintStack(t *testing.T) {
|
func TestTracePrintStack(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
fixtures := protest.FindFixturesDir()
|
fixtures := protest.FindFixturesDir()
|
||||||
cmd := exec.Command(dlvbin, "trace", "--output", filepath.Join(t.TempDir(), "__debug"), "--stack", "2", filepath.Join(fixtures, "issue573.go"), "foo")
|
cmd := exec.Command(dlvbin, "trace", "--output", filepath.Join(t.TempDir(), "__debug"), "--stack", "2", filepath.Join(fixtures, "issue573.go"), "foo")
|
||||||
@ -1186,7 +1125,7 @@ func TestTraceEBPF(t *testing.T) {
|
|||||||
t.Skip("test must be run as root")
|
t.Skip("test must be run as root")
|
||||||
}
|
}
|
||||||
|
|
||||||
dlvbin := getDlvBinEBPF(t)
|
dlvbin := protest.GetDlvBinaryEBPF(t)
|
||||||
|
|
||||||
expected := []byte("> (1) main.foo(99, 9801)\n=> \"9900\"")
|
expected := []byte("> (1) main.foo(99, 9801)\n=> \"9900\"")
|
||||||
|
|
||||||
@ -1225,7 +1164,7 @@ func TestTraceEBPF2(t *testing.T) {
|
|||||||
t.Skip("test must be run as root")
|
t.Skip("test must be run as root")
|
||||||
}
|
}
|
||||||
|
|
||||||
dlvbin := getDlvBinEBPF(t)
|
dlvbin := protest.GetDlvBinaryEBPF(t)
|
||||||
|
|
||||||
expected := []byte(`> (1) main.callme(10)
|
expected := []byte(`> (1) main.callme(10)
|
||||||
> (1) main.callme(9)
|
> (1) main.callme(9)
|
||||||
@ -1285,7 +1224,7 @@ func TestTraceEBPF3(t *testing.T) {
|
|||||||
t.Skip("test must be run as root")
|
t.Skip("test must be run as root")
|
||||||
}
|
}
|
||||||
|
|
||||||
dlvbin := getDlvBinEBPF(t)
|
dlvbin := protest.GetDlvBinaryEBPF(t)
|
||||||
|
|
||||||
expected := []byte(`> (1) main.tracedFunction(0)
|
expected := []byte(`> (1) main.tracedFunction(0)
|
||||||
> (1) main.tracedFunction(1)
|
> (1) main.tracedFunction(1)
|
||||||
@ -1333,7 +1272,7 @@ func TestTraceEBPF4(t *testing.T) {
|
|||||||
t.Skip("test must be run as root")
|
t.Skip("test must be run as root")
|
||||||
}
|
}
|
||||||
|
|
||||||
dlvbin := getDlvBinEBPF(t)
|
dlvbin := protest.GetDlvBinaryEBPF(t)
|
||||||
|
|
||||||
expected := []byte(`> (1) main.tracedFunction(0, true, 97)
|
expected := []byte(`> (1) main.tracedFunction(0, true, 97)
|
||||||
> (1) main.tracedFunction(1, false, 98)
|
> (1) main.tracedFunction(1, false, 98)
|
||||||
@ -1364,7 +1303,7 @@ func TestTraceEBPF4(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDlvTestChdir(t *testing.T) {
|
func TestDlvTestChdir(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
fixtures := protest.FindFixturesDir()
|
fixtures := protest.FindFixturesDir()
|
||||||
|
|
||||||
@ -1396,7 +1335,7 @@ func TestDlvTestChdir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVersion(t *testing.T) {
|
func TestVersion(t *testing.T) {
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
|
||||||
got, err := exec.Command(dlvbin, "version", "-v").CombinedOutput()
|
got, err := exec.Command(dlvbin, "version", "-v").CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1425,7 +1364,7 @@ func TestStaticcheck(t *testing.T) {
|
|||||||
// where we don't do this it is a deliberate style choice.
|
// where we don't do this it is a deliberate style choice.
|
||||||
// * ST1023 "Redundant type in variable declaration" same as S1021.
|
// * ST1023 "Redundant type in variable declaration" same as S1021.
|
||||||
cmd := exec.Command("staticcheck", args...)
|
cmd := exec.Command("staticcheck", args...)
|
||||||
cmd.Dir = projectRoot()
|
cmd.Dir = protest.ProjectRoot()
|
||||||
cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64")
|
cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64")
|
||||||
out, _ := cmd.CombinedOutput()
|
out, _ := cmd.CombinedOutput()
|
||||||
checkAutogenDoc(t, "_scripts/staticcheck-out.txt", fmt.Sprintf("staticcheck %s > _scripts/staticcheck-out.txt", strings.Join(args, " ")), out)
|
checkAutogenDoc(t, "_scripts/staticcheck-out.txt", fmt.Sprintf("staticcheck %s > _scripts/staticcheck-out.txt", strings.Join(args, " ")), out)
|
||||||
@ -1434,7 +1373,7 @@ func TestStaticcheck(t *testing.T) {
|
|||||||
func TestDefaultBinary(t *testing.T) {
|
func TestDefaultBinary(t *testing.T) {
|
||||||
// Check that when delve is run twice in the same directory simultaneously
|
// Check that when delve is run twice in the same directory simultaneously
|
||||||
// it will pick different default output binary paths.
|
// it will pick different default output binary paths.
|
||||||
dlvbin := getDlvBin(t)
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
fixture := filepath.Join(protest.FindFixturesDir(), "testargs.go")
|
fixture := filepath.Join(protest.FindFixturesDir(), "testargs.go")
|
||||||
|
|
||||||
startOne := func() (io.WriteCloser, func() error, *bytes.Buffer) {
|
startOne := func() (io.WriteCloser, func() error, *bytes.Buffer) {
|
||||||
@ -1475,7 +1414,9 @@ func TestUnixDomainSocket(t *testing.T) {
|
|||||||
|
|
||||||
listenPath := filepath.Join(tmpdir, "delve_test")
|
listenPath := filepath.Join(tmpdir, "delve_test")
|
||||||
|
|
||||||
dlvbin := getDlvBin(t)
|
var err error
|
||||||
|
|
||||||
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
defer os.Remove(dlvbin)
|
defer os.Remove(dlvbin)
|
||||||
|
|
||||||
fixtures := protest.FindFixturesDir()
|
fixtures := protest.FindFixturesDir()
|
||||||
|
@ -665,6 +665,13 @@ func (fn *Function) privateRuntime() bool {
|
|||||||
return len(name) > n && name[:n] == "runtime." && !('A' <= name[n] && name[n] <= 'Z')
|
return len(name) > n && name[:n] == "runtime." && !('A' <= name[n] && name[n] <= 'Z')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fn *Function) CompilationUnitName() string {
|
||||||
|
if fn.cu == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fn.cu.name
|
||||||
|
}
|
||||||
|
|
||||||
func rangeParentName(fnname string) int {
|
func rangeParentName(fnname string) int {
|
||||||
const rangeSuffix = "-range"
|
const rangeSuffix = "-range"
|
||||||
ridx := strings.Index(fnname, rangeSuffix)
|
ridx := strings.Index(fnname, rangeSuffix)
|
||||||
|
@ -22,6 +22,12 @@ var EnableRace = flag.Bool("racetarget", false, "Enables race detector on inferi
|
|||||||
|
|
||||||
var runningWithFixtures bool
|
var runningWithFixtures bool
|
||||||
|
|
||||||
|
var ldFlags string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ldFlags = os.Getenv("CGO_LDFLAGS")
|
||||||
|
}
|
||||||
|
|
||||||
// Fixture is a test binary.
|
// Fixture is a test binary.
|
||||||
type Fixture struct {
|
type Fixture struct {
|
||||||
// Name is the short name of the fixture.
|
// Name is the short name of the fixture.
|
||||||
@ -392,3 +398,62 @@ func RegabiSupported() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ProjectRoot() string {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gopaths := strings.FieldsFunc(os.Getenv("GOPATH"), func(r rune) bool { return r == os.PathListSeparator })
|
||||||
|
for _, curpath := range gopaths {
|
||||||
|
// Detects "gopath mode" when GOPATH contains several paths ex. "d:\\dir\\gopath;f:\\dir\\gopath2"
|
||||||
|
if strings.Contains(wd, curpath) {
|
||||||
|
return filepath.Join(curpath, "src", "github.com", "go-delve", "delve")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val, err := exec.Command("go", "list", "-mod=", "-m", "-f", "{{ .Dir }}").Output()
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // the Go tool was tested to work earlier
|
||||||
|
}
|
||||||
|
return strings.TrimSuffix(string(val), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDlvBinary(t *testing.T) string {
|
||||||
|
// In case this was set in the environment
|
||||||
|
// from getDlvBinEBPF lets clear it here, so
|
||||||
|
// we can ensure we don't get build errors
|
||||||
|
// depending on the test ordering.
|
||||||
|
t.Setenv("CGO_LDFLAGS", ldFlags)
|
||||||
|
var tags []string
|
||||||
|
if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
|
||||||
|
tags = []string{"-tags=exp.winarm64"}
|
||||||
|
}
|
||||||
|
if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
|
||||||
|
tags = []string{"-tags=exp.linuxppc64le"}
|
||||||
|
}
|
||||||
|
if runtime.GOOS == "linux" && runtime.GOARCH == "riscv64" {
|
||||||
|
tags = []string{"-tags=exp.linuxriscv64"}
|
||||||
|
}
|
||||||
|
return getDlvBinInternal(t, tags...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDlvBinaryEBPF(t *testing.T) string {
|
||||||
|
return getDlvBinInternal(t, "-tags", "ebpf")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDlvBinInternal(t *testing.T, goflags ...string) string {
|
||||||
|
dlvbin := filepath.Join(t.TempDir(), "dlv.exe")
|
||||||
|
args := append([]string{"build", "-o", dlvbin}, goflags...)
|
||||||
|
args = append(args, "github.com/go-delve/delve/cmd/dlv")
|
||||||
|
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
fmt.Printf("at %s %s\n", wd, goflags)
|
||||||
|
|
||||||
|
out, err := exec.Command("go", args...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("go build -o %v github.com/go-delve/delve/cmd/dlv: %v\n%s", dlvbin, err, string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return dlvbin
|
||||||
|
}
|
||||||
|
@ -555,10 +555,13 @@ Changes the value of a configuration parameter.
|
|||||||
config substitute-path <from> <to>
|
config substitute-path <from> <to>
|
||||||
config substitute-path <from>
|
config substitute-path <from>
|
||||||
config substitute-path -clear
|
config substitute-path -clear
|
||||||
|
config substitute-path -guess
|
||||||
|
|
||||||
Adds or removes a path substitution rule, if -clear is used all
|
Adds or removes a path substitution rule, if -clear is used all
|
||||||
substitute-path rules are removed. Without arguments shows the current list
|
substitute-path rules are removed. Without arguments shows the current list
|
||||||
of substitute-path rules.
|
of substitute-path rules.
|
||||||
|
The -guess option causes Delve to try to guess your substitute-path
|
||||||
|
configuration automatically.
|
||||||
See also Documentation/cli/substitutepath.md for how the rules are applied.
|
See also Documentation/cli/substitutepath.md for how the rules are applied.
|
||||||
|
|
||||||
config alias <command> <alias>
|
config alias <command> <alias>
|
||||||
|
@ -73,6 +73,17 @@ func configureSetSubstitutePath(t *Term, rest string) error {
|
|||||||
t.conf.SubstitutePath = t.conf.SubstitutePath[:0]
|
t.conf.SubstitutePath = t.conf.SubstitutePath[:0]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if strings.TrimSpace(rest) == "-guess" {
|
||||||
|
rules, err := t.client.GuessSubstitutePath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.conf.SubstitutePath = t.conf.SubstitutePath[:0]
|
||||||
|
for _, rule := range rules {
|
||||||
|
t.conf.SubstitutePath = append(t.conf.SubstitutePath, config.SubstitutePathRule{From: rule[0], To: rule[1]})
|
||||||
|
}
|
||||||
|
rest = "" // print the result
|
||||||
|
}
|
||||||
argv := config.SplitQuotedFields(rest, '"')
|
argv := config.SplitQuotedFields(rest, '"')
|
||||||
if len(argv) == 2 && argv[0] == "-clear" {
|
if len(argv) == 2 && argv[0] == "-clear" {
|
||||||
argv = argv[1:]
|
argv = argv[1:]
|
||||||
|
@ -956,6 +956,37 @@ func (env *Env) starlarkPredeclare() (starlark.StringDict, map[string]string) {
|
|||||||
return env.interfaceToStarlarkValue(rpcRet), nil
|
return env.interfaceToStarlarkValue(rpcRet), nil
|
||||||
})
|
})
|
||||||
doc["get_thread"] = "builtin get_thread(Id)\n\nget_thread gets a thread by its ID."
|
doc["get_thread"] = "builtin get_thread(Id)\n\nget_thread gets a thread by its ID."
|
||||||
|
r["guess_substitute_path"] = starlark.NewBuiltin("guess_substitute_path", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
|
||||||
|
if err := isCancelled(thread); err != nil {
|
||||||
|
return starlark.None, decorateError(thread, err)
|
||||||
|
}
|
||||||
|
var rpcArgs rpc2.GuessSubstitutePathIn
|
||||||
|
var rpcRet rpc2.GuessSubstitutePathOut
|
||||||
|
if len(args) > 0 && args[0] != starlark.None {
|
||||||
|
err := unmarshalStarlarkValue(args[0], &rpcArgs.Args, "Args")
|
||||||
|
if err != nil {
|
||||||
|
return starlark.None, decorateError(thread, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, kv := range kwargs {
|
||||||
|
var err error
|
||||||
|
switch kv[0].(starlark.String) {
|
||||||
|
case "Args":
|
||||||
|
err = unmarshalStarlarkValue(kv[1], &rpcArgs.Args, "Args")
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unknown argument %q", kv[0])
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return starlark.None, decorateError(thread, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := env.ctx.Client().CallAPI("GuessSubstitutePath", &rpcArgs, &rpcRet)
|
||||||
|
if err != nil {
|
||||||
|
return starlark.None, err
|
||||||
|
}
|
||||||
|
return env.interfaceToStarlarkValue(rpcRet), nil
|
||||||
|
})
|
||||||
|
doc["guess_substitute_path"] = "builtin guess_substitute_path(Args)"
|
||||||
r["is_multiclient"] = starlark.NewBuiltin("is_multiclient", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
|
r["is_multiclient"] = starlark.NewBuiltin("is_multiclient", func(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
|
||||||
if err := isCancelled(thread); err != nil {
|
if err := isCancelled(thread); err != nil {
|
||||||
return starlark.None, decorateError(thread, err)
|
return starlark.None, decorateError(thread, err)
|
||||||
|
@ -677,3 +677,10 @@ type Target struct {
|
|||||||
CmdLine string
|
CmdLine string
|
||||||
CurrentThread *Thread
|
CurrentThread *Thread
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GuessSubstitutePathIn are the input parameters used to guess a substitute-path configuration automatically.
|
||||||
|
type GuessSubstitutePathIn struct {
|
||||||
|
ImportPathOfMainPackage string
|
||||||
|
ClientGOROOT string
|
||||||
|
ClientModuleDirectories map[string]string
|
||||||
|
}
|
||||||
|
@ -205,6 +205,9 @@ type Client interface {
|
|||||||
// GetDebugInfoDirectories returns the list of directories used to search for debug symbols
|
// GetDebugInfoDirectories returns the list of directories used to search for debug symbols
|
||||||
GetDebugInfoDirectories() ([]string, error)
|
GetDebugInfoDirectories() ([]string, error)
|
||||||
|
|
||||||
|
// GuessSubstitutePath tries to guess a substitute-path configuration for the client
|
||||||
|
GuessSubstitutePath() ([][2]string, error)
|
||||||
|
|
||||||
// CallAPI allows calling an arbitrary rpc method (used by starlark bindings)
|
// CallAPI allows calling an arbitrary rpc method (used by starlark bindings)
|
||||||
CallAPI(method string, args, reply interface{}) error
|
CallAPI(method string, args, reply interface{}) error
|
||||||
}
|
}
|
||||||
|
@ -1975,6 +1975,18 @@ func (s *Session) onAttachRequest(request *dap.AttachRequest) {
|
|||||||
|
|
||||||
s.setLaunchAttachArgs(args.LaunchAttachCommonConfig)
|
s.setLaunchAttachArgs(args.LaunchAttachCommonConfig)
|
||||||
|
|
||||||
|
if len(args.LaunchAttachCommonConfig.SubstitutePath) == 0 && args.GuessSubstitutePath != nil && s.debugger != nil {
|
||||||
|
server2Client := s.debugger.GuessSubstitutePath(args.GuessSubstitutePath)
|
||||||
|
clientToServer := make([][2]string, 0, len(server2Client))
|
||||||
|
serverToClient := make([][2]string, 0, len(server2Client))
|
||||||
|
for serverDir, clientDir := range server2Client {
|
||||||
|
serverToClient = append(serverToClient, [2]string{serverDir, clientDir})
|
||||||
|
clientToServer = append(clientToServer, [2]string{clientDir, serverDir})
|
||||||
|
}
|
||||||
|
s.args.substitutePathClientToServer = clientToServer
|
||||||
|
s.args.substitutePathServerToClient = serverToClient
|
||||||
|
}
|
||||||
|
|
||||||
// Notify the client that the debugger is ready to start accepting
|
// Notify the client that the debugger is ready to start accepting
|
||||||
// configuration requests for setting breakpoints, etc. The client
|
// configuration requests for setting breakpoints, etc. The client
|
||||||
// will end the configuration sequence with 'configurationDone'.
|
// will end the configuration sequence with 'configurationDone'.
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-delve/delve/service/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Launch debug sessions support the following modes:
|
// Launch debug sessions support the following modes:
|
||||||
@ -252,6 +254,11 @@ type AttachConfig struct {
|
|||||||
// Wait for a process with a name beginning with this prefix.
|
// Wait for a process with a name beginning with this prefix.
|
||||||
AttachWaitFor string `json:"waitFor,omitempty"`
|
AttachWaitFor string `json:"waitFor,omitempty"`
|
||||||
|
|
||||||
|
// GuessSubstitutePath is used to automatically guess SubstitutePath if it
|
||||||
|
// is not specified explicitly. It should be copied from the output of
|
||||||
|
// 'dlv substitute-path-guess-helper'.
|
||||||
|
GuessSubstitutePath *api.GuessSubstitutePathIn `json:"guessSubstitutePath,omitempty"`
|
||||||
|
|
||||||
LaunchAttachCommonConfig
|
LaunchAttachCommonConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -2551,3 +2552,157 @@ func (d *Debugger) maybePrintUnattendedBreakpointWarning(stopReason proc.StopRea
|
|||||||
}
|
}
|
||||||
api.PrintStack(formatPathFunc, os.Stderr, apiFrames, "", false, api.StackTraceColors{}, includeFunc)
|
api.PrintStack(formatPathFunc, os.Stderr, apiFrames, "", false, api.StackTraceColors{}, includeFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GuessSubstitutePath returns a substitute-path configuration that maps
|
||||||
|
// server paths to client paths by examining the executable file and a map
|
||||||
|
// of module paths to client directories (clientMod2Dir) passed as input.
|
||||||
|
func (d *Debugger) GuessSubstitutePath(args *api.GuessSubstitutePathIn) map[string]string {
|
||||||
|
bis := []*proc.BinaryInfo{}
|
||||||
|
bins := [][]proc.Function{}
|
||||||
|
tgt := proc.ValidTargets{Group: d.target}
|
||||||
|
for tgt.Next() {
|
||||||
|
bi := tgt.BinInfo()
|
||||||
|
bis = append(bis, bi)
|
||||||
|
bins = append(bins, bi.Functions)
|
||||||
|
}
|
||||||
|
return guessSubstitutePath(args, bins, func(biIdx int, fn *proc.Function) string {
|
||||||
|
file, _ := bis[biIdx].EntryLineForFunc(fn)
|
||||||
|
return file
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func guessSubstitutePath(args *api.GuessSubstitutePathIn, bins [][]proc.Function, fileForFunc func(int, *proc.Function) string) map[string]string {
|
||||||
|
serverMod2Dir := map[string]string{}
|
||||||
|
serverMod2DirCandidate := map[string]map[string]int{}
|
||||||
|
pkg2mod := map[string]string{}
|
||||||
|
|
||||||
|
for mod := range args.ClientModuleDirectories {
|
||||||
|
serverMod2DirCandidate[mod] = make(map[string]int)
|
||||||
|
}
|
||||||
|
|
||||||
|
const minEvidence = 10
|
||||||
|
const decisionThreshold = 0.8
|
||||||
|
|
||||||
|
totCandidates := func(mod string) int {
|
||||||
|
r := 0
|
||||||
|
for _, cnt := range serverMod2DirCandidate[mod] {
|
||||||
|
r += cnt
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
bestCandidate := func(mod string) string {
|
||||||
|
best := ""
|
||||||
|
for dir, cnt := range serverMod2DirCandidate[mod] {
|
||||||
|
if cnt > serverMod2DirCandidate[mod][best] {
|
||||||
|
best = dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best
|
||||||
|
}
|
||||||
|
|
||||||
|
slashes := func(s string) int {
|
||||||
|
r := 0
|
||||||
|
for _, ch := range s {
|
||||||
|
if ch == '/' {
|
||||||
|
r++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
serverGoroot := ""
|
||||||
|
|
||||||
|
logger := logflags.DebuggerLogger()
|
||||||
|
|
||||||
|
for binIdx, bin := range bins {
|
||||||
|
for i := range bin {
|
||||||
|
fn := &bin[i]
|
||||||
|
|
||||||
|
if fn.Name == "runtime.main" && serverGoroot == "" {
|
||||||
|
file := fileForFunc(binIdx, fn)
|
||||||
|
serverGoroot = path.Dir(path.Dir(path.Dir(file)))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fnpkg := fn.PackageName()
|
||||||
|
if fn.CompilationUnitName() != "" && strings.ReplaceAll(fn.CompilationUnitName(), "\\", "/") != fnpkg {
|
||||||
|
// inlined
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fnpkg == "main" && binIdx == 0 && args.ImportPathOfMainPackage != "" {
|
||||||
|
fnpkg = args.ImportPathOfMainPackage
|
||||||
|
}
|
||||||
|
|
||||||
|
fnmod := ""
|
||||||
|
|
||||||
|
if mod, ok := pkg2mod[fnpkg]; ok {
|
||||||
|
fnmod = mod
|
||||||
|
} else {
|
||||||
|
for mod := range args.ClientModuleDirectories {
|
||||||
|
if strings.HasPrefix(fnpkg, mod) {
|
||||||
|
fnmod = mod
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkg2mod[fnpkg] = fnmod
|
||||||
|
if fnmod == "" {
|
||||||
|
logger.Debugf("No module detected for server package %q", fnpkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fnmod == "" {
|
||||||
|
// not in any module we are interested in
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if serverMod2Dir[fnmod] != "" {
|
||||||
|
// already decided
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
elems := slashes(fnpkg[len(fnmod):])
|
||||||
|
|
||||||
|
file := fileForFunc(binIdx, fn)
|
||||||
|
if file == "" || file == "<autogenerated>" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.Debugf("considering %s pkg:%s compile unit:%s file:%s", fn.Name, fnpkg, fn.CompilationUnitName(), file)
|
||||||
|
dir := path.Dir(file) // note: paths are normalized to always use '/' as a separator by pkg/dwarf/line
|
||||||
|
if slashes(dir) < elems {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i := 0; i < elems; i++ {
|
||||||
|
dir = path.Dir(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
serverMod2DirCandidate[fnmod][dir]++
|
||||||
|
|
||||||
|
n := totCandidates(fnmod)
|
||||||
|
best := bestCandidate(fnmod)
|
||||||
|
if n > minEvidence && float64(serverMod2DirCandidate[fnmod][best])/float64(n) > decisionThreshold {
|
||||||
|
serverMod2Dir[fnmod] = best
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for mod := range args.ClientModuleDirectories {
|
||||||
|
if serverMod2Dir[mod] == "" {
|
||||||
|
serverMod2Dir[mod] = bestCandidate(mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server2Client := make(map[string]string)
|
||||||
|
|
||||||
|
for mod, clientDir := range args.ClientModuleDirectories {
|
||||||
|
if serverMod2Dir[mod] != "" {
|
||||||
|
server2Client[serverMod2Dir[mod]] = clientDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverGoroot != "" && args.ClientGOROOT != "" {
|
||||||
|
server2Client[serverGoroot] = args.ClientGOROOT
|
||||||
|
}
|
||||||
|
|
||||||
|
return server2Client
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package debugger
|
package debugger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -9,10 +10,20 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-delve/delve/pkg/gobuild"
|
"github.com/go-delve/delve/pkg/gobuild"
|
||||||
|
"github.com/go-delve/delve/pkg/logflags"
|
||||||
|
"github.com/go-delve/delve/pkg/proc"
|
||||||
protest "github.com/go-delve/delve/pkg/proc/test"
|
protest "github.com/go-delve/delve/pkg/proc/test"
|
||||||
"github.com/go-delve/delve/service/api"
|
"github.com/go-delve/delve/service/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
var logConf string
|
||||||
|
flag.StringVar(&logConf, "log", "", "configures logging")
|
||||||
|
flag.Parse()
|
||||||
|
logflags.Setup(logConf != "", logConf, "")
|
||||||
|
os.Exit(protest.RunTestsWithFixtures(m))
|
||||||
|
}
|
||||||
|
|
||||||
func TestDebugger_LaunchNoMain(t *testing.T) {
|
func TestDebugger_LaunchNoMain(t *testing.T) {
|
||||||
fixturesDir := protest.FindFixturesDir()
|
fixturesDir := protest.FindFixturesDir()
|
||||||
nomaindir := filepath.Join(fixturesDir, "nomaindir")
|
nomaindir := filepath.Join(fixturesDir, "nomaindir")
|
||||||
@ -100,3 +111,45 @@ func TestDebugger_LaunchCurrentDir(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func guessSubstitutePathHelper(t *testing.T, args *api.GuessSubstitutePathIn, fnpaths [][2]string, tgt map[string]string) {
|
||||||
|
const base = 0x40000
|
||||||
|
t.Helper()
|
||||||
|
bins := [][]proc.Function{[]proc.Function{}}
|
||||||
|
for i, fnpath := range fnpaths {
|
||||||
|
bins[0] = append(bins[0], proc.Function{Name: fnpath[0], Entry: uint64(base + i)})
|
||||||
|
}
|
||||||
|
out := guessSubstitutePath(args, bins, func(_ int, fn *proc.Function) string {
|
||||||
|
return fnpaths[fn.Entry-base][1]
|
||||||
|
})
|
||||||
|
t.Logf("%#v\n", out)
|
||||||
|
if len(out) != len(tgt) {
|
||||||
|
t.Errorf("wrong number of entries")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for k := range out {
|
||||||
|
if out[k] != tgt[k] {
|
||||||
|
t.Errorf("mismatch for directory %q", k)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGuessSubstitutePathMinimalMain(t *testing.T) {
|
||||||
|
// When the main module only contains a single package check that its mapping still works
|
||||||
|
guessSubstitutePathHelper(t,
|
||||||
|
&api.GuessSubstitutePathIn{
|
||||||
|
ImportPathOfMainPackage: "github.com/ccampo133/go-docker-alpine-remote-debug",
|
||||||
|
ClientGOROOT: "/user/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.0.linux-amd64",
|
||||||
|
ClientModuleDirectories: map[string]string{
|
||||||
|
"github.com/ccampo133/go-docker-alpine-remote-debug": "/user/gohome/go-docker-alpine-remote-debug",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[][2]string{
|
||||||
|
{"main.main", "/app/main.go"},
|
||||||
|
{"main.hello", "/app/main.go"},
|
||||||
|
{"runtime.main", "/usr/local/go/src/runtime/main.go"}},
|
||||||
|
map[string]string{
|
||||||
|
"/usr/local/go": "/user/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.23.0.linux-amd64",
|
||||||
|
"/app": "/user/gohome/go-docker-alpine-remote-debug"})
|
||||||
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package rpc2
|
package rpc2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/rpc"
|
"net/rpc"
|
||||||
"net/rpc/jsonrpc"
|
"net/rpc/jsonrpc"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-delve/delve/service"
|
"github.com/go-delve/delve/service"
|
||||||
@ -578,6 +583,86 @@ func (c *RPCClient) GetDebugInfoDirectories() ([]string, error) {
|
|||||||
return out.List, err
|
return out.List, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type goListEntry struct {
|
||||||
|
Dir string
|
||||||
|
ImportPath string
|
||||||
|
Name string
|
||||||
|
Module *goListModule
|
||||||
|
}
|
||||||
|
|
||||||
|
type goListModule struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeGuessSusbtitutePathIn returns a mapping from modules to client
|
||||||
|
// directories using "go list".
|
||||||
|
func MakeGuessSusbtitutePathIn() (*api.GuessSubstitutePathIn, error) {
|
||||||
|
cmd := exec.Command("go", "list", "--json", "all")
|
||||||
|
buf, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
importPathOfMainPackage := ""
|
||||||
|
importPathOfMainPackageOk := true
|
||||||
|
mod2dir := make(map[string]string)
|
||||||
|
d := json.NewDecoder(bytes.NewReader(buf))
|
||||||
|
for d.More() {
|
||||||
|
var e goListEntry
|
||||||
|
err := d.Decode(&e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if e.Module == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(e.ImportPath, e.Module.Path) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pkgWithoutModule := e.ImportPath[len(e.Module.Path):]
|
||||||
|
elems := 0
|
||||||
|
for _, c := range pkgWithoutModule {
|
||||||
|
if c == '/' {
|
||||||
|
elems++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir := e.Dir
|
||||||
|
for i := 0; i < elems; i++ {
|
||||||
|
dir = filepath.Dir(dir)
|
||||||
|
}
|
||||||
|
if mod2dir[e.Module.Path] != "" && mod2dir[e.Module.Path] != dir {
|
||||||
|
return nil, fmt.Errorf("could not determine path for module %s (got %q and %q)", e.Module.Path, mod2dir[e.Module.Path], dir)
|
||||||
|
}
|
||||||
|
mod2dir[e.Module.Path] = dir
|
||||||
|
if e.Name == "main" {
|
||||||
|
if importPathOfMainPackage != "" && importPathOfMainPackage != e.ImportPath {
|
||||||
|
importPathOfMainPackageOk = false
|
||||||
|
}
|
||||||
|
importPathOfMainPackage = e.ImportPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf, err = exec.Command("go", "env", "GOROOT").Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientGoroot := strings.TrimSpace(string(buf))
|
||||||
|
if !importPathOfMainPackageOk {
|
||||||
|
// There were multiple main packages
|
||||||
|
importPathOfMainPackage = ""
|
||||||
|
}
|
||||||
|
return &api.GuessSubstitutePathIn{ClientGOROOT: clientGoroot, ImportPathOfMainPackage: importPathOfMainPackage, ClientModuleDirectories: mod2dir}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RPCClient) GuessSubstitutePath() ([][2]string, error) {
|
||||||
|
in, err := MakeGuessSusbtitutePathIn()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &GuessSubstitutePathOut{}
|
||||||
|
err = c.call("GuessSubstitutePath", GuessSubstitutePathIn{*in}, out)
|
||||||
|
return out.List, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *RPCClient) call(method string, args, reply interface{}) error {
|
func (c *RPCClient) call(method string, args, reply interface{}) error {
|
||||||
return c.client.Call("RPCServer."+method, args, reply)
|
return c.client.Call("RPCServer."+method, args, reply)
|
||||||
}
|
}
|
||||||
|
@ -1146,3 +1146,19 @@ func (s *RPCServer) DebugInfoDirectories(arg DebugInfoDirectoriesIn, out *DebugI
|
|||||||
out.List = s.debugger.DebugInfoDirectories()
|
out.List = s.debugger.DebugInfoDirectories()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GuessSubstitutePathIn struct {
|
||||||
|
Args api.GuessSubstitutePathIn
|
||||||
|
}
|
||||||
|
|
||||||
|
type GuessSubstitutePathOut struct {
|
||||||
|
List [][2]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RPCServer) GuessSubstitutePath(arg GuessSubstitutePathIn, out *GuessSubstitutePathOut) error {
|
||||||
|
m := s.debugger.GuessSubstitutePath(&arg.Args)
|
||||||
|
for k, v := range m {
|
||||||
|
out.List = append(out.List, [2]string{k, v})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -3167,3 +3167,135 @@ func TestBreakpointVariablesWithoutG(t *testing.T) {
|
|||||||
assertNoError(state.Err, t, "Continue()")
|
assertNoError(state.Err, t, "Continue()")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGuessSubstitutePath(t *testing.T) {
|
||||||
|
t.Setenv("NOCERT", "1")
|
||||||
|
slashnorm := func(s string) string {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strings.ReplaceAll(s, "\\", "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
guess := func(t *testing.T, goflags string) [][2]string {
|
||||||
|
oldgoflags := os.Getenv("GOFLAGS")
|
||||||
|
os.Setenv("GOFLAGS", goflags)
|
||||||
|
defer os.Setenv("GOFLAGS", oldgoflags)
|
||||||
|
|
||||||
|
dlvbin := protest.GetDlvBinary(t)
|
||||||
|
defer os.Remove(dlvbin)
|
||||||
|
|
||||||
|
listener, clientConn := service.ListenerPipe()
|
||||||
|
defer listener.Close()
|
||||||
|
server := rpccommon.NewServer(&service.Config{
|
||||||
|
Listener: listener,
|
||||||
|
ProcessArgs: []string{dlvbin, "help"},
|
||||||
|
Debugger: debugger.Config{
|
||||||
|
Backend: testBackend,
|
||||||
|
CheckGoVersion: true,
|
||||||
|
BuildFlags: "", // build flags can be an empty string here because the only test that uses it, does not set special flags.
|
||||||
|
ExecuteKind: debugger.ExecutingExistingFile,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err := server.Run(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := rpc2.NewClientFromConn(clientConn)
|
||||||
|
defer client.Detach(true)
|
||||||
|
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "ppc64le":
|
||||||
|
os.Setenv("GOFLAGS", "-tags=exp.linuxppc64le")
|
||||||
|
case "riscv64":
|
||||||
|
os.Setenv("GOFLAGS", "-tags=exp.linuxriscv64")
|
||||||
|
}
|
||||||
|
|
||||||
|
gsp, err := client.GuessSubstitutePath()
|
||||||
|
assertNoError(err, t, "GuessSubstitutePath")
|
||||||
|
return gsp
|
||||||
|
}
|
||||||
|
|
||||||
|
delvePath := protest.ProjectRoot()
|
||||||
|
var nmods int = -1
|
||||||
|
|
||||||
|
t.Run("Normal", func(t *testing.T) {
|
||||||
|
gsp := guess(t, "")
|
||||||
|
t.Logf("Normal build: %d", len(gsp))
|
||||||
|
if len(gsp) == 0 {
|
||||||
|
t.Fatalf("not enough modules")
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for _, e := range gsp {
|
||||||
|
t.Logf("\t%s -> %s", e[0], e[1])
|
||||||
|
if e[0] != slashnorm(e[1]) {
|
||||||
|
t.Fatalf("mismatch %q %q", e[0], e[1])
|
||||||
|
}
|
||||||
|
if e[1] == delvePath {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nmods = len(gsp)
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("could not find main module path %q", delvePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("CI") == "true" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Modules", func(t *testing.T) {
|
||||||
|
gsp := guess(t, "-mod=mod")
|
||||||
|
t.Logf("Modules build: %d", len(gsp))
|
||||||
|
if len(gsp) != nmods && nmods != -1 {
|
||||||
|
t.Fatalf("not enough modules")
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for _, e := range gsp {
|
||||||
|
t.Logf("\t%s -> %s", e[0], e[1])
|
||||||
|
if e[0] == slashnorm(delvePath) && e[1] == delvePath {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("could not find main module path %q", delvePath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Trimpath", func(t *testing.T) {
|
||||||
|
gsp := guess(t, "-trimpath")
|
||||||
|
t.Logf("Trimpath build: %d", len(gsp))
|
||||||
|
if len(gsp) != nmods && nmods != -1 {
|
||||||
|
t.Fatalf("not enough modules")
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for _, e := range gsp {
|
||||||
|
t.Logf("\t%s -> %s", e[0], e[1])
|
||||||
|
if e[0] == "github.com/go-delve/delve" && e[1] == delvePath {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("could not find main module path %q", delvePath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ModulesTrimpath", func(t *testing.T) {
|
||||||
|
gsp := guess(t, "-trimpath -mod=mod")
|
||||||
|
t.Logf("Modules+Trimpath build: %d", len(gsp))
|
||||||
|
if len(gsp) != nmods && nmods != -1 {
|
||||||
|
t.Fatalf("not enough modules")
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for _, e := range gsp {
|
||||||
|
t.Logf("\t%s -> %s", e[0], e[1])
|
||||||
|
if e[0] == "github.com/go-delve/delve" && e[1] == delvePath {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("could not find main module path %q", delvePath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user