-
Notifications
You must be signed in to change notification settings - Fork 0
/
step.go
133 lines (107 loc) · 3.04 KB
/
step.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
package confile
import (
"fmt"
"os"
"os/exec"
"github.com/gomicro/forge/vars"
"github.com/spf13/viper"
)
// Step represents details of single step to be executed by the cli.
type Step struct {
Cmd string `yaml:"cmd,omitempty"`
Cmds []string `yaml:"cmds,omitempty"`
Envs map[string]string `yaml:"envs,omitempty"`
Help string `yaml:"help,omitempty"`
Post []string `yaml:"post,omitempty"`
Pre []string `yaml:"pre,omitempty"`
Steps []string `yaml:"steps,omitempty"`
projectEnvs map[string]string
vars *vars.Vars
}
// Execute runs the command that is specified for the step. It returns the output
// of the command and any errors it encounters.
func (s *Step) Execute(allSteps map[string]*Step, projectEnvs map[string]string, vars *vars.Vars) error {
skipPre := viper.GetBool("solo") || viper.GetBool("no-pre")
skipPost := viper.GetBool("solo") || viper.GetBool("no-post")
s.projectEnvs = projectEnvs
s.vars = vars
if len(s.Pre) > 0 && !skipPre {
err := s.executeSteps(s.Pre, allSteps)
if err != nil {
return fmt.Errorf("step: execute pre: %v", err.Error())
}
}
if len(s.Steps) > 0 {
err := s.executeSteps(s.Steps, allSteps)
if err != nil {
return fmt.Errorf("step: execute steps: %v", err.Error())
}
} else if len(s.Cmds) > 0 {
err := s.executeCmds()
if err != nil {
return fmt.Errorf("step: execute cmds: %v", err.Error())
}
} else {
err := s.executeCmd()
if err != nil {
return fmt.Errorf("step: execute cmd: %v", err.Error())
}
}
if len(s.Post) > 0 && !skipPost {
err := s.executeSteps(s.Post, allSteps)
if err != nil {
return fmt.Errorf("step: execute post: %v", err.Error())
}
}
return nil
}
func (s *Step) executeCmd() error {
cmdString := s.vars.Process(s.Cmd)
return executeCmd(cmdString, s.Envs, s.projectEnvs, s.vars)
}
func (s *Step) executeCmds() error {
for _, c := range s.Cmds {
cmdString := s.vars.Process(c)
err := executeCmd(cmdString, s.Envs, s.projectEnvs, s.vars)
if err != nil {
return fmt.Errorf("cmds: cmd exec: %v", err.Error())
}
}
return nil
}
func (s *Step) executeSteps(execList []string, allSteps map[string]*Step) error {
for _, step := range execList {
s, ok := allSteps[step]
if !ok {
return fmt.Errorf("step does not exist: %v", step)
}
err := s.Execute(allSteps, s.projectEnvs, s.vars)
if err != nil {
return err
}
}
return nil
}
func executeCmd(cmdString string, stepEnvs, projectEnvs map[string]string, vars *vars.Vars) error {
cmd := exec.Command("bash", "-c", cmdString)
cmd.Env = toSlice(stepEnvs)
cmd.Env = append(cmd.Env, toSlice(projectEnvs)...)
for i := range cmd.Env {
cmd.Env[i] = vars.Process(cmd.Env[i])
}
cmd.Env = append(cmd.Env, os.Environ()...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
return fmt.Errorf("execute: %v", err.Error())
}
return cmd.Wait()
}
func toSlice(e map[string]string) []string {
out := []string{}
for k, v := range e {
out = append(out, fmt.Sprintf("%v=%v", k, v))
}
return out
}