Ensure goenv and go play together well

This PR seeks to address several issues surrounding the go and goenv plugins.
The nature of goenv allows for a situation where the initial shell does not
point to a working go binary, and instead at the included shim script. The
result is that one must run reload after moving to a project directory with a
version file, however in doing so, PATH is updated, requiring they exit the
shell or risk lookup collisions and unexpected behavior.

This is solved by using preexec to check the version before changing
directories and restarting the shell if the version has changed. The exec
pattern is copied from _bash-it-restart, but is edited to support this specific
use case.

Additionally, tests have been uploaded and these are now being linted.
pull/1824/head
cornfeedhobo 2021-02-02 02:38:42 -06:00
parent 293d86771a
commit e690f21e4e
No known key found for this signature in database
GPG Key ID: 724357093F994B26
4 changed files with 69 additions and 37 deletions

View File

@ -24,12 +24,6 @@ hooks
.gitattributes .gitattributes
lint_clean_files.sh lint_clean_files.sh
# plugins
#
plugins/available/history.plugin.bash
plugins/available/history-search.plugin.bash
plugins/available/history-substring-search.plugin.bash
# themes # themes
# #
themes/agnoster themes/agnoster
@ -54,6 +48,11 @@ themes/modern
plugins/available/basher.plugin.bash plugins/available/basher.plugin.bash
plugins/available/cmd-returned-notify.plugin.bash plugins/available/cmd-returned-notify.plugin.bash
plugins/available/docker-machine.plugin.bash plugins/available/docker-machine.plugin.bash
plugins/available/go.plugin.bash
plugins/available/goenv.plugin.bash
plugins/available/history.plugin.bash
plugins/available/history-search.plugin.bash
plugins/available/history-substring-search.plugin.bash
plugins/available/xterm.plugin.bash plugins/available/xterm.plugin.bash
# completions # completions

41
plugins/available/go.plugin.bash 100755 → 100644
View File

