1*760c253cSXin Li// Copyright 2019 The ChromiumOS Authors 2*760c253cSXin Li// Use of this source code is governed by a BSD-style license that can be 3*760c253cSXin Li// found in the LICENSE file. 4*760c253cSXin Li 5*760c253cSXin Lipackage main 6*760c253cSXin Li 7*760c253cSXin Liimport ( 8*760c253cSXin Li "bytes" 9*760c253cSXin Li "fmt" 10*760c253cSXin Li "io" 11*760c253cSXin Li "os" 12*760c253cSXin Li "strings" 13*760c253cSXin Li "syscall" 14*760c253cSXin Li "time" 15*760c253cSXin Li) 16*760c253cSXin Li 17*760c253cSXin Liconst artifactsTmpDirEnvName = "CROS_ARTIFACTS_TMP_DIR" 18*760c253cSXin Li 19*760c253cSXin Litype env interface { 20*760c253cSXin Li umask(int) int 21*760c253cSXin Li getenv(key string) (string, bool) 22*760c253cSXin Li environ() []string 23*760c253cSXin Li getwd() string 24*760c253cSXin Li stdin() io.Reader 25*760c253cSXin Li stdout() io.Writer 26*760c253cSXin Li stderr() io.Writer 27*760c253cSXin Li run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error 28*760c253cSXin Li runWithTimeout(cmd *command, duration time.Duration) error 29*760c253cSXin Li exec(cmd *command) error 30*760c253cSXin Li} 31*760c253cSXin Li 32*760c253cSXin Litype processEnv struct { 33*760c253cSXin Li wd string 34*760c253cSXin Li} 35*760c253cSXin Li 36*760c253cSXin Lifunc newProcessEnv() (env, error) { 37*760c253cSXin Li wd, err := os.Getwd() 38*760c253cSXin Li if err != nil { 39*760c253cSXin Li return nil, wrapErrorwithSourceLocf(err, "failed to read working directory") 40*760c253cSXin Li } 41*760c253cSXin Li 42*760c253cSXin Li // Note: On Linux, Getwd may resolve to /proc/self/cwd, since it checks the PWD environment 43*760c253cSXin Li // variable. We need to read the link to get the actual working directory. We can't always 44*760c253cSXin Li // do this as we are calculating the path to clang, since following a symlinked cwd first 45*760c253cSXin Li // would make this calculation invalid. 46*760c253cSXin Li // 47*760c253cSXin Li // FIXME(gbiv): It's not clear why always Readlink()ing here an issue. crrev.com/c/1764624 48*760c253cSXin Li // might provide helpful context? 49*760c253cSXin Li if wd == "/proc/self/cwd" { 50*760c253cSXin Li wd, err = os.Readlink(wd) 51*760c253cSXin Li if err != nil { 52*760c253cSXin Li return nil, wrapErrorwithSourceLocf(err, "resolving /proc/self/cwd") 53*760c253cSXin Li } 54*760c253cSXin Li } 55*760c253cSXin Li 56*760c253cSXin Li return &processEnv{wd: wd}, nil 57*760c253cSXin Li} 58*760c253cSXin Li 59*760c253cSXin Livar _ env = (*processEnv)(nil) 60*760c253cSXin Li 61*760c253cSXin Lifunc (env *processEnv) umask(newmask int) (oldmask int) { 62*760c253cSXin Li return syscall.Umask(newmask) 63*760c253cSXin Li} 64*760c253cSXin Li 65*760c253cSXin Lifunc (env *processEnv) getenv(key string) (string, bool) { 66*760c253cSXin Li return os.LookupEnv(key) 67*760c253cSXin Li} 68*760c253cSXin Li 69*760c253cSXin Lifunc (env *processEnv) environ() []string { 70*760c253cSXin Li return os.Environ() 71*760c253cSXin Li} 72*760c253cSXin Li 73*760c253cSXin Lifunc (env *processEnv) getwd() string { 74*760c253cSXin Li return env.wd 75*760c253cSXin Li} 76*760c253cSXin Li 77*760c253cSXin Lifunc (env *processEnv) stdin() io.Reader { 78*760c253cSXin Li return os.Stdin 79*760c253cSXin Li} 80*760c253cSXin Li 81*760c253cSXin Lifunc (env *processEnv) stdout() io.Writer { 82*760c253cSXin Li return os.Stdout 83*760c253cSXin Li} 84*760c253cSXin Li 85*760c253cSXin Lifunc (env *processEnv) stderr() io.Writer { 86*760c253cSXin Li return os.Stderr 87*760c253cSXin Li} 88*760c253cSXin Li 89*760c253cSXin Lifunc (env *processEnv) exec(cmd *command) error { 90*760c253cSXin Li return execCmd(env, cmd) 91*760c253cSXin Li} 92*760c253cSXin Li 93*760c253cSXin Lifunc (env *processEnv) runWithTimeout(cmd *command, duration time.Duration) error { 94*760c253cSXin Li return runCmdWithTimeout(env, cmd, duration) 95*760c253cSXin Li} 96*760c253cSXin Li 97*760c253cSXin Lifunc (env *processEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 98*760c253cSXin Li return runCmd(env, cmd, stdin, stdout, stderr) 99*760c253cSXin Li} 100*760c253cSXin Li 101*760c253cSXin Litype commandRecordingEnv struct { 102*760c253cSXin Li env 103*760c253cSXin Li stdinReader io.Reader 104*760c253cSXin Li cmdResults []*commandResult 105*760c253cSXin Li} 106*760c253cSXin Litype commandResult struct { 107*760c253cSXin Li Cmd *command `json:"cmd"` 108*760c253cSXin Li Stdout string `json:"stdout,omitempty"` 109*760c253cSXin Li Stderr string `json:"stderr,omitempty"` 110*760c253cSXin Li ExitCode int `json:"exitcode,omitempty"` 111*760c253cSXin Li} 112*760c253cSXin Li 113*760c253cSXin Livar _ env = (*commandRecordingEnv)(nil) 114*760c253cSXin Li 115*760c253cSXin Lifunc (env *commandRecordingEnv) stdin() io.Reader { 116*760c253cSXin Li return env.stdinReader 117*760c253cSXin Li} 118*760c253cSXin Li 119*760c253cSXin Lifunc (env *commandRecordingEnv) exec(cmd *command) error { 120*760c253cSXin Li // Note: We treat exec the same as run so that we can do work 121*760c253cSXin Li // after the call. 122*760c253cSXin Li return env.run(cmd, env.stdin(), env.stdout(), env.stderr()) 123*760c253cSXin Li} 124*760c253cSXin Li 125*760c253cSXin Lifunc (env *commandRecordingEnv) runWithTimeout(cmd *command, duration time.Duration) error { 126*760c253cSXin Li return runCmdWithTimeout(env, cmd, duration) 127*760c253cSXin Li} 128*760c253cSXin Li 129*760c253cSXin Lifunc (env *commandRecordingEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 130*760c253cSXin Li stdoutBuffer := &bytes.Buffer{} 131*760c253cSXin Li stderrBuffer := &bytes.Buffer{} 132*760c253cSXin Li err := env.env.run(cmd, stdin, io.MultiWriter(stdout, stdoutBuffer), io.MultiWriter(stderr, stderrBuffer)) 133*760c253cSXin Li if exitCode, ok := getExitCode(err); ok { 134*760c253cSXin Li env.cmdResults = append(env.cmdResults, &commandResult{ 135*760c253cSXin Li Cmd: cmd, 136*760c253cSXin Li Stdout: stdoutBuffer.String(), 137*760c253cSXin Li Stderr: stderrBuffer.String(), 138*760c253cSXin Li ExitCode: exitCode, 139*760c253cSXin Li }) 140*760c253cSXin Li } 141*760c253cSXin Li return err 142*760c253cSXin Li} 143*760c253cSXin Li 144*760c253cSXin Litype printingEnv struct { 145*760c253cSXin Li env 146*760c253cSXin Li} 147*760c253cSXin Li 148*760c253cSXin Livar _ env = (*printingEnv)(nil) 149*760c253cSXin Li 150*760c253cSXin Lifunc (env *printingEnv) exec(cmd *command) error { 151*760c253cSXin Li printCmd(env, cmd) 152*760c253cSXin Li return env.env.exec(cmd) 153*760c253cSXin Li} 154*760c253cSXin Li 155*760c253cSXin Lifunc (env *printingEnv) runWithTimeout(cmd *command, duration time.Duration) error { 156*760c253cSXin Li printCmd(env, cmd) 157*760c253cSXin Li return env.env.runWithTimeout(cmd, duration) 158*760c253cSXin Li} 159*760c253cSXin Li 160*760c253cSXin Lifunc (env *printingEnv) run(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error { 161*760c253cSXin Li printCmd(env, cmd) 162*760c253cSXin Li return env.env.run(cmd, stdin, stdout, stderr) 163*760c253cSXin Li} 164*760c253cSXin Li 165*760c253cSXin Lifunc printCmd(env env, cmd *command) { 166*760c253cSXin Li fmt.Fprintf(env.stderr(), "cd '%s' &&", env.getwd()) 167*760c253cSXin Li if len(cmd.EnvUpdates) > 0 { 168*760c253cSXin Li fmt.Fprintf(env.stderr(), " env '%s'", strings.Join(cmd.EnvUpdates, "' '")) 169*760c253cSXin Li } 170*760c253cSXin Li fmt.Fprintf(env.stderr(), " '%s'", getAbsCmdPath(env, cmd)) 171*760c253cSXin Li if len(cmd.Args) > 0 { 172*760c253cSXin Li fmt.Fprintf(env.stderr(), " '%s'", strings.Join(cmd.Args, "' '")) 173*760c253cSXin Li } 174*760c253cSXin Li io.WriteString(env.stderr(), "\n") 175*760c253cSXin Li} 176*760c253cSXin Li 177*760c253cSXin Lifunc getCompilerArtifactsDir(env env) string { 178*760c253cSXin Li const defaultArtifactDir = "/tmp" 179*760c253cSXin Li value, _ := env.getenv(artifactsTmpDirEnvName) 180*760c253cSXin Li if value == "" { 181*760c253cSXin Li fmt.Fprintf(env.stdout(), "$%s is not set, artifacts will be written to %s", artifactsTmpDirEnvName, defaultArtifactDir) 182*760c253cSXin Li return defaultArtifactDir 183*760c253cSXin Li } 184*760c253cSXin Li return value 185*760c253cSXin Li 186*760c253cSXin Li} 187