dap: support 'Env' attribute for launch requests (#2846)
* dap: support 'Env' attribute for launch requests Env is applied in addition to the delve process environment variables. The env setting is done by calling os.Setenv as early as possible when a Launch request is received. Prior discussion is in https://github.com/go-delve/delve/pull/2582 In Visual Studio Code, setting null for an environment variable in launch.json or tasks.json indicates users want to unset the environment variable. Support the behavior by accepting nil value. * dap: Env field itself can be omitempty * edit comment
This commit is contained in:
parent
79d5db24a5
commit
21bdb466f1
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
x := os.Getenv("SOMEVAR")
|
x, y := os.LookupEnv("SOMEVAR")
|
||||||
runtime.Breakpoint()
|
runtime.Breakpoint()
|
||||||
fmt.Printf("SOMEVAR=%s\n", x)
|
fmt.Printf("SOMEVAR=%s\n%v", x, y)
|
||||||
}
|
}
|
||||||
|
@ -917,6 +917,20 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for k, v := range args.Env {
|
||||||
|
if v != nil {
|
||||||
|
if err := os.Setenv(k, *v); err != nil {
|
||||||
|
s.sendShowUserErrorResponse(request.Request, FailedToLaunch, "Failed to launch", fmt.Sprintf("failed to setenv(%v) - %v", k, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := os.Unsetenv(k); err != nil {
|
||||||
|
s.sendShowUserErrorResponse(request.Request, FailedToLaunch, "Failed to launch", fmt.Sprintf("failed to unsetenv(%v) - %v", k, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args.Mode == "" {
|
if args.Mode == "" {
|
||||||
args.Mode = "debug"
|
args.Mode = "debug"
|
||||||
}
|
}
|
||||||
|
@ -5509,6 +5509,106 @@ func TestLaunchRequestWithBuildFlags(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLaunchRequestWithEnv(t *testing.T) {
|
||||||
|
// testenv fixture will lookup SOMEVAR with
|
||||||
|
// x, y := os.Lookup("SOMEVAR")
|
||||||
|
// before stopping at runtime.Breakpoint.
|
||||||
|
|
||||||
|
type envMap map[string]*string
|
||||||
|
strVar := func(s string) *string { return &s }
|
||||||
|
|
||||||
|
fixtures := protest.FindFixturesDir() // relative to current working directory.
|
||||||
|
testFile, _ := filepath.Abs(filepath.Join(fixtures, "testenv.go"))
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
initEnv envMap
|
||||||
|
launchEnv envMap
|
||||||
|
wantX string
|
||||||
|
wantY bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no env",
|
||||||
|
initEnv: envMap{"SOMEVAR": strVar("baz")},
|
||||||
|
wantX: "baz",
|
||||||
|
wantY: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overwrite",
|
||||||
|
initEnv: envMap{"SOMEVAR": strVar("baz")},
|
||||||
|
launchEnv: envMap{"SOMEVAR": strVar("bar")},
|
||||||
|
wantX: "bar",
|
||||||
|
wantY: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unset",
|
||||||
|
initEnv: envMap{"SOMEVAR": strVar("baz")},
|
||||||
|
launchEnv: envMap{"SOMEVAR": nil},
|
||||||
|
wantX: "",
|
||||||
|
wantY: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty value",
|
||||||
|
initEnv: envMap{"SOMEVAR": strVar("baz")},
|
||||||
|
launchEnv: envMap{"SOMEVAR": strVar("")},
|
||||||
|
wantX: "",
|
||||||
|
wantY: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set",
|
||||||
|
launchEnv: envMap{"SOMEVAR": strVar("foo")},
|
||||||
|
wantX: "foo",
|
||||||
|
wantY: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "untouched",
|
||||||
|
initEnv: envMap{"SOMEVAR": strVar("baz")},
|
||||||
|
launchEnv: envMap{"SOMEVAR2": nil, "SOMEVAR3": strVar("foo")},
|
||||||
|
wantX: "baz",
|
||||||
|
wantY: true,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// cleanup
|
||||||
|
defer func() {
|
||||||
|
os.Unsetenv("SOMEVAR")
|
||||||
|
os.Unsetenv("SOMEVAR2")
|
||||||
|
os.Unsetenv("SOMEVAR3")
|
||||||
|
}()
|
||||||
|
|
||||||
|
for k, v := range tc.initEnv {
|
||||||
|
if v != nil {
|
||||||
|
os.Setenv(k, *v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serverStopped := make(chan struct{})
|
||||||
|
client := startDAPServerWithClient(t, serverStopped)
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
runDebugSessionWithBPs(t, client, "launch", func() { // launch
|
||||||
|
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||||
|
"mode": "debug",
|
||||||
|
"program": testFile,
|
||||||
|
"env": tc.launchEnv,
|
||||||
|
})
|
||||||
|
}, testFile, nil, // runtime.Breakpoint
|
||||||
|
[]onBreakpoint{{
|
||||||
|
execute: func() {
|
||||||
|
client.EvaluateRequest("x", 1000, "whatever")
|
||||||
|
gotX := client.ExpectEvaluateResponse(t)
|
||||||
|
checkEval(t, gotX, fmt.Sprintf("%q", tc.wantX), false)
|
||||||
|
client.EvaluateRequest("y", 1000, "whatever")
|
||||||
|
gotY := client.ExpectEvaluateResponse(t)
|
||||||
|
checkEval(t, gotY, fmt.Sprintf("%v", tc.wantY), false)
|
||||||
|
},
|
||||||
|
disconnect: true,
|
||||||
|
}})
|
||||||
|
<-serverStopped
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAttachRequest(t *testing.T) {
|
func TestAttachRequest(t *testing.T) {
|
||||||
if runtime.GOOS == "freebsd" {
|
if runtime.GOOS == "freebsd" {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
|
@ -129,6 +129,15 @@ type LaunchConfig struct {
|
|||||||
// directory.
|
// directory.
|
||||||
DlvCwd string `json:"dlvCwd,omitempty"`
|
DlvCwd string `json:"dlvCwd,omitempty"`
|
||||||
|
|
||||||
|
// Env specifies optional environment variables for Delve server
|
||||||
|
// in addition to the environment variables Delve initially
|
||||||
|
// started with.
|
||||||
|
// Variables with 'nil' values can be used to unset the named
|
||||||
|
// environment variables.
|
||||||
|
// Values are interpreted verbatim. Variable substitution or
|
||||||
|
// reference to other environment variables is not supported.
|
||||||
|
Env map[string]*string `json:"env,omitempty"`
|
||||||
|
|
||||||
LaunchAttachCommonConfig
|
LaunchAttachCommonConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user