internal/gocommand: kill gracefully

We want the go command to get a chance to do its cleanups. Send it
Interrupt before Kill.

Fixes golang/go#37368.

Change-Id: Id891d2f4f85aae30d2aaa19b9c854d2346ec6e1f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/220738
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Heschi Kreinick 2020-02-24 16:58:45 -05:00
parent c5cec6710e
commit 7c03e3340d
1 changed files with 31 additions and 2 deletions

View File

@ -5,6 +5,7 @@ import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
@ -49,7 +50,7 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *
goArgs = append(goArgs, i.BuildFlags...)
goArgs = append(goArgs, i.Args...)
}
cmd := exec.CommandContext(ctx, "go", goArgs...)
cmd := exec.Command("go", goArgs...)
stdout = &bytes.Buffer{}
stderr = &bytes.Buffer{}
cmd.Stdout = stdout
@ -65,7 +66,7 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *
defer func(start time.Time) { log("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now())
rawError = cmd.Run()
rawError = runCmdContext(ctx, cmd)
friendlyError = rawError
if rawError != nil {
// Check for 'go' executable not being found.
@ -80,6 +81,34 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *
return
}
// runCmdContext is like exec.CommandContext except it sends os.Interrupt
// before os.Kill.
func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
if err := cmd.Start(); err != nil {
return err
}
resChan := make(chan error, 1)
go func() {
resChan <- cmd.Wait()
}()
select {
case err := <-resChan:
return err
case <-ctx.Done():
}
// Cancelled. Interrupt and see if it ends voluntarily.
cmd.Process.Signal(os.Interrupt)
select {
case err := <-resChan:
return err
case <-time.After(time.Second):
}
// Didn't shut down in response to interrupt. Kill it hard.
cmd.Process.Kill()
return <-resChan
}
func cmdDebugStr(cmd *exec.Cmd) string {
env := make(map[string]string)
for _, kv := range cmd.Env {