-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathruncmd.go
138 lines (108 loc) · 2.22 KB
/
runcmd.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package actions
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"os/exec"
"sync"
)
func RunCmd(cmd string, args []string) (string, string, error) {
c := exec.Command(cmd, args...)
//c.Stdin = os.Stdin
//var out bytes.Buffer
//cmd.Stdout = &out
stdoutCh := make(chan string, 10)
fulloutCh := make(chan string, 10)
wg := sync.WaitGroup{}
wgFullout := sync.WaitGroup{}
wgFullout.Add(2)
stdoutW := func() *io.PipeWriter {
stdoutR, stdoutW := io.Pipe()
stdoutScanner := bufio.NewScanner(stdoutR)
c.Stdout = stdoutW
wg.Add(1)
go func() {
defer wg.Done()
defer close(stdoutCh)
defer wgFullout.Done()
for stdoutScanner.Scan() {
text := stdoutScanner.Text() + "\n"
stdoutCh <- text
fulloutCh <- text
fmt.Fprintf(os.Stdout, text)
}
}()
return stdoutW
}()
stderrW := func() *io.PipeWriter {
stderrR, stderrW := io.Pipe()
stderrScanner := bufio.NewScanner(stderrR)
c.Stderr = stderrW
wg.Add(1)
go func() {
defer wg.Done()
defer wgFullout.Done()
for stderrScanner.Scan() {
text := stderrScanner.Text() + "\n"
fulloutCh <- text
fmt.Fprintf(os.Stderr, text)
}
}()
return stderrW
}()
go func() {
wgFullout.Wait()
close(fulloutCh)
}()
stdout := func() *bytes.Buffer {
buf := &bytes.Buffer{}
wg.Add(1)
go func() {
FOR:
for {
select {
case v, ok := <-stdoutCh:
if ok {
buf.WriteString(v)
} else {
break FOR
}
}
}
wg.Done()
}()
return buf
}()
fullout := func() *bytes.Buffer {
buf := &bytes.Buffer{}
wg.Add(1)
go func() {
FOR:
for {
select {
case v, ok := <-fulloutCh:
if ok {
buf.WriteString(v)
} else {
break FOR
}
}
}
wg.Done()
}()
return buf
}()
err := c.Run()
// As the command returned, the pipes should be safe to close now.
// Note that you have to close write-side of pipes. If you close readers first, you'll end up seeing "write to closed pipes" errors
stdoutW.Close()
stderrW.Close()
// Ensure that:
// - stdout and stderr are sent to the channels and
// - all the messages sent to the channels are consumed and
// - their contents are stored in buffers
wg.Wait()
return stdout.String(), fullout.String(), err
}