-
Notifications
You must be signed in to change notification settings - Fork 1
/
runner.go
170 lines (131 loc) · 4.46 KB
/
runner.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package exe
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"text/template"
)
// Runner combines all run functions into one interface.
type Runner interface {
Run(cmd *exec.Cmd, name string, settings ...SettingsFunc)
RunE(cmd *exec.Cmd, name string, settings ...SettingsFunc) (err error)
RunWithOutput(cmd *exec.Cmd, name string, settings ...SettingsFunc) string
RunWithOutputE(cmd *exec.Cmd, name string, settings ...SettingsFunc) (out string, err error)
Execute(s string, obj interface{}, settings ...SettingsFunc) *exec.Cmd
ExecuteE(s string, obj interface{}, settings ...SettingsFunc) (*exec.Cmd, error)
SplitCommand(string) []string
ExecuteWithContext(ctx context.Context, s string, obj interface{}, settings ...SettingsFunc) *exec.Cmd
ExecuteEWithContext(ctx context.Context, s string, obj interface{}, settings ...SettingsFunc) (*exec.Cmd, error)
ExecuteWithOutput(s string, obj interface{}, settings ...SettingsFunc) string
ExecuteWithOutputE(s string, obj interface{}, settings ...SettingsFunc) (out string, err error)
}
// DefaultRunner returns the default Runner implementation.
func DefaultRunner() Runner {
return &runner{}
}
type runner struct {
}
func (r *runner) Run(cmd *exec.Cmd, name string, settings ...SettingsFunc) {
if err := r.RunE(cmd, name, settings...); err != nil {
os.Exit(1)
}
}
func (r *runner) RunE(cmd *exec.Cmd, name string, settings ...SettingsFunc) (err error) {
setting := extractSettingsFromSlice(settings)
applySettings(cmd, setting)
_, err = runWithSettings(cmd, setting)
if err != nil {
fmt.Printf("%s failed: %v\n", name, err)
return err
}
return nil
}
func (r *runner) RunWithOutput(cmd *exec.Cmd, name string, settings ...SettingsFunc) string {
out, err := r.RunWithOutputE(cmd, name, settings...)
if err != nil {
os.Exit(1)
}
return out
}
func (r *runner) RunWithOutputE(cmd *exec.Cmd, name string, settings ...SettingsFunc) (out string, err error) {
setting := extractSettingsFromSlice(append(settings, withOutput))
applySettings(cmd, setting)
out, err = runWithSettings(cmd, setting)
if err != nil {
fmt.Printf("%s - %v failed with %v\n", name, cmd, err)
return out, err
}
return
}
func (r *runner) Execute(s string, obj interface{}, settings ...SettingsFunc) *exec.Cmd {
return r.ExecuteWithContext(context.Background(), s, obj, settings...)
}
func (r *runner) ExecuteE(s string, obj interface{}, settings ...SettingsFunc) (*exec.Cmd, error) {
return r.ExecuteEWithContext(context.Background(), s, obj, settings...)
}
func (r *runner) ExecuteWithContext(ctx context.Context, s string, obj interface{}, settings ...SettingsFunc) *exec.Cmd {
cmd, _ := r.ExecuteEWithContext(ctx, s, obj, settings...)
return cmd
}
func (r *runner) ExecuteEWithContext(ctx context.Context, s string, obj interface{}, settings ...SettingsFunc) (*exec.Cmd, error) {
t := template.Must(template.New("").Parse(s))
var tpl bytes.Buffer
if err := t.Execute(&tpl, obj); err != nil {
panic(err)
}
fmt.Println(tpl.String())
args := r.SplitCommand(os.ExpandEnv(tpl.String()))
//args := strings.Split(tpl.String(), " ")
if len(args) == 0 {
panic("template length was zero.")
}
cmd := exec.CommandContext(ctx, args[0], args[1:]...)
return cmd, r.RunE(cmd, args[0], settings...)
}
func (r *runner) ExecuteWithOutput(s string, obj interface{}, settings ...SettingsFunc) string {
out, err := r.ExecuteWithOutputE(s, obj, settings...)
if err != nil {
fmt.Printf("Command failed with %v\n", err)
os.Exit(1)
}
return out
}
func (r *runner) ExecuteWithOutputE(s string, obj interface{}, settings ...SettingsFunc) (out string, err error) {
t := template.Must(template.New("").Parse(s))
var tpl bytes.Buffer
if err := t.Execute(&tpl, obj); err != nil {
panic(err)
}
fmt.Println(tpl.String())
args := r.SplitCommand(os.ExpandEnv(tpl.String()))
if len(args) == 0 {
panic("template length was zero.")
}
cmd := exec.Command(args[0], args[1:]...)
return r.RunWithOutputE(cmd, args[0], settings...)
}
func extractSettingsFromSlice(settings []SettingsFunc) ExecuteSetting {
setting := defaultSettings()
for _, settingsFunc := range settings {
settingsFunc(&setting)
}
return setting
}
func applySettings(cmd *exec.Cmd, setting ExecuteSetting) {
if setting.dir != "" {
cmd.Dir = os.ExpandEnv(setting.dir)
}
if setting.output {
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
} else {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
}
}
func defaultSettings() ExecuteSetting {
return ExecuteSetting{}
}