aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/env.go
diff options
context:
space:
mode:
authorTobias Bosch <tbosch@google.com>2019-06-24 09:31:39 -0700
committerTobias Bosch <tbosch@google.com>2019-06-28 19:00:23 +0000
commit900dbc92800d8fc927905db29cb302461054cf97 (patch)
treec74ecbfb01ee4ee679090139596aef3546f19d9b /compiler_wrapper/env.go
parent739e6abb2cd03b60e579df31ad55870a4a00260a (diff)
downloadtoolchain-utils-900dbc92800d8fc927905db29cb302461054cf97.tar.gz
Introduce infrastructure for calling and testing nested
commands, error messages and exit codes. Also: - implements the -Xclang-path= flag as use case of calling a nested command. - adds tests for forwarding errors, comparing against the old wrapper, and exit codes. - captures the source locations of errors in error messages. - compares exit codes of new wrapper and old wrapper. BUG=chromium:773875 TEST=unit test Change-Id: I919e58091d093d68939809f676f799a68ec7a34e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1676833 Reviewed-by: George Burgess <gbiv@chromium.org> Tested-by: Tobias Bosch <tbosch@google.com>
Diffstat (limited to 'compiler_wrapper/env.go')
-rw-r--r--compiler_wrapper/env.go64
1 files changed, 63 insertions, 1 deletions
diff --git a/compiler_wrapper/env.go b/compiler_wrapper/env.go
index 3c106d4a..6cf1a1b9 100644
--- a/compiler_wrapper/env.go
+++ b/compiler_wrapper/env.go
@@ -1,13 +1,20 @@
package main
import (
+ "bytes"
+ "io"
"os"
+ "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 {
@@ -17,7 +24,7 @@ type processEnv struct {
func newProcessEnv() (env, error) {
wd, err := os.Getwd()
if err != nil {
- return nil, err
+ return nil, wrapErrorwithSourceLocf(err, "failed to read working directory")
}
return &processEnv{wd: wd}, nil
}
@@ -35,3 +42,58 @@ func (env *processEnv) environ() []string {
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 will only get here if the exec failed,
+ // e.g. when the underlying command could not be called.
+ // In this case, we don't compare commands, so nothing to record.
+ return env.exec(cmd)
+}
+
+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
+}