Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ENVIRONMENT_VARIABLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ name | default | description
`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)
`GOENV_RC_FILE` | `$HOME/.goenvrc` | If `GOENV_RC_FILE` is set, it will be modified accordingly.
`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`.
`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.
`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.
15 changes: 11 additions & 4 deletions HOW_IT_WORKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,28 @@ then `/bin`.

## Understanding Shims

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

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

**Important:** If you have a system Go installation, you need to configure goenv
to put shims at the front of your PATH. Add `export GOENV_PATH_ORDER=front` to
your `~/.goenvrc` file (or your shell profile). This ensures goenv's shims take
precedence:

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

Through a process called _rehashing_, goenv maintains shims in that
directory to match every `go` command across every installed version
of Go.

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

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

Expand Down
64 changes: 53 additions & 11 deletions libexec/goenv-init
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,42 @@ mkdir -p "${GOENV_ROOT}/"{shims,versions}

case "$shell" in
fish)
cat <<EOL
set -gx GOENV_SHELL ${shell}
set -gx GOENV_ROOT ${GOENV_ROOT}
if test -z \$GOENV_RC_FILE
set GOENV_RC_FILE \$HOME/.goenvrc
cat <<'EOL'
set -gx GOENV_SHELL fish
EOL
echo "set -gx GOENV_ROOT ${GOENV_ROOT}"
cat <<'EOL'
if test -z $GOENV_RC_FILE
set GOENV_RC_FILE $HOME/.goenvrc
end
if test -e \$GOENV_RC_FILE
source \$GOENV_RC_FILE
if test -e $GOENV_RC_FILE
source $GOENV_RC_FILE
end
if not contains \$GOENV_ROOT/shims \$PATH
if test "\$GOENV_PATH_ORDER" = "front"
set -gx PATH \$GOENV_ROOT/shims \$PATH
if not contains $GOENV_ROOT/shims $PATH
if test "$GOENV_PATH_ORDER" = "front"
set -gx PATH $GOENV_ROOT/shims $PATH
else
set -gx PATH \$PATH \$GOENV_ROOT/shims
set -gx PATH $PATH $GOENV_ROOT/shims
end
end
EOL

# Add PATH collision warning unless explicitly disabled
if [ "${GOENV_DISABLE_PATH_WARNING:-0}" != "1" ]; then
cat <<'EOL'
if test "$GOENV_PATH_ORDER" != "front"
set -l system_go_path (command -v go 2>/dev/null)
if test -n "$system_go_path"; and not string match -q "$GOENV_ROOT*" $system_go_path
echo "goenv: WARNING: System 'go' found at $system_go_path" >&2
echo "goenv: Since your shims are at the end of PATH, system 'go' will be used instead of goenv-managed versions." >&2
echo "goenv: To fix this, add the following to your $GOENV_RC_FILE:" >&2
echo "goenv: set -gx GOENV_PATH_ORDER front" >&2
echo "goenv: Or run: echo 'set -gx GOENV_PATH_ORDER front' >> $GOENV_RC_FILE" >&2
echo "" >&2
end
end
EOL
fi
;;
*)
cat <<EOL
Expand All @@ -122,6 +141,29 @@ if [ "\${PATH#*\$GOENV_ROOT/shims}" = "\${PATH}" ]; then
fi
fi
EOL

# Add PATH collision warning unless explicitly disabled
if [ "${GOENV_DISABLE_PATH_WARNING:-0}" != "1" ]; then
cat <<'EOL'
if [ "${GOENV_PATH_ORDER:-}" != "front" ]; then
system_go_path="$(command -v go 2>/dev/null || true)"
if [ -n "$system_go_path" ]; then
case "$system_go_path" in
${GOENV_ROOT}/*)
;;
*)
echo "goenv: WARNING: System 'go' found at $system_go_path" >&2
echo "goenv: Since your shims are at the end of PATH, system 'go' will be used instead of goenv-managed versions." >&2
echo "goenv: To fix this, add the following to your ${GOENV_RC_FILE}:" >&2
echo "goenv: export GOENV_PATH_ORDER=front" >&2
echo "goenv: Or run: echo 'export GOENV_PATH_ORDER=front' >> ${GOENV_RC_FILE}" >&2
echo "" >&2
;;
esac
fi
fi
EOL
fi
;;
esac

Expand Down
49 changes: 49 additions & 0 deletions test/goenv-init.bats
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,52 @@ OUT
assert [ -n "$(echo "$output" | grep "__goenv_auto_detect_version")" ]
assert [ -n "$(echo "$output" | grep "on-variable PWD")" ]
}

@test "includes PATH collision warning when system go exists and GOENV_PATH_ORDER is not front for bash" {
# Create a fake go binary in PATH
create_executable "${GOENV_TEST_DIR}/bin" "go"

unset GOENV_DISABLE_PATH_WARNING
run goenv-init - bash

assert_success
assert_line 'if [ "${GOENV_PATH_ORDER:-}" != "front" ]; then'
assert [ -n "$(echo "$output" | grep 'WARNING: System.*go.*found')" ]
}

@test "does not include PATH collision warning when GOENV_DISABLE_PATH_WARNING is set to 1" {
create_executable "${GOENV_TEST_DIR}/bin" "go"

GOENV_DISABLE_PATH_WARNING=1 run goenv-init - bash

assert_success
refute_line ' system_go_path="$(command -v go 2>/dev/null || true)"'
}

@test "warning executes and shows message when system go exists and GOENV_PATH_ORDER not set" {
# Create a fake go binary
create_executable "${GOENV_TEST_DIR}/bin" "go"

# Don't disable the warning for this test
unset GOENV_DISABLE_PATH_WARNING
unset GOENV_PATH_ORDER

# Eval the init output and capture stderr
run bash -c 'eval "$(GOENV_DISABLE_PATH_WARNING=0 goenv-init - bash 2>&1)" 2>&1'

assert_success
assert [ -n "$(echo "$output" | grep 'WARNING: System.*go.*found')" ]
assert [ -n "$(echo "$output" | grep 'GOENV_PATH_ORDER=front')" ]
}

@test "warning does not execute when GOENV_PATH_ORDER is set to front" {
create_executable "${GOENV_TEST_DIR}/bin" "go"

unset GOENV_DISABLE_PATH_WARNING
export GOENV_PATH_ORDER=front

run bash -c 'eval "$(GOENV_DISABLE_PATH_WARNING=0 goenv-init - bash 2>&1)" 2>&1'

assert_success
assert [ -z "$(echo "$output" | grep 'WARNING')" ]
}
3 changes: 3 additions & 0 deletions test/test_helper.bash
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ load ./test_assert_helpers
unset GOENV_VERSION
unset GOENV_DIR

# Disable PATH warning in tests to avoid changing expected output
export GOENV_DISABLE_PATH_WARNING=1

# guard against executing this block twice due to bats internals
if [ -z "$GOENV_TEST_DIR" ]; then
GOENV_TEST_DIR="${BATS_TMPDIR}/goenv"
Expand Down
Loading