dap: define LaunchConfig/AttachConfig types (#2571)
Formally define these types and document their meaning.
We will auto-generate the dlv-dap documentation from these Go type doc.
mapToStruct is a helper that sets the given struct's fields with the
info in map[string]interface{} (launch/attach's Arguments). We achieve
this by reencoding map[string]interface{} to json and decoding back to
the target struct. If go-dap left the implementation-specific arguments
as json.RawMessage and let the implementation decode as needed, this
reencoding could've been avoided.
encoding/json itself does not have mean to enforce required fields.
There was a test case that checks substitutePath elements must set
both from/to fields. Path.UnmarshalJSON implements the check.
I am not yet sure about the need for distinction between missing
'from/to' and empty strings yet. (empty value is useful when dealing with
a binary built with trimpath, right?)
A minor behavior change - previously, if noDebug is not a boolean type,
we ignored the attribute silently. Since we use json decoding, any
mismatched types will cause an error and this non-boolean type noDebug
attribute will result in launch failure.
This commit is contained in:
parent
7c91fa0d72
commit
1433c07957
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
||||
github.com/cosiner/argv v0.1.0
|
||||
github.com/creack/pty v1.1.9
|
||||
github.com/derekparker/trie v0.0.0-20200317170641-1fdf38b7b0e9
|
||||
github.com/google/go-dap v0.5.0
|
||||
github.com/google/go-dap v0.5.1-0.20210713061233-c91b005e3987
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/mattn/go-colorable v0.0.9
|
||||
github.com/mattn/go-isatty v0.0.3
|
||||
|
||||
6
go.sum
6
go.sum
@ -70,8 +70,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-dap v0.5.0 h1:RMHAVn5xeunBakYk65ggHXttk6qjZVdbmi+xhAoL2wY=
|
||||
github.com/google/go-dap v0.5.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
|
||||
github.com/google/go-dap v0.5.1-0.20210713061233-c91b005e3987 h1:aghNk+kvabZ5I1OC3cNHWvfZ8svcoDLAGyKYimqyGVk=
|
||||
github.com/google/go-dap v0.5.1-0.20210713061233-c91b005e3987/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
@ -185,10 +185,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
||||
@ -184,15 +184,20 @@ func (c *Client) InitializeRequestWithArgs(args dap.InitializeRequestArguments)
|
||||
c.send(request)
|
||||
}
|
||||
|
||||
func toRawMessage(in interface{}) json.RawMessage {
|
||||
out, _ := json.Marshal(in)
|
||||
return out
|
||||
}
|
||||
|
||||
// LaunchRequest sends a 'launch' request with the specified args.
|
||||
func (c *Client) LaunchRequest(mode, program string, stopOnEntry bool) {
|
||||
request := &dap.LaunchRequest{Request: *c.newRequest("launch")}
|
||||
request.Arguments = map[string]interface{}{
|
||||
request.Arguments = toRawMessage(map[string]interface{}{
|
||||
"request": "launch",
|
||||
"mode": mode,
|
||||
"program": program,
|
||||
"stopOnEntry": stopOnEntry,
|
||||
}
|
||||
})
|
||||
c.send(request)
|
||||
}
|
||||
|
||||
@ -201,7 +206,7 @@ func (c *Client) LaunchRequest(mode, program string, stopOnEntry bool) {
|
||||
// test for values of unexpected types or unspecified values.
|
||||
func (c *Client) LaunchRequestWithArgs(arguments map[string]interface{}) {
|
||||
request := &dap.LaunchRequest{Request: *c.newRequest("launch")}
|
||||
request.Arguments = arguments
|
||||
request.Arguments = toRawMessage(arguments)
|
||||
c.send(request)
|
||||
}
|
||||
|
||||
@ -209,7 +214,7 @@ func (c *Client) LaunchRequestWithArgs(arguments map[string]interface{}) {
|
||||
// arguments.
|
||||
func (c *Client) AttachRequest(arguments map[string]interface{}) {
|
||||
request := &dap.AttachRequest{Request: *c.newRequest("attach")}
|
||||
request.Arguments = arguments
|
||||
request.Arguments = toRawMessage(arguments)
|
||||
c.send(request)
|
||||
}
|
||||
|
||||
|
||||
@ -150,6 +150,8 @@ type launchAttachArgs struct {
|
||||
}
|
||||
|
||||
// defaultArgs borrows the defaults for the arguments from the original vscode-go adapter.
|
||||
// TODO(polinasok): clean up this and its reference (Server.args)
|
||||
// in favor of default*Config variables defined in types.go.
|
||||
var defaultArgs = launchAttachArgs{
|
||||
stopOnEntry: false,
|
||||
stackTraceDepth: 50,
|
||||
@ -218,43 +220,18 @@ func NewServer(config *service.Config) *Server {
|
||||
|
||||
// If user-specified options are provided via Launch/AttachRequest,
|
||||
// we override the defaults for optional args.
|
||||
func (s *Server) setLaunchAttachArgs(request dap.LaunchAttachRequest) error {
|
||||
stop, ok := request.GetArguments()["stopOnEntry"].(bool)
|
||||
if ok {
|
||||
s.args.stopOnEntry = stop
|
||||
func (s *Server) setLaunchAttachArgs(args LaunchAttachCommonConfig) error {
|
||||
s.args.stopOnEntry = args.StopOnEntry
|
||||
if depth := args.StackTraceDepth; depth > 0 {
|
||||
s.args.stackTraceDepth = depth
|
||||
}
|
||||
depth, ok := request.GetArguments()["stackTraceDepth"].(float64)
|
||||
if ok && depth > 0 {
|
||||
s.args.stackTraceDepth = int(depth)
|
||||
}
|
||||
globals, ok := request.GetArguments()["showGlobalVariables"].(bool)
|
||||
if ok {
|
||||
s.args.showGlobalVariables = globals
|
||||
}
|
||||
paths, ok := request.GetArguments()["substitutePath"]
|
||||
if ok {
|
||||
typeMismatchError := fmt.Errorf("'substitutePath' attribute '%v' in debug configuration is not a []{'from': string, 'to': string}", paths)
|
||||
pathsParsed, ok := paths.([]interface{})
|
||||
if !ok {
|
||||
return typeMismatchError
|
||||
}
|
||||
clientToServer := make([][2]string, 0, len(pathsParsed))
|
||||
serverToClient := make([][2]string, 0, len(pathsParsed))
|
||||
for _, arg := range pathsParsed {
|
||||
pathMapping, ok := arg.(map[string]interface{})
|
||||
if !ok {
|
||||
return typeMismatchError
|
||||
}
|
||||
from, ok := pathMapping["from"].(string)
|
||||
if !ok {
|
||||
return typeMismatchError
|
||||
}
|
||||
to, ok := pathMapping["to"].(string)
|
||||
if !ok {
|
||||
return typeMismatchError
|
||||
}
|
||||
clientToServer = append(clientToServer, [2]string{from, to})
|
||||
serverToClient = append(serverToClient, [2]string{to, from})
|
||||
s.args.showGlobalVariables = args.ShowGlobalVariables
|
||||
if paths := args.SubstitutePath; len(paths) > 0 {
|
||||
clientToServer := make([][2]string, 0, len(paths))
|
||||
serverToClient := make([][2]string, 0, len(paths))
|
||||
for _, p := range paths {
|
||||
clientToServer = append(clientToServer, [2]string{p.From, p.To})
|
||||
serverToClient = append(serverToClient, [2]string{p.To, p.From})
|
||||
}
|
||||
s.args.substitutePathClientToServer = clientToServer
|
||||
s.args.substitutePathServerToClient = serverToClient
|
||||
@ -766,44 +743,38 @@ func cleanExeName(name string) string {
|
||||
}
|
||||
|
||||
func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
// Validate launch request mode
|
||||
mode, ok := request.Arguments["mode"]
|
||||
if !ok || mode == "" {
|
||||
mode = "debug"
|
||||
}
|
||||
if !isValidLaunchMode(mode) {
|
||||
var args = defaultLaunchConfig // narrow copy for initializing non-zero default values
|
||||
if err := unmarshalLaunchAttachArgs(request.Arguments, &args); err != nil {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
fmt.Sprintf("Unsupported 'mode' value %q in debug configuration.", mode))
|
||||
FailedToLaunch, "Failed to launch", fmt.Sprintf("invalid debug configuration - %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
mode := args.Mode
|
||||
if mode == "" {
|
||||
mode = "debug"
|
||||
}
|
||||
if !isValidLaunchMode(mode) {
|
||||
s.sendErrorResponse(request.Request, FailedToLaunch, "Failed to launch", fmt.Sprintf("invalid debug configuration - unsupported 'mode' attribute %q", mode))
|
||||
return
|
||||
}
|
||||
// TODO(polina): Respond with an error if debug session is in progress?
|
||||
program, ok := request.Arguments["program"].(string)
|
||||
if (!ok || program == "") && mode != "replay" { // Only fail on modes requiring a program
|
||||
program := args.Program
|
||||
if program == "" && mode != "replay" { // Only fail on modes requiring a program
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
"The program attribute is missing in debug configuration.")
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := request.Arguments["backend"]
|
||||
if ok {
|
||||
backendParsed, ok := backend.(string)
|
||||
if !ok {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
fmt.Sprintf("'backend' attribute '%v' in debug configuration is not a string.", backend))
|
||||
return
|
||||
}
|
||||
s.config.Debugger.Backend = backendParsed
|
||||
if backend := args.Backend; backend != "" {
|
||||
s.config.Debugger.Backend = backend
|
||||
} else {
|
||||
s.config.Debugger.Backend = "default"
|
||||
}
|
||||
|
||||
if mode == "replay" {
|
||||
traceDirPath, _ := request.Arguments["traceDirPath"].(string)
|
||||
|
||||
traceDirPath := args.TraceDirPath
|
||||
// Validate trace directory
|
||||
if traceDirPath == "" {
|
||||
s.sendErrorResponse(request.Request,
|
||||
@ -818,17 +789,14 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
}
|
||||
|
||||
if mode == "core" {
|
||||
coreFilePath, _ := request.Arguments["coreFilePath"].(string)
|
||||
|
||||
coreFilePath := args.CoreFilePath
|
||||
// Validate core dump path
|
||||
if coreFilePath == "" {
|
||||
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
"The 'coreFilePath' attribute is missing in debug configuration.")
|
||||
return
|
||||
}
|
||||
|
||||
// Assign the non-empty core file path to debugger configuration. This will
|
||||
// trigger a native core file replay instead of an rr trace replay
|
||||
s.config.Debugger.CoreFile = coreFilePath
|
||||
@ -839,8 +807,8 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
|
||||
// Prepare the debug executable filename, build flags and build it
|
||||
if mode == "debug" || mode == "test" {
|
||||
output, ok := request.Arguments["output"].(string)
|
||||
if !ok || output == "" {
|
||||
output := args.Output
|
||||
if output == "" {
|
||||
output = defaultDebugBinary
|
||||
}
|
||||
output = cleanExeName(output)
|
||||
@ -850,17 +818,7 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
buildFlags := ""
|
||||
buildFlagsArg, ok := request.Arguments["buildFlags"]
|
||||
if ok {
|
||||
buildFlags, ok = buildFlagsArg.(string)
|
||||
if !ok {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
fmt.Sprintf("'buildFlags' attribute '%v' in debug configuration is not a string.", buildFlagsArg))
|
||||
return
|
||||
}
|
||||
}
|
||||
buildFlags := args.BuildFlags
|
||||
|
||||
var cmd string
|
||||
var out []byte
|
||||
@ -890,56 +848,21 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
err := s.setLaunchAttachArgs(request)
|
||||
if err != nil {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
err.Error())
|
||||
if err := s.setLaunchAttachArgs(args.LaunchAttachCommonConfig); err != nil {
|
||||
s.sendErrorResponse(request.Request, FailedToLaunch, "Failed to launch", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var targetArgs []string
|
||||
args, ok := request.Arguments["args"]
|
||||
if ok {
|
||||
argsParsed, ok := args.([]interface{})
|
||||
if !ok {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
fmt.Sprintf("'args' attribute '%v' in debug configuration is not an array.", args))
|
||||
return
|
||||
}
|
||||
for _, arg := range argsParsed {
|
||||
argParsed, ok := arg.(string)
|
||||
if !ok {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
fmt.Sprintf("value '%v' in 'args' attribute in debug configuration is not a string.", arg))
|
||||
return
|
||||
}
|
||||
targetArgs = append(targetArgs, argParsed)
|
||||
}
|
||||
}
|
||||
|
||||
s.config.ProcessArgs = append([]string{program}, targetArgs...)
|
||||
s.config.ProcessArgs = append([]string{program}, args.Args...)
|
||||
s.config.Debugger.WorkingDir = filepath.Dir(program)
|
||||
|
||||
// Set the WorkingDir for this program to the one specified in the request arguments.
|
||||
wd, ok := request.Arguments["cwd"]
|
||||
if ok {
|
||||
wdParsed, ok := wd.(string)
|
||||
if !ok {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToLaunch, "Failed to launch",
|
||||
fmt.Sprintf("'cwd' attribute '%v' in debug configuration is not a string.", wd))
|
||||
return
|
||||
}
|
||||
s.config.Debugger.WorkingDir = wdParsed
|
||||
if args.Cwd != "" {
|
||||
s.config.Debugger.WorkingDir = args.Cwd
|
||||
}
|
||||
|
||||
s.log.Debugf("running binary '%s' in '%s'", program, s.config.Debugger.WorkingDir)
|
||||
if noDebug, ok := request.Arguments["noDebug"].(bool); ok && noDebug {
|
||||
if args.NoDebug {
|
||||
s.mu.Lock()
|
||||
cmd, err := s.newNoDebugProcess(program, targetArgs, s.config.Debugger.WorkingDir)
|
||||
cmd, err := s.newNoDebugProcess(program, args.Args, s.config.Debugger.WorkingDir)
|
||||
s.mu.Unlock()
|
||||
if err != nil {
|
||||
s.sendErrorResponse(request.Request, FailedToLaunch, "Failed to launch", err.Error())
|
||||
@ -968,6 +891,7 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
func() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock() // Make sure to unlock in case of panic that will become internal error
|
||||
@ -1021,39 +945,6 @@ func (s *Server) stopNoDebugProcess() {
|
||||
s.noDebugProcess = nil
|
||||
}
|
||||
|
||||
// Launch debug sessions support the following modes:
|
||||
// -- [DEFAULT] "debug" - builds and launches debugger for specified program (similar to 'dlv debug')
|
||||
// Required args: program
|
||||
// Optional args with default: output, cwd, noDebug
|
||||
// Optional args: buildFlags, args
|
||||
// -- "test" - builds and launches debugger for specified test (similar to 'dlv test')
|
||||
// same args as above
|
||||
// -- "exec" - launches debugger for precompiled binary (similar to 'dlv exec')
|
||||
// Required args: program
|
||||
// Optional args with default: cwd, noDebug
|
||||
// Optional args: args
|
||||
// -- replay: skips program build and sets the Debugger.CoreFile property based on the
|
||||
// Required args: coreFilePath
|
||||
// Optional args: program, args
|
||||
// -- core: skips program build and sets the Debugger.CoreFile property based on the
|
||||
// Required args: program, traceDirPath
|
||||
// Optional args: args
|
||||
func isValidLaunchMode(mode interface{}) bool {
|
||||
switch mode {
|
||||
case "exec", "debug", "test", "replay", "core":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Attach debug sessions support the following modes:
|
||||
// -- [DEFAULT] "local" -- attaches debugger to a local running process
|
||||
// Required args: processId
|
||||
// TODO(polina): support "remote" mode
|
||||
func isValidAttachMode(mode interface{}) bool {
|
||||
return mode == "local"
|
||||
}
|
||||
|
||||
// onDisconnectRequest handles the DisconnectRequest. Per the DAP spec,
|
||||
// it disconnects the debuggee and signals that the debug adaptor
|
||||
// (in our case this TCP server) can be terminated.
|
||||
@ -1524,46 +1415,40 @@ func (s *Server) onThreadsRequest(request *dap.ThreadsRequest) {
|
||||
// onAttachRequest handles 'attach' request.
|
||||
// This is a mandatory request to support.
|
||||
func (s *Server) onAttachRequest(request *dap.AttachRequest) {
|
||||
mode, ok := request.Arguments["mode"]
|
||||
if !ok || mode == "" {
|
||||
mode = "local"
|
||||
}
|
||||
if !isValidAttachMode(mode) {
|
||||
// TODO(polina): support 'remote' mode that expects a non-nil debugger
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToAttach, "Failed to attach",
|
||||
fmt.Sprintf("Unsupported 'mode' value %q in debug configuration", mode))
|
||||
var args AttachConfig = defaultAttachConfig // narrow copy for initializing non-zero default values
|
||||
if err := unmarshalLaunchAttachArgs(request.Arguments, &args); err != nil {
|
||||
s.sendErrorResponse(request.Request, FailedToAttach, "Failed to attach", fmt.Sprintf("invalid debug configuration - %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
mode := args.Mode
|
||||
if mode == "" {
|
||||
mode = "local"
|
||||
}
|
||||
|
||||
if !isValidAttachMode(mode) {
|
||||
s.sendErrorResponse(request.Request, FailedToAttach, "Failed to attach",
|
||||
fmt.Sprintf("invalid debug configuration - unsupported 'mode' attribute %q", args.Mode))
|
||||
return
|
||||
}
|
||||
if mode == "local" {
|
||||
pid, ok := request.Arguments["processId"].(float64)
|
||||
if !ok || pid == 0 {
|
||||
if args.ProcessID == 0 {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToAttach, "Failed to attach",
|
||||
"The 'processId' attribute is missing in debug configuration")
|
||||
return
|
||||
}
|
||||
s.config.Debugger.AttachPid = int(pid)
|
||||
err := s.setLaunchAttachArgs(request)
|
||||
if err != nil {
|
||||
s.config.Debugger.AttachPid = args.ProcessID
|
||||
if err := s.setLaunchAttachArgs(args.LaunchAttachCommonConfig); err != nil {
|
||||
s.sendErrorResponse(request.Request, FailedToAttach, "Failed to attach", err.Error())
|
||||
return
|
||||
}
|
||||
backend, ok := request.Arguments["backend"]
|
||||
if ok {
|
||||
backendParsed, ok := backend.(string)
|
||||
if !ok {
|
||||
s.sendErrorResponse(request.Request,
|
||||
FailedToAttach, "Failed to attach",
|
||||
fmt.Sprintf("'backend' attribute '%v' in debug configuration is not a string.", backend))
|
||||
return
|
||||
}
|
||||
s.config.Debugger.Backend = backendParsed
|
||||
if backend := args.Backend; backend != "" {
|
||||
s.config.Debugger.Backend = backend
|
||||
} else {
|
||||
s.config.Debugger.Backend = "default"
|
||||
}
|
||||
|
||||
var err error
|
||||
func() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock() // Make sure to unlock in case of panic that will become internal error
|
||||
|
||||
@ -4117,14 +4117,6 @@ func TestLaunchRequestDefaults(t *testing.T) {
|
||||
// writes to default output dir __debug_bin
|
||||
})
|
||||
})
|
||||
|
||||
// if noDebug is not a bool, behave as if it is the default value (false).
|
||||
runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
|
||||
runDebugSession(t, client, "launch", func() {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "debug", "program": fixture.Source, "noDebug": "true"})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// TestLaunchRequestOutputPath verifies that relative output binary path
|
||||
@ -4428,10 +4420,6 @@ type helperForSetVariable struct {
|
||||
c *daptest.Client
|
||||
}
|
||||
|
||||
func (h *helperForSetVariable) expectSetVariableAndStop(ref int, name, value string) {
|
||||
h.t.Helper()
|
||||
h.expectSetVariable0(ref, name, value, true)
|
||||
}
|
||||
func (h *helperForSetVariable) expectSetVariable(ref int, name, value string) {
|
||||
h.t.Helper()
|
||||
h.expectSetVariable0(ref, name, value, false)
|
||||
@ -4867,7 +4855,7 @@ func TestBadLaunchRequests(t *testing.T) {
|
||||
// Bad "program"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": 12345})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: The program attribute is missing in debug configuration.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"program\" of type string")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": nil})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
@ -4880,15 +4868,15 @@ func TestBadLaunchRequests(t *testing.T) {
|
||||
// Bad "mode"
|
||||
client.LaunchRequest("remote", fixture.Path, stopOnEntry)
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: Unsupported 'mode' value \"remote\" in debug configuration.")
|
||||
"Failed to launch: invalid debug configuration - unsupported 'mode' attribute \"remote\"")
|
||||
|
||||
client.LaunchRequest("notamode", fixture.Path, stopOnEntry)
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: Unsupported 'mode' value \"notamode\" in debug configuration.")
|
||||
"Failed to launch: invalid debug configuration - unsupported 'mode' attribute \"notamode\"")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": 12345, "program": fixture.Path})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: Unsupported 'mode' value %!q(float64=12345) in debug configuration.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"mode\" of type string")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": ""}) // empty mode defaults to "debug" (not an error)
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
@ -4899,55 +4887,51 @@ func TestBadLaunchRequests(t *testing.T) {
|
||||
"Failed to launch: The program attribute is missing in debug configuration.")
|
||||
|
||||
// Bad "args"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": nil})
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": "foobar"})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'args' attribute '<nil>' in debug configuration is not an array.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal string into \"args\" of type []string")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": 12345})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'args' attribute '12345' in debug configuration is not an array.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"args\" of type []string")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "exec", "program": fixture.Path, "args": []int{1, 2}})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: value '1' in 'args' attribute in debug configuration is not a string.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"args\" of type string")
|
||||
|
||||
// Bad "buildFlags"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "buildFlags": 123})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'buildFlags' attribute '123' in debug configuration is not a string.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"buildFlags\" of type string")
|
||||
|
||||
// Bad "backend"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "backend": 123})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'backend' attribute '123' in debug configuration is not a string.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"backend\" of type string")
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "backend": "foo"})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: could not launch process: unknown backend \"foo\"")
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "backend": ""})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: could not launch process: unknown backend \"\"")
|
||||
|
||||
// Bad "substitutePath"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": 123})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'substitutePath' attribute '123' in debug configuration is not a []{'from': string, 'to': string}")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"substitutePath\" of type {\"from\":string, \"to\":string}")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": []interface{}{123}})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'substitutePath' attribute '[123]' in debug configuration is not a []{'from': string, 'to': string}")
|
||||
"Failed to launch: invalid debug configuration - cannot use 123 as 'substitutePath' of type {\"from\":string, \"to\":string}")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": []interface{}{map[string]interface{}{"to": "path2"}}})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'substitutePath' attribute '[map[to:path2]]' in debug configuration is not a []{'from': string, 'to': string}")
|
||||
"Failed to launch: invalid debug configuration - 'substitutePath' requires both 'from' and 'to' entries")
|
||||
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "substitutePath": []interface{}{map[string]interface{}{"from": "path1", "to": 123}}})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to launch: 'substitutePath' attribute '[map[from:path1 to:123]]' in debug configuration is not a []{'from': string, 'to': string}")
|
||||
|
||||
"Failed to launch: invalid debug configuration - cannot use {\"from\":\"path1\",\"to\":123} as 'substitutePath' of type {\"from\":string, \"to\":string}")
|
||||
// Bad "cwd"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "cwd": 123})
|
||||
checkFailedToLaunchWithMessage(client.ExpectErrorResponse(t),
|
||||
"Failed to launch: 'cwd' attribute '123' in debug configuration is not a string.")
|
||||
"Failed to launch: invalid debug configuration - cannot unmarshal number into \"cwd\" of type string")
|
||||
|
||||
// Skip detailed message checks for potentially different OS-specific errors.
|
||||
client.LaunchRequest("exec", fixture.Path+"_does_not_exist", stopOnEntry)
|
||||
@ -4960,7 +4944,12 @@ func TestBadLaunchRequests(t *testing.T) {
|
||||
}
|
||||
checkFailedToLaunch(client.ExpectInvisibleErrorResponse(t))
|
||||
|
||||
client.LaunchRequest("" /*debug by default*/, fixture.Path+"_does_not_exist", stopOnEntry)
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"request": "launch",
|
||||
/* mode: debug by default*/
|
||||
"program": fixture.Path + "_does_not_exist",
|
||||
"stopOnEntry": stopOnEntry,
|
||||
})
|
||||
oe = client.ExpectOutputEvent(t)
|
||||
if !strings.HasPrefix(oe.Body.Output, "Build Error: ") || oe.Body.Category != "stderr" {
|
||||
t.Errorf("got %#v, want Category=\"stderr\" Output=\"Build Error: ...\"", oe)
|
||||
@ -4989,6 +4978,9 @@ func TestBadLaunchRequests(t *testing.T) {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": true, "cwd": "dir/invalid"})
|
||||
checkFailedToLaunch(client.ExpectErrorResponse(t)) // invalid directory, the error message is system-dependent.
|
||||
|
||||
// Bad "noDebug"
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "debug", "program": fixture.Source, "noDebug": "true"})
|
||||
checkFailedToLaunchWithMessage(client.ExpectInvisibleErrorResponse(t), "Failed to launch: invalid debug configuration - cannot unmarshal string into \"noDebug\" of type bool")
|
||||
// Bad "replay" parameters
|
||||
// These errors come from dap layer
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{"mode": "replay", "traceDirPath": ""})
|
||||
@ -5057,15 +5049,15 @@ func TestBadAttachRequest(t *testing.T) {
|
||||
// Bad "mode"
|
||||
client.AttachRequest(map[string]interface{}{"mode": "remote"})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: Unsupported 'mode' value \"remote\" in debug configuration")
|
||||
"Failed to attach: invalid debug configuration - unsupported 'mode' attribute \"remote\"")
|
||||
|
||||
client.AttachRequest(map[string]interface{}{"mode": "blah blah blah"})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: Unsupported 'mode' value \"blah blah blah\" in debug configuration")
|
||||
"Failed to attach: invalid debug configuration - unsupported 'mode' attribute \"blah blah blah\"")
|
||||
|
||||
client.AttachRequest(map[string]interface{}{"mode": 123})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: Unsupported 'mode' value %!q(float64=123) in debug configuration")
|
||||
"Failed to attach: invalid debug configuration - cannot unmarshal number into \"mode\" of type string")
|
||||
|
||||
client.AttachRequest(map[string]interface{}{"mode": ""}) // empty mode defaults to "local" (not an error)
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
@ -5090,7 +5082,7 @@ func TestBadAttachRequest(t *testing.T) {
|
||||
|
||||
client.AttachRequest(map[string]interface{}{"mode": "local", "processId": "1"})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: The 'processId' attribute is missing in debug configuration")
|
||||
"Failed to attach: invalid debug configuration - cannot unmarshal string into \"processId\" of type int")
|
||||
|
||||
client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1})
|
||||
// The exact message varies on different systems, so skip that check
|
||||
@ -5116,13 +5108,10 @@ func TestBadAttachRequest(t *testing.T) {
|
||||
// Bad "backend"
|
||||
client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1, "backend": 123})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: 'backend' attribute '123' in debug configuration is not a string.")
|
||||
"Failed to attach: invalid debug configuration - cannot unmarshal number into \"backend\" of type string")
|
||||
client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1, "backend": "foo"})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: could not attach to pid 1: unknown backend \"foo\"")
|
||||
client.AttachRequest(map[string]interface{}{"mode": "local", "processId": 1, "backend": ""})
|
||||
checkFailedToAttachWithMessage(client.ExpectInvisibleErrorResponse(t),
|
||||
"Failed to attach: could not attach to pid 1: unknown backend \"\"")
|
||||
|
||||
// We failed to attach to the program. Make sure shutdown still works.
|
||||
client.DisconnectRequest()
|
||||
|
||||
213
service/dap/types.go
Normal file
213
service/dap/types.go
Normal file
@ -0,0 +1,213 @@
|
||||
package dap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Launch debug sessions support the following modes:
|
||||
// -- [DEFAULT] "debug" - builds and launches debugger for specified program (similar to 'dlv debug')
|
||||
// Required args: program
|
||||
// Optional args with default: output, cwd, noDebug
|
||||
// Optional args: buildFlags, args
|
||||
// -- "test" - builds and launches debugger for specified test (similar to 'dlv test')
|
||||
// same args as above
|
||||
// -- "exec" - launches debugger for precompiled binary (similar to 'dlv exec')
|
||||
// Required args: program
|
||||
// Optional args with default: cwd, noDebug
|
||||
// Optional args: args
|
||||
// -- "replay" - replays a trace generated by mozilla rr. Mozilla rr must be installed.
|
||||
// Required args: traceDirPath
|
||||
// Optional args: args
|
||||
// -- "core" - examines a core dump (only supports linux and windows core dumps).
|
||||
// Required args: program, coreFilePath
|
||||
// Optional args: args
|
||||
//
|
||||
// TODO(hyangah): change this to 'validateLaunchMode' that checks
|
||||
// all the required/optional fields mentioned above.
|
||||
func isValidLaunchMode(mode string) bool {
|
||||
switch mode {
|
||||
case "exec", "debug", "test", "replay", "core":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Attach debug sessions support the following modes:
|
||||
// -- [DEFAULT] "local" -- attaches debugger to a local running process
|
||||
// Required args: processID
|
||||
// TODO(polina): support "remote" mode
|
||||
func isValidAttachMode(mode string) bool {
|
||||
return mode == "local"
|
||||
}
|
||||
|
||||
// Default values for Launch/Attach configs.
|
||||
// Used to initialize configuration variables before decoding
|
||||
// arguments in launch/attach requests.
|
||||
var (
|
||||
defaultLaunchAttachCommonConfig = LaunchAttachCommonConfig{
|
||||
Backend: "default",
|
||||
StackTraceDepth: 50,
|
||||
}
|
||||
defaultLaunchConfig = LaunchConfig{
|
||||
Mode: "debug",
|
||||
Output: defaultDebugBinary,
|
||||
LaunchAttachCommonConfig: defaultLaunchAttachCommonConfig,
|
||||
}
|
||||
defaultAttachConfig = AttachConfig{
|
||||
Mode: "local",
|
||||
LaunchAttachCommonConfig: defaultLaunchAttachCommonConfig,
|
||||
}
|
||||
)
|
||||
|
||||
// LaunchConfig is the collection of launch request attributes recognized by delve DAP implementation.
|
||||
type LaunchConfig struct {
|
||||
// Acceptable values are:
|
||||
// "debug": compiles your program with optimizations disabled, starts and attaches to it.
|
||||
// "test": compiles your unit test program with optimizations disabled, starts and attaches to it.
|
||||
// "exec": executes a precompiled binary and begins a debug session.
|
||||
// "replay": replays an rr trace.
|
||||
// "core": examines a core dump.
|
||||
//
|
||||
// Default is "debug".
|
||||
Mode string `json:"mode,omitempty"`
|
||||
|
||||
// Required when mode is `debug`, `test`, or `exec`.
|
||||
// Path to the program folder (or any go file within that folder)
|
||||
// when in `debug` or `test` mode, and to the pre-built binary file
|
||||
// to debug in `exec` mode.
|
||||
// If it is not an absolute path, it will be interpreted as a path
|
||||
// relative to the working directory of the delve process.
|
||||
Program string `json:"program,omitempty"`
|
||||
|
||||
// Command line arguments passed to the debugged program.
|
||||
Args []string `json:"args,omitempty"`
|
||||
|
||||
// Working directory of the program being debugged
|
||||
// if a non-empty value is specified. If a relative path is provided,
|
||||
// it will be interpreted as a relative path to the delve's
|
||||
// working directory.
|
||||
//
|
||||
// If not specified or empty, currently the built program's directory will
|
||||
// be used.
|
||||
// This is similar to delve's `--wd` flag.
|
||||
Cwd string `json:"cwd,omitempty"`
|
||||
|
||||
// Build flags, to be passed to the Go compiler.
|
||||
// It is like delve's `--build-flags`. For example,
|
||||
//
|
||||
// "buildFlags": "-tags=integration -mod=vendor -cover -v"
|
||||
BuildFlags string `json:"buildFlags,omitempty"`
|
||||
|
||||
// Output path for the binary of the debugee.
|
||||
// Relative path is interpreted as the path relative to
|
||||
// the delve process's working directory.
|
||||
// This is deleted after the debug session ends.
|
||||
//
|
||||
// FIXIT: the built program's directory is used as the default
|
||||
// working directory of the debugged program, which means
|
||||
// the directory of `output` is used as the default working
|
||||
// directory. This is a bug and needs fix.
|
||||
Output string `json:"output,omitempty"`
|
||||
|
||||
// NoDebug is used to run the program without debugging.
|
||||
NoDebug bool `json:"noDebug,omitempty"`
|
||||
|
||||
// TraceDirPath is the trace directory path for replay mode.
|
||||
// This is required for "replay" mode but unused in other modes.
|
||||
TraceDirPath string `json:"traceDirPath,omitempty"`
|
||||
|
||||
// CoreFilePath is the core file path for core mode.
|
||||
// This is required for "core" mode but unused in other modes.
|
||||
CoreFilePath string `json:"coreFilePath,omitempty"`
|
||||
|
||||
LaunchAttachCommonConfig
|
||||
}
|
||||
|
||||
// LaunchAttachCommonConfig is the attributes common in both launch/attach requests.
|
||||
type LaunchAttachCommonConfig struct {
|
||||
// Automatically stop program after launch or attach.
|
||||
StopOnEntry bool `json:"stopOnEntry,omitempty"`
|
||||
|
||||
// Backend used by delve. See `dlv backend` for allowed values.
|
||||
// Default is "default".
|
||||
Backend string `json:"backend,omitempty"`
|
||||
|
||||
// Maximum depth of stack trace collected from Delve.
|
||||
// Default is 50.
|
||||
StackTraceDepth int `json:"stackTraceDepth,omitempty"`
|
||||
|
||||
// Boolean value to indicate whether global package variables
|
||||
// should be shown in the variables pane or not.
|
||||
ShowGlobalVariables bool `json:"showGlobalVariables,omitempty"`
|
||||
|
||||
// An array of mappings from a local path (client) to the remote path (debugger).
|
||||
// This setting is useful when working in a file system with symbolic links,
|
||||
// running remote debugging, or debugging an executable compiled externally.
|
||||
// The debug adapter will replace the local path with the remote path in all of the calls.
|
||||
SubstitutePath []SubstitutePath `json:"substitutePath,omitempty"`
|
||||
}
|
||||
|
||||
// SubstitutePath defines a mapping from a local path to the remote path.
|
||||
// Both 'from' and 'to' must be specified and non-empty.
|
||||
type SubstitutePath struct {
|
||||
// The local path to be replaced when passing paths to the debugger.
|
||||
From string `json:"from,omitempty"`
|
||||
// The remote path to be replaced when passing paths back to the client.
|
||||
To string `json:"to,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SubstitutePath) UnmarshalJSON(data []byte) error {
|
||||
// use custom unmarshal to check if both from/to are set.
|
||||
type tmpType SubstitutePath
|
||||
var tmp tmpType
|
||||
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
if _, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return fmt.Errorf(`cannot use %s as 'substitutePath' of type {"from":string, "to":string}`, data)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if tmp.From == "" || tmp.To == "" {
|
||||
return errors.New("'substitutePath' requires both 'from' and 'to' entries")
|
||||
}
|
||||
*m = SubstitutePath(tmp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AttachConfig is the collection of attach request attributes recognized by delve DAP implementation.
|
||||
type AttachConfig struct {
|
||||
// Acceptable values are:
|
||||
// "local": attaches to the local process with the given ProcessID.
|
||||
//
|
||||
// Default is "local".
|
||||
Mode string `json:"mode"`
|
||||
|
||||
// The numeric ID of the process to be debugged. Required and must not be 0.
|
||||
ProcessID int `json:"processId,omitempty"`
|
||||
|
||||
LaunchAttachCommonConfig
|
||||
}
|
||||
|
||||
// unmarshalLaunchAttachArgs wraps unmarshalling of launch/attach request's
|
||||
// arguments attribute. Upon unmarshal failure, it returns an error massaged
|
||||
// to be suitable for end-users.
|
||||
func unmarshalLaunchAttachArgs(input json.RawMessage, config interface{}) error {
|
||||
if err := json.Unmarshal(input, config); err != nil {
|
||||
if uerr, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
// Format json.UnmarshalTypeError error string in our own way. E.g.,
|
||||
// "json: cannot unmarshal number into Go struct field LaunchArgs.substitutePath of type dap.SubstitutePath"
|
||||
// => "cannot unmarshal number into 'substitutePath' of type {from:string, to:string}"
|
||||
// "json: cannot unmarshal number into Go struct field LaunchArgs.program of type string" (go1.16)
|
||||
// => "cannot unmarshal number into 'program' of type string"
|
||||
typ := uerr.Type.String()
|
||||
if uerr.Field == "substitutePath" {
|
||||
typ = `{"from":string, "to":string}`
|
||||
}
|
||||
return fmt.Errorf("cannot unmarshal %v into %q of type %v", uerr.Value, uerr.Field, typ)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
1
vendor/github.com/google/go-dap/.travis.yml
generated
vendored
1
vendor/github.com/google/go-dap/.travis.yml
generated
vendored
@ -6,6 +6,7 @@ language: go
|
||||
go:
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
- 1.16.x
|
||||
|
||||
env:
|
||||
global:
|
||||
|
||||
1
vendor/github.com/google/go-dap/README.md
generated
vendored
1
vendor/github.com/google/go-dap/README.md
generated
vendored
@ -1,5 +1,6 @@
|
||||
# go-dap: Go implementation of the Debug Adapter Protocol
|
||||
|
||||
[](https://pkg.go.dev/github.com/google/go-dap)
|
||||
[](https://travis-ci.org/google/go-dap)
|
||||
[](https://goreportcard.com/report/github.com/google/go-dap)
|
||||
|
||||
|
||||
16
vendor/github.com/google/go-dap/schematypes.go
generated
vendored
16
vendor/github.com/google/go-dap/schematypes.go
generated
vendored
@ -18,6 +18,8 @@
|
||||
|
||||
package dap
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Message is an interface that all DAP message types implement with pointer
|
||||
// receivers. It's not part of the protocol but is used to enforce static
|
||||
// typing in Go code and provide some common accessors.
|
||||
@ -56,7 +58,7 @@ type EventMessage interface {
|
||||
type LaunchAttachRequest interface {
|
||||
RequestMessage
|
||||
// GetArguments provides access to the Arguments map.
|
||||
GetArguments() map[string]interface{}
|
||||
GetArguments() json.RawMessage
|
||||
}
|
||||
|
||||
// ProtocolMessage: Base class of requests, responses, and events.
|
||||
@ -492,11 +494,11 @@ func (r *ConfigurationDoneResponse) GetResponse() *Response { return &r.Response
|
||||
type LaunchRequest struct {
|
||||
Request
|
||||
|
||||
Arguments map[string]interface{} `json:"arguments"`
|
||||
Arguments json.RawMessage `json:"arguments"`
|
||||
}
|
||||
|
||||
func (r *LaunchRequest) GetRequest() *Request { return &r.Request }
|
||||
func (r *LaunchRequest) GetArguments() map[string]interface{} { return r.Arguments }
|
||||
func (r *LaunchRequest) GetRequest() *Request { return &r.Request }
|
||||
func (r *LaunchRequest) GetArguments() json.RawMessage { return r.Arguments }
|
||||
|
||||
// LaunchResponse: Response to 'launch' request. This is just an acknowledgement, so no body field is required.
|
||||
type LaunchResponse struct {
|
||||
@ -510,11 +512,11 @@ func (r *LaunchResponse) GetResponse() *Response { return &r.Response }
|
||||
type AttachRequest struct {
|
||||
Request
|
||||
|
||||
Arguments map[string]interface{} `json:"arguments"`
|
||||
Arguments json.RawMessage `json:"arguments"`
|
||||
}
|
||||
|
||||
func (r *AttachRequest) GetRequest() *Request { return &r.Request }
|
||||
func (r *AttachRequest) GetArguments() map[string]interface{} { return r.Arguments }
|
||||
func (r *AttachRequest) GetRequest() *Request { return &r.Request }
|
||||
func (r *AttachRequest) GetArguments() json.RawMessage { return r.Arguments }
|
||||
|
||||
// AttachResponse: Response to 'attach' request. This is just an acknowledgement, so no body field is required.
|
||||
type AttachResponse struct {
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -13,7 +13,7 @@ github.com/creack/pty
|
||||
# github.com/derekparker/trie v0.0.0-20200317170641-1fdf38b7b0e9
|
||||
## explicit
|
||||
github.com/derekparker/trie
|
||||
# github.com/google/go-dap v0.5.0
|
||||
# github.com/google/go-dap v0.5.1-0.20210713061233-c91b005e3987
|
||||
## explicit
|
||||
github.com/google/go-dap
|
||||
# github.com/hashicorp/golang-lru v0.5.4
|
||||
|
||||
Loading…
Reference in New Issue
Block a user