diff options
Diffstat (limited to 'src/pkg/os/exec/exec.go')
-rw-r--r-- | src/pkg/os/exec/exec.go | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go index a3bbcf300..491cc242b 100644 --- a/src/pkg/os/exec/exec.go +++ b/src/pkg/os/exec/exec.go @@ -13,6 +13,7 @@ import ( "io" "os" "strconv" + "sync" "syscall" ) @@ -357,6 +358,10 @@ func (c *Cmd) CombinedOutput() ([]byte, error) { // StdinPipe returns a pipe that will be connected to the command's // standard input when the command starts. +// The pipe will be closed automatically after Wait sees the command exit. +// A caller need only call Close to force the pipe to close sooner. +// For example, if the command being run will not exit until standard input +// is closed, the caller must close the pipe. func (c *Cmd) StdinPipe() (io.WriteCloser, error) { if c.Stdin != nil { return nil, errors.New("exec: Stdin already set") @@ -370,13 +375,33 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) { } c.Stdin = pr c.closeAfterStart = append(c.closeAfterStart, pr) - c.closeAfterWait = append(c.closeAfterWait, pw) - return pw, nil + wc := &closeOnce{File: pw} + c.closeAfterWait = append(c.closeAfterWait, wc) + return wc, nil +} + +type closeOnce struct { + *os.File + + close sync.Once + closeErr error +} + +func (c *closeOnce) Close() error { + c.close.Do(func() { + c.closeErr = c.File.Close() + }) + return c.closeErr } // StdoutPipe returns a pipe that will be connected to the command's // standard output when the command starts. -// The pipe will be closed automatically after Wait sees the command exit. +// +// Wait will close the pipe after seeing the command exit, so most callers +// need not close the pipe themselves; however, an implication is that +// it is incorrect to call Wait before all reads from the pipe have completed. +// For the same reason, it is incorrect to call Run when using StdoutPipe. +// See the example for idiomatic usage. func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { if c.Stdout != nil { return nil, errors.New("exec: Stdout already set") @@ -396,7 +421,12 @@ func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { // StderrPipe returns a pipe that will be connected to the command's // standard error when the command starts. -// The pipe will be closed automatically after Wait sees the command exit. +// +// Wait will close the pipe after seeing the command exit, so most callers +// need not close the pipe themselves; however, an implication is that +// it is incorrect to call Wait before all reads from the pipe have completed. +// For the same reason, it is incorrect to use Run when using StderrPipe. +// See the StdoutPipe example for idiomatic usage. func (c *Cmd) StderrPipe() (io.ReadCloser, error) { if c.Stderr != nil { return nil, errors.New("exec: Stderr already set") |