cmd/dlv,terminal: fix accept-multiclient behavior

1. Check IsMulticlient and send stop request before doing anything
   else.
2. Allow init file to call 'exit'

Fixes #1430
This commit is contained in:
aarzilli 2018-11-30 09:53:29 +01:00 committed by Derek Parker
parent cb386d0966
commit d7d4c144c8
5 changed files with 38 additions and 14 deletions

1
_fixtures/exit.init Normal file

@ -0,0 +1 @@
exit

@ -500,6 +500,20 @@ func connect(addr string, clientConn net.Conn, conf *config.Config, kind execute
} else {
client = rpc2.NewClient(addr)
}
if client.IsMulticlient() {
state, _ := client.GetStateNonBlocking()
// The error return of GetState will usually be the ErrProcessExited,
// which we don't care about. If there are other errors they will show up
// later, here we are only concerned about stopping a running target so
// that we can initialize our connection.
if state != nil && state.Running {
_, err := client.Halt()
if err != nil {
fmt.Fprintf(os.Stderr, "could not halt: %v", err)
return 1
}
}
}
if client.Recorded() && (kind == executingGeneratedFile || kind == executingGeneratedTest) {
// When using the rr backend remove the trace directory if we built the
// executable

@ -256,3 +256,20 @@ func TestGeneratedDoc(t *testing.T) {
checkAutogenDoc(t, docFilename, "scripts/gen-usage-docs.go", slurpFile(t, tempDir+"/"+doc.Name()))
}
}
func TestExitInInit(t *testing.T) {
dlvbin, tmpdir := getDlvBin(t)
defer os.RemoveAll(tmpdir)
buildtestdir := filepath.Join(protest.FindFixturesDir(), "buildtest")
exitInit := filepath.Join(protest.FindFixturesDir(), "exit.init")
cmd := exec.Command(dlvbin, "--init", exitInit, "debug")
cmd.Dir = buildtestdir
out, err := cmd.CombinedOutput()
t.Logf("%q %v\n", string(out), err)
// dlv will exit anyway because stdin is not a tty but it will print the
// prompt once if the init file didn't call exit successfully.
if strings.Contains(string(out), "(dlv)") {
t.Fatal("init did not cause dlv to exit")
}
}

@ -1933,6 +1933,9 @@ func (c *Commands) executeFile(t *Term, name string) error {
}
if err := c.Call(line, t); err != nil {
if _, isExitRequest := err.(ExitRequestError); isExitRequest {
return err
}
fmt.Printf("%s:%d: %v\n", name, lineno, err)
}
}

@ -64,20 +64,6 @@ type Term struct {
// New returns a new Term.
func New(client service.Client, conf *config.Config) *Term {
if client != nil && client.IsMulticlient() {
state, _ := client.GetStateNonBlocking()
// The error return of GetState will usually be the ErrProcessExited,
// which we don't care about. If there are other errors they will show up
// later, here we are only concerned about stopping a running target so
// that we can initialize our connection.
if state != nil && state.Running {
_, err := client.Halt()
if err != nil {
fmt.Fprintf(os.Stderr, "could not halt: %v", err)
return nil
}
}
}
cmds := DebugCommands(client)
if conf != nil && conf.Aliases != nil {
cmds.Merge(conf.Aliases)
@ -204,6 +190,9 @@ func (t *Term) Run() (int, error) {
if t.InitFile != "" {
err := t.cmds.executeFile(t, t.InitFile)
if err != nil {
if _, ok := err.(ExitRequestError); ok {
return t.handleExit()
}
fmt.Fprintf(os.Stderr, "Error executing init file: %s\n", err)
}
}