Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: insert error handling in list-all & download plugin scripts #881

Merged
merged 10 commits into from May 19, 2021
39 changes: 21 additions & 18 deletions lib/commands/command-install.bash
Expand Up @@ -173,24 +173,27 @@ install_tool_version() {
)
fi

(
# shellcheck disable=SC2031
export ASDF_INSTALL_TYPE=$install_type
# shellcheck disable=SC2031
export ASDF_INSTALL_VERSION=$version
# shellcheck disable=SC2031
export ASDF_INSTALL_PATH=$install_path
# shellcheck disable=SC2031
export ASDF_DOWNLOAD_PATH=$download_path
# shellcheck disable=SC2031
export ASDF_CONCURRENCY=$concurrency
mkdir "$install_path"
asdf_run_hook "pre_asdf_install_${plugin_name}" "$full_version"
bash "${plugin_path}"/bin/install
)

local exit_code=$?
if [ $exit_code -eq 0 ]; then
local download_exit_code=$?
if [ $download_exit_code -eq 0 ]; then
(
# shellcheck disable=SC2031
export ASDF_INSTALL_TYPE=$install_type
# shellcheck disable=SC2031
export ASDF_INSTALL_VERSION=$version
# shellcheck disable=SC2031
export ASDF_INSTALL_PATH=$install_path
# shellcheck disable=SC2031
export ASDF_DOWNLOAD_PATH=$download_path
# shellcheck disable=SC2031
export ASDF_CONCURRENCY=$concurrency
mkdir "$install_path"
asdf_run_hook "pre_asdf_install_${plugin_name}" "$full_version"
bash "${plugin_path}"/bin/install
)
fi

local install_exit_code=$?
if [ $install_exit_code -eq 0 ] && [ $download_exit_code -eq 0 ]; then
# Remove download directory if --keep-download flag or always_keep_download config setting are not set
always_keep_download=$(get_asdf_config_value "always_keep_download")
if [ ! "$keep_download" = "true" ] && [ ! "$always_keep_download" = "yes" ] && [ -d "$download_path" ]; then
Expand Down
33 changes: 29 additions & 4 deletions lib/commands/command-list-all.bash
Expand Up @@ -4,23 +4,48 @@ list_all_command() {
local plugin_name=$1
local query=$2
local plugin_path
local std_out
local std_err
plugin_path=$(get_plugin_path "$plugin_name")
check_if_plugin_exists "$plugin_name"

local versions
versions=$(bash "${plugin_path}/bin/list-all")
# Capture return code to allow error handling
return_code=0 && split_outputs std_out std_err "bash ${plugin_path}/bin/list-all" || return_code=$?

if [[ $return_code -ne 0 ]]; then
# Printing all output to allow plugin to handle error formatting
printf "Plugin %s's list-all callback script failed with output:\\n" "${plugin_name}" >&2
printf "%s\\n" "${std_err}" >&2
printf "%s\\n" "${std_out}" >&2
exit 1
fi

if [[ $query ]]; then
versions=$(tr ' ' '\n' <<<"$versions" |
std_out=$(tr ' ' '\n' <<<"$std_out" |
grep -E "^\\s*$query" |
tr '\n' ' ')
fi

IFS=' ' read -r -a versions_list <<<"$versions"
IFS=' ' read -r -a versions_list <<<"$std_out"

for version in "${versions_list[@]}"; do
printf "%s\\n" "${version}"
done
}

# This function splits stdout from std error, whilst preserving the return core
function split_outputs() {
{
IFS=$'\n' read -r -d '' "${1}"
IFS=$'\n' read -r -d '' "${2}"
(
IFS=$'\n' read -r -d '' _ERRNO_
return "${_ERRNO_}"
)
} < <((printf '\0%s\0%d\0' "$( ( ( ({
${3}
printf "%s\n" ${?} 1>&3-
} | tr -d '\0' 1>&4-) 4>&2- 2>&1- | tr -d '\0' 1>&4-) 3>&1- | exit "$(cat)") 4>&1-)" "${?}" 1>&2) 2>&1)
}

list_all_command "$@"
4 changes: 4 additions & 0 deletions test/fixtures/dummy_broken_plugin/bin/download
@@ -0,0 +1,4 @@
#!/usr/bin/env bash

echo "Download failed!"
exit 1
3 changes: 3 additions & 0 deletions test/fixtures/dummy_broken_plugin/bin/install
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

echo "Unused script"
5 changes: 5 additions & 0 deletions test/fixtures/dummy_broken_plugin/bin/list-all
@@ -0,0 +1,5 @@
#!/usr/bin/env bash

