-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmd.go
150 lines (137 loc) · 3.03 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
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
138
139
140
141
142
143
144
145
146
147
148
149
150
package os
import (
"fmt"
stringsi "github.com/hopeio/cherry/utils/strings"
"log"
"os"
"os/exec"
"os/signal"
"runtime"
"strconv"
"strings"
"syscall"
)
func Cmd(s string) (string, error) {
words := Split(s)
cmd := exec.Command(words[0], words[1:]...)
buf, err := cmd.CombinedOutput()
if err != nil {
return stringsi.BytesToString(buf), err
}
if len(buf) == 0 {
return "", nil
}
lastIndex := len(buf) - 1
if buf[lastIndex] == '\n' {
buf = buf[:lastIndex]
}
return stringsi.BytesToString(buf), nil
}
func StdOutCmd(s string) error {
words := Split(s)
cmd := exec.Command(words[0], words[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func Split(line string) []string {
var words []string
Words:
for {
line = strings.TrimLeft(line, " \t")
if len(line) == 0 {
break
}
if line[0] == '"' {
for i := 1; i < len(line); i++ {
c := line[i] // Only looking for ASCII so this is OK.
switch c {
case '\\':
if i+1 == len(line) {
log.Panic("bad backslash")
}
i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
case '"':
word, err := strconv.Unquote(line[0 : i+1])
if err != nil {
log.Panic("bad quoted string")
}
words = append(words, word)
line = line[i+1:]
// Check the next character is space or end of line.
if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
log.Panic("expect space after quoted argument")
}
continue Words
}
}
log.Panic("mismatched quoted string")
}
i := strings.IndexAny(line, " \t")
if i < 0 {
i = len(line)
}
words = append(words, line[0:i])
line = line[i:]
}
// Substitute command if required.
// Substitute environment variables.
for i, word := range words {
words[i] = os.Expand(word, expandVar)
}
return words
}
var env = []string{
"GOARCH=" + runtime.GOARCH,
"GOOS=" + runtime.GOOS,
}
func expandVar(word string) string {
w := word + "="
for _, e := range env {
if strings.HasPrefix(e, w) {
return e[len(w):]
}
}
return os.Getenv(word)
}
func CmdLog(s string) (string, error) {
out, err := Cmd(s)
if err != nil {
log.Printf(`exec:"%s" failed,out:%v,err:%v`, s, out, err)
return out, err
}
log.Printf(`exec:"%s"`, s)
return out, err
}
func CmdInDir(s, dir string) (string, error) {
words := Split(s)
cmd := exec.Command(words[0], words[1:]...)
cmd.Dir = dir
buf, err := cmd.CombinedOutput()
if err != nil {
return stringsi.BytesToString(buf), err
}
if len(buf) == 0 {
return "", nil
}
lastIndex := len(buf) - 1
if buf[lastIndex] == '\n' {
buf = buf[:lastIndex]
}
return stringsi.BytesToString(buf), nil
}
func WaitShutdown() {
// Set up signal handling.
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
done := make(chan bool, 1)
go func() {
sig := <-signals
fmt.Println("")
fmt.Println("Disconnection requested via Ctrl+C", sig)
done <- true
}()
fmt.Println("Press Ctrl+C to disconnect.")
<-done
os.Exit(0)
}