xref: /aosp_15_r20/external/toolchain-utils/compiler_wrapper/env.go (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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