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() {
|
||||
x := os.Getenv("SOMEVAR")
|
||||
x, y := os.LookupEnv("SOMEVAR")
|
||||
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 == "" {
|
||||
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) {
|
||||
if runtime.GOOS == "freebsd" {
|
||||
t.SkipNow()
|
||||
|
@ -129,6 +129,15 @@ type LaunchConfig struct {
|
||||
// directory.
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user