Skip to content

Commit 41988f9

Browse files
committed
fix(cli): fix case where linkLocalBazel fails when os.UserCacheDir returns path starting with ~ (#1182)
Also run `help flags-as-proto` command in a UserCacheDir() location instead of the tmp dir and fix order of error handling for the result of that call. UserCacheDir() is more robust since tmpdir is not guaranteed to exist or to be writable (as per [golang docs](https://pkg.go.dev/os#TempDir)). We already depend on UserCacheDir() in the CLI code. GitOrigin-RevId: df084e1effce5ba4a813f56b33260e9749c5526d
1 parent bb0946f commit 41988f9

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

pkg/bazel/bazel.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"fmt"
2424
"io"
2525
"os"
26+
"path"
2627
"path/filepath"
2728
"strings"
2829

@@ -162,6 +163,23 @@ func (b *bazel) Flags() (map[string]*flags.FlagInfo, error) {
162163
if allFlags != nil {
163164
return allFlags, nil
164165
}
166+
167+
// create a directory in the user cache dir with an empty WORKSPACE file to run
168+
// `bazel help flags-as-proto` in so it doesn't affect the bazel server in the user's WORKSPACE
169+
userCacheDir, err := UserCacheDir()
170+
if err != nil {
171+
return nil, fmt.Errorf("failed to get user cache dir: %w", err)
172+
}
173+
tmpdir := path.Join(userCacheDir, ".aspect/cli-flags-as-proto")
174+
err = os.MkdirAll(tmpdir, os.ModePerm)
175+
if err != nil {
176+
return nil, fmt.Errorf("failed write create directory %s: %w", tmpdir, err)
177+
}
178+
err = os.WriteFile(path.Join(tmpdir, "WORKSPACE"), []byte{}, 0644)
179+
if err != nil {
180+
return nil, fmt.Errorf("failed write WORKSPACE file in %s: %w", tmpdir, err)
181+
}
182+
165183
var stdout bytes.Buffer
166184
var stderr bytes.Buffer
167185
streams := ioutils.Streams{
@@ -174,23 +192,23 @@ func (b *bazel) Flags() (map[string]*flags.FlagInfo, error) {
174192
bazelExitCode := make(chan int, 1)
175193
defer close(bazelErrs)
176194
defer close(bazelExitCode)
177-
go func() {
195+
196+
go func(wd string) {
178197
// Running in batch mode will prevent bazel from spawning a daemon. Spawning a bazel daemon takes time which is something we don't want here.
179198
// Also, instructing bazel to ignore all rc files will protect it from failing if any of the rc files is broken.
180-
tmpdir := os.TempDir()
181-
exitCode, err := b.RunCommand(streams, &tmpdir, "--nobatch", "--ignore_all_rc_files", "help", "flags-as-proto")
199+
exitCode, err := b.RunCommand(streams, &wd, "--nobatch", "--ignore_all_rc_files", "help", "flags-as-proto")
182200
bazelErrs <- err
183201
bazelExitCode <- exitCode
184-
}()
185-
186-
if exitCode := <-bazelExitCode; exitCode != 0 {
187-
return nil, fmt.Errorf("failed to get bazel flags: %w", fmt.Errorf("bazel has quit with code %d\nstderr:\n%s", exitCode, stderr.String()))
188-
}
202+
}(tmpdir)
189203

190204
if err := <-bazelErrs; err != nil {
191205
return nil, fmt.Errorf("failed to get bazel flags: %w", err)
192206
}
193207

208+
if exitCode := <-bazelExitCode; exitCode != 0 {
209+
return nil, fmt.Errorf("failed to get bazel flags running in %s: %w", tmpdir, fmt.Errorf("bazel has quit with code %d\nstderr:\n%s", exitCode, stderr.String()))
210+
}
211+
194212
helpProtoBytes, err := io.ReadAll(stdoutDecoder)
195213
if err != nil {
196214
return nil, fmt.Errorf("failed to get bazel flags: %w", err)

pkg/bazel/bazelisk.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,31 @@ func NewBazelisk(workspaceRoot string) *Bazelisk {
6767
return &Bazelisk{workspaceRoot: workspaceRoot}
6868
}
6969

70+
func UserCacheDir() (string, error) {
71+
userCacheDir, err := os.UserCacheDir()
72+
if err != nil {
73+
return "", fmt.Errorf("could not get the user's cache directory: %v", err)
74+
}
75+
76+
// We hit a case in a bazel-in-bazel test where os.UserCacheDir() return a path starting with '~'.
77+
// Run it through homedir.Expand to turn it into an absolute path incase that happens.
78+
userCacheDir, err = homedir.Expand(userCacheDir)
79+
if err != nil {
80+
return "", fmt.Errorf("could not expand home directory in path: %v", err)
81+
}
82+
83+
return userCacheDir, err
84+
}
85+
7086
// Run runs the main Bazelisk logic for the given arguments and Bazel repositories.
7187
func (bazelisk *Bazelisk) Run(args []string, repos *core.Repositories, streams ioutils.Streams, env []string, wd *string) (int, error) {
7288
httputil.UserAgent = bazelisk.getUserAgent()
7389

7490
bazeliskHome := bazelisk.GetEnvOrConfig("BAZELISK_HOME")
7591
if len(bazeliskHome) == 0 {
76-
userCacheDir, err := os.UserCacheDir()
92+
userCacheDir, err := UserCacheDir()
7793
if err != nil {
78-
return -1, fmt.Errorf("could not get the user's cache directory: %v", err)
94+
return -1, err
7995
}
8096

8197
bazeliskHome = filepath.Join(userCacheDir, "bazelisk")
@@ -128,7 +144,7 @@ func (bazelisk *Bazelisk) Run(args []string, repos *core.Repositories, streams i
128144
baseDirectory := filepath.Join(bazeliskHome, "local")
129145
bazelPath, err = linkLocalBazel(baseDirectory, bazelPath)
130146
if err != nil {
131-
return -1, fmt.Errorf("cound not link local Bazel: %v", err)
147+
return -1, fmt.Errorf("could not link local Bazel: %v", err)
132148
}
133149
}
134150

0 commit comments

Comments
 (0)