-
Notifications
You must be signed in to change notification settings - Fork 24
/
cmd.go
108 lines (90 loc) · 1.7 KB
/
cmd.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package gvm
import (
"bufio"
"io"
"os"
"os/exec"
"sync"
"github.com/sirupsen/logrus"
)
type command struct {
Path string
Args []string
Dir string
Env []string
Stdout func(string)
Stderr func(string)
}
func makeCommand(cmd string, args ...string) *command {
return &command{
Path: cmd,
Args: args,
}
}
func (c *command) WithLogger(log logrus.FieldLogger) *command {
if c.Stdout == nil {
c.Stdout = infoOutLog(log)
}
if c.Stderr == nil {
c.Stderr = errOutLog(log)
}
return c
}
func (c *command) WithDir(dir string) *command {
c.Dir = dir
return c
}
func infoOutLog(log logrus.FieldLogger) func(string) {
return makeOutLog(log.Info)
}
func errOutLog(log logrus.FieldLogger) func(string) {
return makeOutLog(log.Error)
}
func makeOutLog(fn func(...interface{})) func(string) {
return func(text string) { fn(text) }
}
func (c *command) Exec() error {
cmd := exec.Command(c.Path, c.Args...)
cmd.Dir = c.Dir
if len(c.Env) > 0 {
cmd.Env = append(os.Environ(), c.Env...)
}
var err error
var stdout, stderr io.ReadCloser
if c.Stdout != nil {
stdout, err = cmd.StdoutPipe()
if err != nil {
return err
}
defer stdout.Close()
}
if c.Stderr != nil {
stderr, err = cmd.StderrPipe()
if err != nil {
return err
}
defer stderr.Close()
}
var wg sync.WaitGroup
defer wg.Wait()
captureLines := func(in io.Reader, fn func(string)) {
defer wg.Done()
scanner := bufio.NewScanner(in)
for scanner.Scan() {
text := scanner.Text()
fn(text)
}
}
if stdout != nil {
wg.Add(1)
go captureLines(stdout, c.Stdout)
}
if stderr != nil {
wg.Add(1)
go captureLines(stderr, c.Stderr)
}
if err := cmd.Start(); err != nil {
return err
}
return cmd.Wait()
}