aboutsummaryrefslogtreecommitdiff
path: root/compiler_wrapper/env.go
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_wrapper/env.go')
-rw-r--r--compiler_wrapper/env.go45
1 files changed, 37 insertions, 8 deletions
diff --git a/compiler_wrapper/env.go b/compiler_wrapper/env.go
index 40bc2e41..bbf3ec45 100644
--- a/compiler_wrapper/env.go
+++ b/compiler_wrapper/env.go
@@ -17,9 +17,10 @@ type env interface {
getenv(key string) string
environ() []string
getwd() string
+ stdin() io.Reader
stdout() io.Writer
stderr() io.Writer
- run(cmd *command, stdout io.Writer, stderr io.Writer) error
+ run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error
exec(cmd *command) error
}
@@ -49,6 +50,10 @@ func (env *processEnv) getwd() string {
return env.wd
}
+func (env *processEnv) stdin() io.Reader {
+ return os.Stdin
+}
+
func (env *processEnv) stdout() io.Writer {
return os.Stdout
}
@@ -62,16 +67,36 @@ func (env *processEnv) exec(cmd *command) error {
return syscall.Exec(execCmd.Path, execCmd.Args, execCmd.Env)
}
-func (env *processEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error {
+func (env *processEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
execCmd := newExecCmd(env, cmd)
+ execCmd.Stdin = stdin
execCmd.Stdout = stdout
execCmd.Stderr = stderr
+ _, stdinIsFile := stdin.(*os.File)
+ _, stdinIsBytesReader := stdin.(*bytes.Reader)
+ if stdin != nil && !stdinIsFile && !stdinIsBytesReader {
+ // We can't use execCmd.Run() here as that blocks if stdin blocks,
+ // even if the underlying process has already terminated. We care
+ // especially about the case when stdin is an io.TeeReader for os.Stdin.
+ // See https://github.com/golang/go/issues/7990 for more details.
+ if err := execCmd.Start(); err != nil {
+ return err
+ }
+ if _, err := execCmd.Process.Wait(); err != nil {
+ return err
+ }
+ // Closing Stdin here as we didn't wait for the read to finish via
+ // execCmd.Wait to prevent race conditions.
+ os.Stdin.Close()
+ return nil
+ }
return execCmd.Run()
}
type commandRecordingEnv struct {
env
- cmdResults []*commandResult
+ stdinReader io.Reader
+ cmdResults []*commandResult
}
type commandResult struct {
Cmd *command `json:"cmd"`
@@ -82,16 +107,20 @@ type commandResult struct {
var _ env = (*commandRecordingEnv)(nil)
+func (env *commandRecordingEnv) stdin() io.Reader {
+ return env.stdinReader
+}
+
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())
+ return env.run(cmd, env.stdin(), env.stdout(), env.stderr())
}
-func (env *commandRecordingEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error {
+func (env *commandRecordingEnv) run(cmd *command, stdin io.Reader, 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))
+ err := env.env.run(cmd, stdin, io.MultiWriter(stdout, stdoutBuffer), io.MultiWriter(stderr, stderrBuffer))
if exitCode, ok := getExitCode(err); ok {
env.cmdResults = append(env.cmdResults, &commandResult{
Cmd: cmd,
@@ -114,9 +143,9 @@ func (env *printingEnv) exec(cmd *command) error {
return env.env.exec(cmd)
}
-func (env *printingEnv) run(cmd *command, stdout io.Writer, stderr io.Writer) error {
+func (env *printingEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
printCmd(env, cmd)
- return env.env.run(cmd, stdout, stderr)
+ return env.env.run(cmd, stdin, stdout, stderr)
}
func printCmd(env env, cmd *command) {