@ -1,19 +1,36 @@
#!/usr/bin/env bash # shellcheck shell=bash
cite about-plugin cite about-plugin
about-plugin 'go environment variables & path configuration' about-plugin 'go environment variables & path configuration'
command -v go &>/dev/null || return # Load after basher and goenv
# BASH_IT_LOAD_PRIORITY: 270
function _go_pathmunge_wrap() { # Test `go version` because goenv creates shim scripts that will be found in PATH
IFS=':' local -a 'a=($1)' # but do not always resolve to a working install.
local i=${#a[@]} { _command_exists go && go version &> /dev/null; } || return 0
while [ $i -gt 0 ] ; do
i=$(( i - 1 ))
pathmunge "${a[i]}/bin"
done
}
export GOROOT="${GOROOT:-$(go env GOROOT)}" export GOROOT="${GOROOT:-$(go env GOROOT)}"
export GOPATH="${GOPATH:-$(go env GOPATH)}" export GOPATH="${GOPATH:-$(go env GOPATH)}"
_go_pathmunge_wrap "${GOPATH}:${GOROOT}"
# $GOPATH/bin is the default location for binaries. Because GOPATH accepts a list of paths and each
# might be managed differently, we add each path's /bin folder to PATH using pathmunge,
# while preserving ordering.
# e.g. GOPATH=foo:bar -> PATH=foo/bin:bar/bin
_bash-it-gopath-pathmunge() {
_about 'Ensures paths in GOPATH are added to PATH using pathmunge, with /bin appended'
_group 'go'
if [[ -z $GOPATH ]]; then
echo 'GOPATH empty' >&2
return 1
fi
local paths i
IFS=: read -r -a paths <<< "$GOPATH"
i=${#paths[@]}
while [[ $i -gt 0 ]]; do
i=$((i - 1))
if [[ -n "${paths[i]}" ]]; then
pathmunge "${paths[i]}/bin"
fi
done
}
_bash-it-gopath-pathmunge

View File

@ -1,20 +1,42 @@
# shellcheck shell=bash
cite about-plugin cite about-plugin
about-plugin 'load goenv, if you are using it' about-plugin 'load goenv, if you are using it'
# https://github.com/syndbg/goenv
# Load after basher
# BASH_IT_LOAD_PRIORITY: 260
# Don't modify the environment if we can't find the tool: # Don't modify the environment if we can't find the tool:
# - Check if in $PATH already # - Check if in $PATH already
# - Check if installed manually to $GOENV_ROOT # - Check if installed manually to $GOENV_ROOT
# - Check if installed manually to $HOME # - Check if installed manually to $HOME
_command_exists goenv || _command_exists goenv \
[[ -n "$GOENV_ROOT" && -x "$GOENV_ROOT/bin/goenv" ]] || || [[ -n "$GOENV_ROOT" && -x "$GOENV_ROOT/bin/goenv" ]] \
[[ -x "$HOME/.goenv/bin/goenv" ]] || || [[ -x "$HOME/.goenv/bin/goenv" ]] \
return || return 0
# Set GOENV_ROOT, if not already set # Set GOENV_ROOT, if not already set
export GOENV_ROOT="${GOENV_ROOT:-$HOME/.goenv}" export GOENV_ROOT="${GOENV_ROOT:-$HOME/.goenv}"
# Add GOENV_ROOT/bin to PATH, if that's where it's installed # Add GOENV_ROOT/bin to PATH, if that's where it's installed
! _command_exists goenv && [[ -x "$GOENV_ROOT/bin/goenv" ]] && pathmunge "$GOENV_ROOT/bin" if ! _command_exists goenv && [[ -x "$GOENV_ROOT/bin/goenv" ]]; then
pathmunge "$GOENV_ROOT/bin"
fi
# Initialize goenv # Initialize goenv
eval "$(goenv init - bash)" eval "$(goenv init - bash)"
# If moving to a directory with a goenv version set, reload the shell
# to ensure the shell environment matches expectations.
_bash-it-goenv-preexec() {
export GOENV_OLD_VERSION="$(goenv version-name)"
}
_bash-it-goenv-precmd() {
if [[ -n $GOENV_OLD_VERSION ]] && [[ "$GOENV_OLD_VERSION" != "$(goenv version-name)" ]]; then
exec env -u PATH -u GOROOT -u GOPATH -u GOENV_OLD_VERSION "${0/-/}" --login
fi
unset GOENV_OLD_VERSION
}
preexec_functions+=(_bash-it-goenv-preexec)
precmd_functions+=(_bash-it-goenv-precmd)

View File

@ -4,57 +4,51 @@ load ../test_helper
load ../../lib/helpers load ../../lib/helpers
load ../../lib/composure load ../../lib/composure
@test 'ensure _go_pathmunge_wrap is defined' { @test 'ensure _bash-it-gopath-pathmunge is defined' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
run type -t _go_pathmunge_wrap run type -t _bash-it-gopath-pathmunge
assert_line 'function' assert_line 'function'
} }
@test 'plugins go: single entry in GOPATH' { @test 'plugins go: single entry in GOPATH' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
export GOPATH="/foo" export GOPATH="/foo"
export GOROOT="/baz"
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
assert_equal "$(cut -d':' -f1,2 <<<$PATH)" "/foo/bin:/baz/bin" assert_equal "$(cut -d':' -f1 <<<$PATH)" "/foo/bin"
} }
@test 'plugins go: single entry in GOPATH, with space' { @test 'plugins go: single entry in GOPATH, with space' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
export GOPATH="/foo bar" export GOPATH="/foo bar"
export GOROOT="/baz"
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
assert_equal "$(cut -d':' -f1,2 <<<$PATH)" "/foo bar/bin:/baz/bin" assert_equal "$(cut -d':' -f1 <<<$PATH)" "/foo bar/bin"
} }
@test 'plugins go: single entry in GOPATH, with escaped space' { @test 'plugins go: single entry in GOPATH, with escaped space' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
export GOPATH="/foo\ bar" export GOPATH="/foo\ bar"
export GOROOT="/baz"
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
assert_equal "$(cut -d':' -f1,2 <<<$PATH)" "/foo\ bar/bin:/baz/bin" assert_equal "$(cut -d':' -f1 <<<$PATH)" "/foo\ bar/bin"
} }
@test 'plugins go: multiple entries in GOPATH' { @test 'plugins go: multiple entries in GOPATH' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
export GOPATH="/foo:/bar" export GOPATH="/foo:/bar"
export GOROOT="/baz"
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
assert_equal "$(cut -d':' -f1,2,3 <<<$PATH)" "/foo/bin:/bar/bin:/baz/bin" assert_equal "$(cut -d':' -f1,2 <<<$PATH)" "/foo/bin:/bar/bin"
} }
@test 'plugins go: multiple entries in GOPATH, with space' { @test 'plugins go: multiple entries in GOPATH, with space' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
export GOPATH="/foo:/foo bar" export GOPATH="/foo:/foo bar"
export GOROOT="/baz"
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
assert_equal "$(cut -d':' -f1,2,3 <<<$PATH)" "/foo/bin:/foo bar/bin:/baz/bin" assert_equal "$(cut -d':' -f1,2 <<<$PATH)" "/foo/bin:/foo bar/bin"
} }
@test 'plugins go: multiple entries in GOPATH, with escaped space' { @test 'plugins go: multiple entries in GOPATH, with escaped space' {
{ [[ $CI ]] || _command_exists go; } || skip 'golang not found' { [[ $CI ]] || _command_exists go; } || skip 'golang not found'
export GOPATH="/foo:/foo\ bar" export GOPATH="/foo:/foo\ bar"
export GOROOT="/baz"
load ../../plugins/available/go.plugin load ../../plugins/available/go.plugin
assert_equal "$(cut -d':' -f1,2,3 <<<$PATH)" "/foo/bin:/foo\ bar/bin:/baz/bin" assert_equal "$(cut -d':' -f1,2 <<<$PATH)" "/foo/bin:/foo\ bar/bin"
} }