Commit 4cad6104 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

os/exec: remove Cmd.RunContext and Cmd.WaitContext, add CommandContext

Fixes #15775

Change-Id: I0a6c2ca09d3850c3538494711f7a9801b9500411
Reviewed-on: https://go-review.googlesource.com/23300
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 85e39f83
......@@ -103,8 +103,9 @@ type Cmd struct {
// available after a call to Wait or Run.
ProcessState *os.ProcessState
lookPathErr error // LookPath error, if any.
finished bool // when Wait was called
ctx context.Context // nil means none
lookPathErr error // LookPath error, if any.
finished bool // when Wait was called
childFiles []*os.File
closeAfterStart []io.Closer
closeAfterWait []io.Closer
......@@ -139,6 +140,20 @@ func Command(name string, arg ...string) *Cmd {
return cmd
}
// CommandContext is like Command but includes a context.
//
// The provided context is used to kill the process (by calling
// os.Process.Kill) if the context becomes done before the command
// completes on its own.
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
if ctx == nil {
panic("nil Context")
}
cmd := Command(name, arg...)
cmd.ctx = ctx
return cmd
}
// interfaceEqual protects against panics from doing equality tests on
// two interfaces with non-comparable underlying types.
func interfaceEqual(a, b interface{}) bool {
......@@ -263,15 +278,6 @@ func (c *Cmd) Run() error {
return c.Wait()
}
// RunContext is like Run, but kills the process (by calling os.Process.Kill)
// if ctx is done before the process ends on its own.
func (c *Cmd) RunContext(ctx context.Context) error {
if err := c.Start(); err != nil {
return err
}
return c.WaitContext(ctx)
}
// lookExtensions finds windows executable by its dir and path.
// It uses LookPath to try appropriate extensions.
// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
......@@ -396,12 +402,6 @@ func (e *ExitError) Error() string {
//
// Wait releases any resources associated with the Cmd.
func (c *Cmd) Wait() error {
return c.WaitContext(nil)
}
// WaitContext is like Wait, but kills the process (by calling os.Process.Kill)
// if ctx is done before the process ends on its own.
func (c *Cmd) WaitContext(ctx context.Context) error {
if c.Process == nil {
return errors.New("exec: not started")
}
......@@ -411,11 +411,11 @@ func (c *Cmd) WaitContext(ctx context.Context) error {
c.finished = true
var waitDone chan struct{}
if ctx != nil {
if c.ctx != nil {
waitDone = make(chan struct{})
go func() {
select {
case <-ctx.Done():
case <-c.ctx.Done():
c.Process.Kill()
case <-waitDone:
}
......
......@@ -29,16 +29,24 @@ import (
"time"
)
func helperCommand(t *testing.T, s ...string) *exec.Cmd {
func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd *exec.Cmd) {
testenv.MustHaveExec(t)
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
cmd := exec.Command(os.Args[0], cs...)
if ctx != nil {
cmd = exec.CommandContext(ctx, os.Args[0], cs...)
} else {
cmd = exec.Command(os.Args[0], cs...)
}
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
func helperCommand(t *testing.T, s ...string) *exec.Cmd {
return helperCommandContext(t, nil, s...)
}
func TestEcho(t *testing.T) {
bs, err := helperCommand(t, "echo", "foo bar", "baz").Output()
if err != nil {
......@@ -834,7 +842,8 @@ func TestOutputStderrCapture(t *testing.T) {
}
func TestContext(t *testing.T) {
c := helperCommand(t, "pipetest")
ctx, cancel := context.WithCancel(context.Background())
c := helperCommandContext(t, ctx, "pipetest")
stdin, err := c.StdinPipe()
if err != nil {
t.Fatal(err)
......@@ -843,7 +852,6 @@ func TestContext(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
if err := c.Start(); err != nil {
t.Fatal(err)
}
......@@ -858,7 +866,7 @@ func TestContext(t *testing.T) {
}
waitErr := make(chan error, 1)
go func() {
waitErr <- c.WaitContext(ctx)
waitErr <- c.Wait()
}()
cancel()
select {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment