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
|
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
"syscall"
)
type env interface {
getenv(key string) string
environ() []string
getwd() string
stdout() io.Writer
stderr() io.Writer
run(cmd *command, stdout io.Writer, stderr io.Writer) error
exec(cmd *command) error
}
type processEnv struct {
wd string
}
func newProcessEnv() (env, error) {
wd, err := os.Getwd()
if err != nil {
return nil, wrapErrorwithSourceLocf(err, "failed to read working directory")
}
return &processEnv{wd: wd}, nil
}
var _ env = (*processEnv)(nil)
func (env *processEnv) getenv(key string) string {
return os.Getenv(key)
}
func (env *processEnv) environ() []string {
return os.Environ()
}
func (env *processEnv) getwd() string {
return env.wd
}
func (env *processEnv) stdout() io.Writer {
return os.Stdout
}
func (env *processEnv) stderr() io.Writer {
return os.Stderr
}
func (env *processEnv) exec(cmd *command) error {
execCmd := newExecCmd(env, cmd)
return syscall.Exec(execCmd.Path, execCmd.Args, execCmd.Env)
}
func (env *processEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error {
execCmd := newExecCmd(env, cmd)
execCmd.Stdout = stdout
execCmd.Stderr = stderr
return execCmd.Run()
}
type commandRecordingEnv struct {
env
cmdResults []*commandResult
}
type commandResult struct {
cmd *command
stdout string
stderr string
exitCode int
}
var _ env = (*commandRecordingEnv)(nil)
func (env *commandRecordingEnv) exec(cmd *command) error {
// Note: We treat exec the same as run so that we can do work
// after the call.
return env.run(cmd, env.stdout(), env.stderr())
}
func (env *commandRecordingEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error {
stdoutBuffer := &bytes.Buffer{}
stderrBuffer := &bytes.Buffer{}
err := env.env.run(cmd, io.MultiWriter(stdout, stdoutBuffer), io.MultiWriter(stderr, stderrBuffer))
if exitCode, ok := getExitCode(err); ok {
env.cmdResults = append(env.cmdResults, &commandResult{
cmd: cmd,
stdout: stdoutBuffer.String(),
stderr: stderrBuffer.String(),
exitCode: exitCode,
})
}
return err
}
type printingEnv struct {
env
}
var _env = (*printingEnv)(nil)
func (env *printingEnv) exec(cmd *command) error {
printCmd(env, cmd)
return env.env.exec(cmd)
}
func (env *printingEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error {
printCmd(env, cmd)
return env.env.run(cmd, stdout, stderr)
}
func printCmd(env env, cmd *command) {
fmt.Fprintf(env.stderr(), "cd '%s' &&", env.getwd())
if len(cmd.envUpdates) > 0 {
fmt.Fprintf(env.stderr(), " env '%s'", strings.Join(cmd.envUpdates, "' '"))
}
fmt.Fprintf(env.stderr(), " '%s'", getAbsCmdPath(env, cmd))
if len(cmd.args) > 0 {
fmt.Fprintf(env.stderr(), " '%s'", strings.Join(cmd.args, "' '"))
}
io.WriteString(env.stderr(), "\n")
}
|