From 9116e8453dacdd32accfb092e0f21c143fec86f9 Mon Sep 17 00:00:00 2001 From: Jonathan Mast Date: Sat, 9 Mar 2019 12:30:31 -0500 Subject: [PATCH] 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 --- asdf.fish | 15 +++++++++++ asdf.sh | 19 ++++++++++++++ bin/asdf | 8 ++++++ completions/asdf.bash | 4 +-- completions/asdf.fish | 5 ++++ lib/commands/version_commands.sh | 28 ++++++++++++++++++++ test/version_commands.bats | 45 ++++++++++++++++++++++++++++++++ 7 files changed, 122 insertions(+), 2 deletions(-) diff --git a/asdf.fish b/asdf.fish index afe5c0e4..0f9b85f4 100644 --- a/asdf.fish +++ b/asdf.fish @@ -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 diff --git a/asdf.sh b/asdf.sh index 5f482343..a2d4f256 100644 --- a/asdf.sh +++ b/asdf.sh @@ -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 diff --git a/bin/asdf b/bin/asdf index b3e41177..850a5f5f 100755 --- a/bin/asdf +++ b/bin/asdf @@ -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[@]}";; diff --git a/completions/asdf.bash b/completions/asdf.bash index 0d57b719..5c6511e3 100644 --- a/completions/asdf.bash +++ b/completions/asdf.bash @@ -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")) ;; diff --git a/completions/asdf.fish b/completions/asdf.fish index 4f037861..d6c0d887 100644 --- a/completions/asdf.fish +++ b/completions/asdf.fish @@ -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" diff --git a/lib/commands/version_commands.sh b/lib/commands/version_commands.sh index 7ce888ff..c4690633 100644 --- a/lib/commands/version_commands.sh +++ b/lib/commands/version_commands.sh @@ -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 " >&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 +} diff --git a/test/version_commands.bats b/test/version_commands.bats index 46eb78d1..2c083a4f 100644 --- a/test/version_commands.bats +++ b/test/version_commands.bats @@ -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\"" ] +}