-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcommand.go
64 lines (53 loc) · 1008 Bytes
/
command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package execpool
import (
"context"
"io"
"os/exec"
"sync"
)
// Command is wrapper around exec.Cmd that implements io.Reader interface
type Command struct {
cmd *exec.Cmd
lock sync.RWMutex
err error
stdin io.WriteCloser
stdout io.ReadCloser
cancel func()
ctx context.Context
}
// Read implements io.Reader
func (c *Command) Read(p []byte) (int, error) {
n, err := c.stdout.Read(p)
if err == io.EOF {
if waitErr := c.cmd.Wait(); waitErr != nil {
c.stop(waitErr)
return n, waitErr
}
c.stop(nil)
return n, io.EOF
}
if err := c.error(); err != nil {
return n, err
}
if err != nil {
c.stop(err)
}
return n, err
}
// stop stops command execution by closing stdout and cancelling
// command context
func (c *Command) stop(err error) {
c.lock.Lock()
if c.err == nil {
c.err = err
}
c.lock.Unlock()
c.stdout.Close()
c.cancel()
}
// error returns command error
func (c *Command) error() error {
c.lock.RLock()
defer c.lock.RUnlock()
return c.err
}