f953f1eb38
Trace all command execution at the time when the command starts. Previously, only "simple" execution created trace entries, leading to mysterious gaps in trace logs where time passed but it looked like nothing was happening.
75 lines
1.3 KiB
Go
75 lines
1.3 KiB
Go
package subprocess
|
|
|
|
import (
|
|
"io"
|
|
"os/exec"
|
|
)
|
|
|
|
// Thin wrapper around exec.Cmd. Takes care of pipe shutdown by
|
|
// keeping an internal reference to any created pipes. Whenever
|
|
// Cmd.Wait() is called, all created pipes are closed.
|
|
type Cmd struct {
|
|
*exec.Cmd
|
|
|
|
pipes []io.Closer
|
|
}
|
|
|
|
func (c *Cmd) Run() error {
|
|
c.trace()
|
|
return c.Cmd.Run()
|
|
}
|
|
|
|
func (c *Cmd) Start() error {
|
|
c.trace()
|
|
return c.Cmd.Start()
|
|
}
|
|
|
|
func (c *Cmd) Output() ([]byte, error) {
|
|
c.trace()
|
|
return c.Cmd.Output()
|
|
}
|
|
|
|
func (c *Cmd) CombinedOutput() ([]byte, error) {
|
|
c.trace()
|
|
return c.Cmd.CombinedOutput()
|
|
}
|
|
|
|
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
|
|
stdout, err := c.Cmd.StdoutPipe()
|
|
c.pipes = append(c.pipes, stdout)
|
|
return stdout, err
|
|
}
|
|
|
|
func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
|
|
stderr, err := c.Cmd.StderrPipe()
|
|
c.pipes = append(c.pipes, stderr)
|
|
return stderr, err
|
|
}
|
|
|
|
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
|
|
stdin, err := c.Cmd.StdinPipe()
|
|
c.pipes = append(c.pipes, stdin)
|
|
return stdin, err
|
|
}
|
|
|
|
func (c *Cmd) Wait() error {
|
|
for _, pipe := range c.pipes {
|
|
pipe.Close()
|
|
}
|
|
|
|
return c.Cmd.Wait()
|
|
}
|
|
|
|
func (c *Cmd) trace() {
|
|
if len(c.Args) > 0 {
|
|
Trace(c.Args[0], c.Args[1:]...)
|
|
} else {
|
|
Trace(c.Path)
|
|
}
|
|
}
|
|
|
|
func newCmd(cmd *exec.Cmd) *Cmd {
|
|
wrapped := &Cmd{Cmd: cmd}
|
|
return wrapped
|
|
}
|