Skip to content

Commit 9a790fb

Browse files
Warn users when system Go installation bypasses goenv shims (#496)
* Initial plan * Add PATH collision warning for system Go installations Co-authored-by: ChronosMasterOfAllTime <28963807+ChronosMasterOfAllTime@users.noreply.github.com> * Add tests and documentation for PATH collision warning Co-authored-by: ChronosMasterOfAllTime <28963807+ChronosMasterOfAllTime@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ChronosMasterOfAllTime <28963807+ChronosMasterOfAllTime@users.noreply.github.com>
1 parent d555168 commit 9a790fb

5 files changed

Lines changed: 117 additions & 15 deletions

File tree

ENVIRONMENT_VARIABLES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ name | default | description
1919
`GOENV_AUTO_INSTALL_FLAGS` | | (Note: only works if `GOENV_AUTO_INSTALL` is set to 1) Appends flags to the auto install command (see `goenv install --help` for all available flags)
2020
`GOENV_RC_FILE` | `$HOME/.goenvrc` | If `GOENV_RC_FILE` is set, it will be modified accordingly.
2121
`GOENV_PATH_ORDER` | | If `GOENV_PATH_ORDER` is set to `front`, `$GOENV_ROOT/shims` will be prepended to the existing `PATH`.Set `GOENV_PATH_ORDER` to a configuration file named by `GOENV_RC_FILE`(e.g. `~/.goenvrc`), for example `GOENV_PATH_ORDER=front` in `~/.goenvrc`.
22+
`GOENV_DISABLE_PATH_WARNING` | `0` | Disables the warning about system Go taking precedence over goenv when shims are at the end of PATH. Set to `1` to disable the warning.
2223
`GOENV_AUTOMATICALLY_DETECT_VERSION` | `0` | If set to `1`, goenv will automatically update `GOROOT` and `GOPATH` when you change directories. This enables automatic version switching based on local `.go-version` files without needing to reload your shell configuration. **Note:** This feature adds a hook that runs on every directory change, which may have a slight performance impact.

HOW_IT_WORKS.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,28 @@ then `/bin`.
2222

2323
## Understanding Shims
2424

25-
goenv works by inserting a directory of _shims_ at the end of your
26-
`PATH`, so if you have `go` in `/usr/bin` it will be found first:
25+
By default, goenv works by inserting a directory of _shims_ at the end of your
26+
`PATH`. This means if you have `go` in `/usr/bin`, it will be found first:
2727

2828
/usr/local/bin:/usr/bin:/bin:~/.goenv/shims
2929

30+
**Important:** If you have a system Go installation, you need to configure goenv
31+
to put shims at the front of your PATH. Add `export GOENV_PATH_ORDER=front` to
32+
your `~/.goenvrc` file (or your shell profile). This ensures goenv's shims take
33+
precedence:
34+
35+
~/.goenv/shims:/usr/local/bin:/usr/bin:/bin
36+
3037
Through a process called _rehashing_, goenv maintains shims in that
3138
directory to match every `go` command across every installed version
3239
of Go.
3340

3441
Shims are lightweight executables that simply pass your command along
35-
to goenv. So with goenv installed, when you run `go` your
42+
to goenv. So with goenv properly configured, when you run `go` your
3643
operating system will do the following:
3744

3845
* Search your `PATH` for an executable file named `go`
39-
* Find the goenv shim named `go` at the beginning of your `PATH`
46+
* Find the goenv shim named `go` at the beginning of your `PATH` (if `GOENV_PATH_ORDER=front`)
4047
* Run the shim named `go`, which in turn passes the command along to
4148
goenv
4249

libexec/goenv-init

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,23 +86,42 @@ mkdir -p "${GOENV_ROOT}/"{shims,versions}
8686

8787
case "$shell" in
8888
fish)
89-
cat <<EOL
90-
set -gx GOENV_SHELL ${shell}
91-
set -gx GOENV_ROOT ${GOENV_ROOT}
92-
if test -z \$GOENV_RC_FILE
93-
set GOENV_RC_FILE \$HOME/.goenvrc
89+
cat <<'EOL'
90+
set -gx GOENV_SHELL fish
91+
EOL
92+
echo "set -gx GOENV_ROOT ${GOENV_ROOT}"
93+
cat <<'EOL'
94+
if test -z $GOENV_RC_FILE
95+
set GOENV_RC_FILE $HOME/.goenvrc
9496
end
95-
if test -e \$GOENV_RC_FILE
96-
source \$GOENV_RC_FILE
97+
if test -e $GOENV_RC_FILE
98+
source $GOENV_RC_FILE
9799
end
98-
if not contains \$GOENV_ROOT/shims \$PATH
99-
if test "\$GOENV_PATH_ORDER" = "front"
100-
set -gx PATH \$GOENV_ROOT/shims \$PATH
100+
if not contains $GOENV_ROOT/shims $PATH
101+
if test "$GOENV_PATH_ORDER" = "front"
102+
set -gx PATH $GOENV_ROOT/shims $PATH
101103
else
102-
set -gx PATH \$PATH \$GOENV_ROOT/shims
104+
set -gx PATH $PATH $GOENV_ROOT/shims
103105
end
104106
end
105107
EOL
108+
109+
# Add PATH collision warning unless explicitly disabled
110+
if [ "${GOENV_DISABLE_PATH_WARNING:-0}" != "1" ]; then
111+
cat <<'EOL'
112+
if test "$GOENV_PATH_ORDER" != "front"
113+
set -l system_go_path (command -v go 2>/dev/null)
114+
if test -n "$system_go_path"; and not string match -q "$GOENV_ROOT*" $system_go_path
115+
echo "goenv: WARNING: System 'go' found at $system_go_path" >&2
116+
echo "goenv: Since your shims are at the end of PATH, system 'go' will be used instead of goenv-managed versions." >&2
117+
echo "goenv: To fix this, add the following to your $GOENV_RC_FILE:" >&2
118+
echo "goenv: set -gx GOENV_PATH_ORDER front" >&2
119+
echo "goenv: Or run: echo 'set -gx GOENV_PATH_ORDER front' >> $GOENV_RC_FILE" >&2
120+
echo "" >&2
121+
end
122+
end
123+
EOL
124+
fi
106125
;;
107126
*)
108127
cat <<EOL
@@ -122,6 +141,29 @@ if [ "\${PATH#*\$GOENV_ROOT/shims}" = "\${PATH}" ]; then
122141
fi
123142
fi
124143
EOL
144+
145+
# Add PATH collision warning unless explicitly disabled
146+
if [ "${GOENV_DISABLE_PATH_WARNING:-0}" != "1" ]; then
147+
cat <<'EOL'
148+
if [ "${GOENV_PATH_ORDER:-}" != "front" ]; then
149+
system_go_path="$(command -v go 2>/dev/null || true)"
150+
if [ -n "$system_go_path" ]; then
151+
case "$system_go_path" in
152+
${GOENV_ROOT}/*)
153+
;;
154+
*)
155+
echo "goenv: WARNING: System 'go' found at $system_go_path" >&2
156+
echo "goenv: Since your shims are at the end of PATH, system 'go' will be used instead of goenv-managed versions." >&2
157+
echo "goenv: To fix this, add the following to your ${GOENV_RC_FILE}:" >&2
158+
echo "goenv: export GOENV_PATH_ORDER=front" >&2
159+
echo "goenv: Or run: echo 'export GOENV_PATH_ORDER=front' >> ${GOENV_RC_FILE}" >&2
160+
echo "" >&2
161+
;;
162+
esac
163+
fi
164+
fi
165+
EOL
166+
fi
125167
;;
126168
esac
127169

test/goenv-init.bats

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,52 @@ OUT
377377
assert [ -n "$(echo "$output" | grep "__goenv_auto_detect_version")" ]
378378
assert [ -n "$(echo "$output" | grep "on-variable PWD")" ]
379379
}
380+
381+
@test "includes PATH collision warning when system go exists and GOENV_PATH_ORDER is not front for bash" {
382+
# Create a fake go binary in PATH
383+
create_executable "${GOENV_TEST_DIR}/bin" "go"
384+
385+
unset GOENV_DISABLE_PATH_WARNING
386+
run goenv-init - bash
387+
388+
assert_success
389+
assert_line 'if [ "${GOENV_PATH_ORDER:-}" != "front" ]; then'
390+
assert [ -n "$(echo "$output" | grep 'WARNING: System.*go.*found')" ]
391+
}
392+
393+
@test "does not include PATH collision warning when GOENV_DISABLE_PATH_WARNING is set to 1" {
394+
create_executable "${GOENV_TEST_DIR}/bin" "go"
395+
396+
GOENV_DISABLE_PATH_WARNING=1 run goenv-init - bash
397+
398+
assert_success
399+
refute_line ' system_go_path="$(command -v go 2>/dev/null || true)"'
400+
}
401+
402+
@test "warning executes and shows message when system go exists and GOENV_PATH_ORDER not set" {
403+
# Create a fake go binary
404+
create_executable "${GOENV_TEST_DIR}/bin" "go"
405+
406+
# Don't disable the warning for this test
407+
unset GOENV_DISABLE_PATH_WARNING
408+
unset GOENV_PATH_ORDER
409+
410+
# Eval the init output and capture stderr
411+
run bash -c 'eval "$(GOENV_DISABLE_PATH_WARNING=0 goenv-init - bash 2>&1)" 2>&1'
412+
413+
assert_success
414+
assert [ -n "$(echo "$output" | grep 'WARNING: System.*go.*found')" ]
415+
assert [ -n "$(echo "$output" | grep 'GOENV_PATH_ORDER=front')" ]
416+
}
417+
418+
@test "warning does not execute when GOENV_PATH_ORDER is set to front" {
419+
create_executable "${GOENV_TEST_DIR}/bin" "go"
420+
421+
unset GOENV_DISABLE_PATH_WARNING
422+
export GOENV_PATH_ORDER=front
423+
424+
run bash -c 'eval "$(GOENV_DISABLE_PATH_WARNING=0 goenv-init - bash 2>&1)" 2>&1'
425+
426+
assert_success
427+
assert [ -z "$(echo "$output" | grep 'WARNING')" ]
428+
}

test/test_helper.bash

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ load ./test_assert_helpers
33
unset GOENV_VERSION
44
unset GOENV_DIR
55

6+
# Disable PATH warning in tests to avoid changing expected output
7+
export GOENV_DISABLE_PATH_WARNING=1
8+
69
# guard against executing this block twice due to bats internals
710
if [ -z "$GOENV_TEST_DIR" ]; then
811
GOENV_TEST_DIR="${BATS_TMPDIR}/goenv"

0 commit comments

Comments
 (0)