Add "shell" subcommand for setting versions in shell session

Add a "shell" command similar to the existing "global" and "local"
commands, which sets the version in an environment variable instead of
writing it to a file. This was inspired by the similar functionality in
rbenv.

It works by adding a wrapper function for the asdf command. It forwards
to a "sh-shell" command that returns the exports as shell code which is
then evaled by the wrapper. This is a little gross, but we need to run
the code in the shell context in order to set variables.

Resolves #378
This commit is contained in:
Jonathan Mast 2019-03-09 12:30:31 -05:00
parent 9e30218766
commit 9116e8453d
No known key found for this signature in database
GPG Key ID: 61BD854CBFF15EE6
7 changed files with 122 additions and 2 deletions

View File

@ -13,3 +13,18 @@ for x in $asdf_bin_dirs
set -gx fish_user_paths $fish_user_paths $x
end
end
# Add function wrapper so we can export variables
function asdf
set command $argv[1]
set -e argv[1]
switch "$command"
case "shell"
# eval commands that need to export variables
source (env ASDF_SHELL=fish asdf "sh-$command" $argv | psub)
case '*'
# forward other commands to asdf script
command asdf "$command" $argv
end
end

19
asdf.sh
View File

@ -23,6 +23,25 @@ ASDF_USER_SHIMS="${ASDF_DATA_DIR:-$HOME/.asdf}/shims"
PATH="${ASDF_BIN}:$PATH"
PATH="${ASDF_USER_SHIMS}:$PATH"
# Add function wrapper so we can export variables
asdf() {
local command
command="$1"
if [ "$#" -gt 0 ]; then
shift
fi
case "$command" in
"shell")
# eval commands that need to export variables
eval "$(asdf "sh-$command" "$@")";;
*)
# forward other commands to asdf script
command asdf "$command" "$@";;
esac
}
if [ -n "$ZSH_VERSION" ]; then
autoload -U bashcompinit
bashcompinit

View File

@ -46,6 +46,14 @@ case "$1" in
load_cmd "current" "plugin-list"
current_command "${cmd_args[@]}";;
"sh-shell")
load_cmd "version_commands"
shell_command "${cmd_args[@]}";;
"shell")
echo "Shell integration is not enabled. Please ensure you source asdf in your shell setup."
exit 1;;
"local")
load_cmd "version_commands"
local_command "${cmd_args[@]}";;

View File

@ -46,7 +46,7 @@ _asdf () {
# shellcheck disable=SC2207
COMPREPLY=($(compgen -W "--head" -- "$cur"))
;;
uninstall|where|reshim|local|global)
uninstall|where|reshim|local|global|shell)
if [[ "$plugins" == *"$prev"* ]] ; then
local versions
versions=$(asdf list "$prev" 2> /dev/null)
@ -58,7 +58,7 @@ _asdf () {
fi
;;
*)
local cmds='current global help install list list-all local plugin-add plugin-list plugin-list-all plugin-remove plugin-update reshim uninstall update where which '
local cmds='current global help install list list-all local plugin-add plugin-list plugin-list-all plugin-remove plugin-update reshim shell uninstall update where which '
# shellcheck disable=SC2207
COMPREPLY=($(compgen -W "$cmds" -- "$cur"))
;;

View File

@ -105,6 +105,11 @@ complete -f -c asdf -n '__fish_asdf_needs_command' -a global -d "Set global vers
complete -f -c asdf -n '__fish_asdf_using_command global; and __fish_asdf_arg_number 2' -a '(__fish_asdf_plugin_list)'
complete -f -c asdf -n '__fish_asdf_using_command global; and test (count (commandline -opc)) -gt 2' -a '(__fish_asdf_list_versions (__fish_asdf_arg_at 3)) system'
# shell completion
complete -f -c asdf -n '__fish_asdf_needs_command' -a shell -d "Set version for a plugin in current shell session"
complete -f -c asdf -n '__fish_asdf_using_command shell; and __fish_asdf_arg_number 2' -a '(__fish_asdf_plugin_list)'
complete -f -c asdf -n '__fish_asdf_using_command shell; and test (count (commandline -opc)) -gt 2' -a '(__fish_asdf_list_versions (__fish_asdf_arg_at 3)) system'
# misc
complete -f -c asdf -n '__fish_asdf_needs_command' -l "help" -d "Displays help"
complete -f -c asdf -n '__fish_asdf_needs_command' -l "version" -d "Displays asdf version"

View File

@ -77,3 +77,31 @@ global_command() {
# shellcheck disable=2068
version_command "global" $@
}
# Output from this command must be executable shell code
shell_command() {
if [ "$#" -lt "2" ]; then
echo "Usage: asdf shell <name> <version>" >&2
echo 'false'
exit 1
fi
local plugin=$1
local version=$2
if ! (check_if_version_exists "$plugin" "$version"); then
echo 'false'
exit 1
fi
local upcase_name
upcase_name=$(echo "$plugin" | tr '[:lower:]-' '[:upper:]_')
local version_env_var="ASDF_${upcase_name}_VERSION"
case $ASDF_SHELL in
fish )
echo "set -gx $version_env_var \"$version\"";;
* )
echo "export $version_env_var=\"$version\"";;
esac
}

View File

@ -230,3 +230,48 @@ teardown() {
[ -L $HOME/.tool-versions ]
[ "$(cat other-dir/.tool-versions)" = "dummy 1.1.0" ]
}
@test "shell wrapper function should export ENV var" {
source $(dirname "$BATS_TEST_DIRNAME")/asdf.sh
asdf shell "dummy" "1.1.0"
[ $(echo $ASDF_DUMMY_VERSION) = "1.1.0" ]
unset ASDF_DUMMY_VERSION
}
@test "shell wrapper function should return an error for missing plugins" {
source $(dirname "$BATS_TEST_DIRNAME")/asdf.sh
run asdf shell "nonexistent" "1.0.0"
[ "$status" -eq 1 ]
[ "$output" = "No such plugin: nonexistent" ]
}
@test "shell should emit an error when wrapper function is not loaded" {
run asdf shell "dummy" "1.1.0"
echo $output
[ "$status" -eq 1 ]
[ "$output" = "Shell integration is not enabled. Please ensure you source asdf in your shell setup." ]
}
@test "sh-shell should emit an error when plugin does not exist" {
run asdf sh-shell "nonexistent" "1.0.0"
[ "$status" -eq 1 ]
[ "$output" = $'No such plugin: nonexistent\nfalse' ]
}
@test "sh-shell should emit an error when version does not exist" {
run asdf sh-shell "dummy" "nonexistent"
[ "$status" -eq 1 ]
[ "$output" = $'version nonexistent is not installed for dummy\nfalse' ]
}
@test "sh-shell should export version if it exists" {
run asdf sh-shell "dummy" "1.1.0"
[ "$status" -eq 0 ]
[ "$output" = "export ASDF_DUMMY_VERSION=\"1.1.0\"" ]
}
@test "sh-shell should use set when shell is fish" {
ASDF_SHELL=fish run asdf sh-shell "dummy" "1.1.0"
[ "$status" -eq 0 ]
[ "$output" = "set -gx ASDF_DUMMY_VERSION \"1.1.0\"" ]
}