Skip to content

Commit

Permalink
Support user .bazeliskrc in addition to workspace root .bazeliskrc (
Browse files Browse the repository at this point in the history
#390)

* core: Implement fallback to .bazeliskrc in the user home directory

* README.md: Documentation for ~/.bazeliskrc usage

* bazelisk_test.sh: Integration test for user home ~/.bazeliskrc precedence

* bazelisk_test.sh: Set USERPROFILE as user home for compatibility with Windows
  • Loading branch information
LINKIWI committed Nov 4, 2022
1 parent aa0e93d commit c908174
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 33 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ You can control the user agent that Bazelisk sends in all HTTP requests by setti

# .bazeliskrc configuration file

The Go version supports a `.bazeliskrc` file in the root directory of a workspace. This file allows users to set environment variables persistently.
The Go version supports a `.bazeliskrc` file in the root directory of a workspace and the user home directory. This file allows users to set environment variables persistently.

Example file content:

Expand All @@ -151,7 +151,11 @@ The following variables can be set:
- `BAZELISK_USER_AGENT`
- `USE_BAZEL_VERSION`

Please note that the actual environment variables take precedence over those in the `.bazeliskrc` file.
Configuration variables are evaluated with precedence order. The preferred values are derived in order from highest to lowest precedence as follows:

* Variables defined in the environment
* Variables defined in the workspace root `.bazeliskrc`
* Variables defined in the user home `.bazeliskrc`

## Requirements

Expand Down
45 changes: 42 additions & 3 deletions bazelisk_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ shift 1
# GitHub by default, whereas the Go version GCS (without this json file)
function setup() {
unset USE_BAZEL_VERSION

USER_HOME="$(mktemp -d $TEST_TMPDIR/user.XXXXXX)"
BAZELISK_HOME="$(mktemp -d $TEST_TMPDIR/home.XXXXXX)"

cp "$(rlocation __main__/releases_for_tests.json)" "${BAZELISK_HOME}/bazelbuild-releases.json"
Expand Down Expand Up @@ -129,12 +131,41 @@ function test_bazel_version_prefer_environment_to_bazeliskrc() {
(echo "FAIL: Expected to find 'Build label: 0.20.0' in the output of 'bazelisk version'"; exit 1)
}

function test_bazel_version_from_bazeliskrc() {
function test_bazel_version_from_workspace_bazeliskrc() {
setup

echo "USE_BAZEL_VERSION=0.19.0" > .bazeliskrc

BAZELISK_HOME="$BAZELISK_HOME" \
bazelisk version 2>&1 | tee log

grep "Build label: 0.19.0" log || \
(echo "FAIL: Expected to find 'Build label: 0.19.0' in the output of 'bazelisk version'"; exit 1)
}

function test_bazel_version_from_user_home_bazeliskrc() {
setup

echo "USE_BAZEL_VERSION=0.19.0" > "${USER_HOME}/.bazeliskrc"

BAZELISK_HOME="$BAZELISK_HOME" \
HOME="$USER_HOME" \
USERPROFILE="$USER_HOME" \
bazelisk version 2>&1 | tee log

grep "Build label: 0.19.0" log || \
(echo "FAIL: Expected to find 'Build label: 0.19.0' in the output of 'bazelisk version'"; exit 1)
}

function test_bazel_version_prefer_workspace_bazeliskrc_to_user_home_bazeliskrc() {
setup

echo "USE_BAZEL_VERSION=0.19.0" > .bazeliskrc
echo "USE_BAZEL_VERSION=0.20.0" > "${USER_HOME}/.bazeliskrc"

BAZELISK_HOME="$BAZELISK_HOME" \
HOME="$USER_HOME" \
USERPROFILE="$USER_HOME" \
bazelisk version 2>&1 | tee log

grep "Build label: 0.19.0" log || \
Expand Down Expand Up @@ -360,8 +391,16 @@ if [[ $BAZELISK_VERSION == "GO" ]]; then
test_bazel_version_prefer_environment_to_bazeliskrc
echo

echo "# test_bazel_version_from_bazeliskrc"
test_bazel_version_from_bazeliskrc
echo "# test_bazel_version_from_workspace_bazeliskrc"
test_bazel_version_from_workspace_bazeliskrc
echo

echo "# test_bazel_version_from_user_home_bazeliskrc"
test_bazel_version_from_user_home_bazeliskrc
echo

echo "# test_bazel_version_prefer_workspace_bazeliskrc_to_user_home_bazeliskrc"
test_bazel_version_prefer_workspace_bazeliskrc_to_user_home_bazeliskrc
echo

echo "# test_bazel_version_prefer_bazeliskrc_to_bazelversion_file"
Expand Down
102 changes: 74 additions & 28 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
bazelReal = "BAZEL_REAL"
skipWrapperEnv = "BAZELISK_SKIP_WRAPPER"
wrapperPath = "./tools/bazel"
rcFileName = ".bazeliskrc"
)

var (
Expand Down Expand Up @@ -196,40 +197,85 @@ func GetEnvOrConfig(name string) string {
return val
}

// Parse .bazeliskrc in the workspace root, once, if it can be found.
fileConfigOnce.Do(func() {
workingDirectory, err := os.Getwd()
fileConfigOnce.Do(loadFileConfig)

return fileConfig[name]
}

// loadFileConfig locates available .bazeliskrc configuration files, parses them with a precedence order preference,
// and updates a global configuration map with their contents. This routine should be executed exactly once.
func loadFileConfig() {
var rcFilePaths []string

if userRC, err := locateUserConfigFile(); err == nil {
rcFilePaths = append(rcFilePaths, userRC)
}
if workspaceRC, err := locateWorkspaceConfigFile(); err == nil {
rcFilePaths = append(rcFilePaths, workspaceRC)
}

fileConfig = make(map[string]string)
for _, rcPath := range rcFilePaths {
config, err := parseFileConfig(rcPath)
if err != nil {
return
log.Fatal(err)
}
workspaceRoot := findWorkspaceRoot(workingDirectory)
if workspaceRoot == "" {
return

for key, value := range config {
fileConfig[key] = value
}
rcFilePath := filepath.Join(workspaceRoot, ".bazeliskrc")
contents, err := ioutil.ReadFile(rcFilePath)
if err != nil {
if os.IsNotExist(err) {
return
}
log.Fatal(err)
}
}

// locateWorkspaceConfigFile locates a .bazeliskrc file in the current workspace root.
func locateWorkspaceConfigFile() (string, error) {
workingDirectory, err := os.Getwd()
if err != nil {
return "", err
}
workspaceRoot := findWorkspaceRoot(workingDirectory)
if workspaceRoot == "" {
return "", err
}
return filepath.Join(workspaceRoot, rcFileName), nil
}

// locateUserConfigFile locates a .bazeliskrc file in the user's home directory.
func locateUserConfigFile() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, rcFileName), nil
}

// parseFileConfig parses a .bazeliskrc file as a map of key-value configuration values.
func parseFileConfig(rcFilePath string) (map[string]string, error) {
config := make(map[string]string)

contents, err := ioutil.ReadFile(rcFilePath)
if err != nil {
if os.IsNotExist(err) {
// Non-critical error.
return config, nil
}
fileConfig = make(map[string]string)
for _, line := range strings.Split(string(contents), "\n") {
if strings.HasPrefix(line, "#") {
// comments
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) < 2 {
continue
}
key := strings.TrimSpace(parts[0])
fileConfig[key] = strings.TrimSpace(parts[1])
return nil, err
}

for _, line := range strings.Split(string(contents), "\n") {
if strings.HasPrefix(line, "#") {
// comments
continue
}
})
parts := strings.SplitN(line, "=", 2)
if len(parts) < 2 {
continue
}
key := strings.TrimSpace(parts[0])
config[key] = strings.TrimSpace(parts[1])
}

return fileConfig[name]
return config, nil
}

// isValidWorkspace returns true iff the supplied path is the workspace root, defined by the presence of
Expand Down

0 comments on commit c908174

Please sign in to comment.