echo "Attempting to list versions"
echo "List-all failed!" >&2
exit 1
2 changes: 2 additions & 0 deletions test/fixtures/dummy_plugin/bin/list-all
Expand Up @@ -2,3 +2,5 @@

versions_list=(1.0.0 1.1.0 2.0.0)
echo "${versions_list[@]}"
# Sending message to STD error to ensure that it is ignored
echo "ignore this error" >&2
10 changes: 10 additions & 0 deletions test/install_command.bats
Expand Up @@ -6,6 +6,7 @@ setup() {
setup_asdf_dir
install_dummy_legacy_plugin
install_dummy_plugin
install_dummy_broken_plugin

PROJECT_DIR=$HOME/project
mkdir $PROJECT_DIR
Expand Down Expand Up @@ -258,3 +259,12 @@ EOM
[ -d $ASDF_DIR/downloads/dummy/1.1.0 ]
[ $(cat $ASDF_DIR/installs/dummy/1.1.0/version) = "1.1.0" ]
}

@test "install_command fails when download script exits with non-zero code" {
run asdf install dummy-broken 1.0.0
echo $output
[ "$status" -eq 1 ]
[ ! -d $ASDF_DIR/downloads/dummy-broken/1.1.0 ]
[ ! -d $ASDF_DIR/installs/dummy-broken/1.1.0 ]
[ "$output" == "Download failed!" ]
}
29 changes: 27 additions & 2 deletions test/list_command.bats
Expand Up @@ -5,6 +5,7 @@ load test_helpers
setup() {
setup_asdf_dir
install_dummy_plugin
install_dummy_broken_plugin
}

teardown() {
Expand All @@ -15,7 +16,8 @@ teardown() {
run asdf install dummy 1.0.0
run asdf install dummy 1.1.0
run asdf list
[ "$(echo -e "dummy\n 1.0.0\n 1.1.0")" == "$output" ]
[[ "$output" == "$(echo -e "dummy\n 1.0.0\n 1.1.0")"* ]]
[[ "$output" == *"$(echo -e "dummy-broken\n No versions installed")" ]]
[ "$status" -eq 0 ]
}

Expand All @@ -26,7 +28,10 @@ teardown() {
run asdf install dummy 1.0.0
run asdf install tummy 2.0.0
run asdf list
[ "$(echo -e "dummy\n 1.0.0\nmummy\n No versions installed\ntummy\n 2.0.0")" == "$output" ]
[[ "$output" == "$(echo -e "dummy\n 1.0.0")"* ]]
[[ "$output" == *"$(echo -e "dummy-broken\n No versions installed")"* ]]
[[ "$output" == *"$(echo -e "mummy\n No versions installed")"* ]]
[[ "$output" == *"$(echo -e "tummy\n 2.0.0")" ]]
laidbackware marked this conversation as resolved.
Show resolved Hide resolved
[ "$status" -eq 0 ]
}

Expand All @@ -49,3 +54,23 @@ teardown() {
[ "$(echo -e "1.0.0\n1.1.0")" == "$output" ]
[ "$status" -eq 0 ]
}

@test "list_all_command fails when list-all script exits with non-zero code" {
run asdf list-all dummy-broken
echo $output
[ "$status" -eq 1 ]
[[ "$output" == "Plugin dummy-broken's list-all callback script failed with output:"* ]]
}

@test "list_all_command displays stderr then stdout when failing" {
run asdf list-all dummy-broken
echo $output
[[ "$output" == *"List-all failed!"* ]]
[[ "$output" == *"Attempting to list versions" ]]
}


@test "list_all_command ignores stderr when completing successfully" {
run asdf list-all dummy
[[ "$output" != *"ignore this error"* ]]
}
10 changes: 10 additions & 0 deletions test/test_helpers.bash
Expand Up @@ -33,6 +33,12 @@ install_mock_legacy_plugin() {
cp -r "$BATS_TEST_DIRNAME/fixtures/dummy_legacy_plugin" "$location/plugins/$plugin_name"
}

install_mock_broken_plugin() {
local plugin_name=$1
local location="${2:-$ASDF_DIR}"
cp -r "$BATS_TEST_DIRNAME/fixtures/dummy_broken_plugin" "$location/plugins/$plugin_name"
}

install_mock_plugin_repo() {
local plugin_name=$1
local location="${BASE_DIR}/repo-${plugin_name}"
Expand All @@ -59,6 +65,10 @@ install_dummy_legacy_plugin() {
install_mock_legacy_plugin "legacy-dummy"
}

install_dummy_broken_plugin() {
install_mock_broken_plugin "dummy-broken"
}

install_dummy_version() {
install_mock_plugin_version "dummy" "$1"
}
Expand Down