Skip to content

Commit

Permalink
feat: Improve asdf update experience
Browse files Browse the repository at this point in the history
  • Loading branch information
hyperupcall committed Jul 18, 2023
1 parent d1a563d commit c8aa635
Show file tree
Hide file tree
Showing 4 changed files with 1,251 additions and 19 deletions.
2 changes: 2 additions & 0 deletions help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ asdf shim-versions <command> List the plugins and versions that
provide a command
asdf update Update asdf to the latest stable release
asdf update --head Update asdf to the latest on the master branch
asdf update --interactive|-i Update asdf interactively, choosing from versioned local git tags
asdf update <ref> Update asdf to specified ref

RESOURCES
GitHub: https://github.com/asdf-vm/asdf
Expand Down
78 changes: 59 additions & 19 deletions lib/commands/command-update.bash
Original file line number Diff line number Diff line change
@@ -1,44 +1,65 @@
# -*- sh -*-

update_command() {
local update_to_head=$1
local arg=$1

(
cd "$(asdf_dir)" || exit 1
local asdf_dir=
asdf_dir=$(asdf_dir)
cd "$asdf_dir" || exit 1

if [ -f asdf_updates_disabled ] || ! git rev-parse --is-inside-work-tree &>/dev/null; then
printf "Update command disabled. Please use the package manager that you used to install asdf to upgrade asdf.\n"
exit 42
else
do_update "$update_to_head"
fi

local ref=
case $arg in
--head)
ref='--head'
;;
--interactive|-i)
source "$asdf_dir/lib/vendor/bash-term.bash"
source "$asdf_dir/lib/utils-tty.bash"

local -a tags=()
readarray -d $'\n' -t tags <<< "$(print_tags | tac)"
tty.array_select "${tags[0]}" tags
local tag="$REPLY"

ref=$tag
;;
*)
if [ -n "$1" ]; then
ref="$1"

if ! git rev-parse --verify "$ref"; then
display_error "String '$ref' is not a valid git ref"
exit 1
fi
else
ref=$(print_tags --fetch | sed '$!d') || exit 1
fi
;;
esac

do_update "$ref"
)
}

do_update() {
local update_to_head=$1
local ref=$1

if [ "$update_to_head" = "--head" ]; then
if [ "$ref" = "--head" ]; then
# Update to latest on the master branch
git fetch origin master
git checkout master
git reset --hard origin/master
printf "Updated asdf to latest on the master branch\n"
else
# Update to latest release
git fetch origin --tags || exit 1

if [ "$(get_asdf_config_value "use_release_candidates")" = "yes" ]; then
# Use the latest tag whether or not it is an RC
tag=$(git tag | sort_versions | sed '$!d') || exit 1
else
# Exclude RC tags when selecting latest tag
tag=$(git tag | sort_versions | grep -vi "rc" | sed '$!d') || exit 1
fi

# Update
git checkout "$tag" || exit 1
printf "Updated asdf to release %s\n" "$tag"
git checkout "$ref" || exit 1
printf "Updated asdf to release or ref: %s\n" "$ref"
fi
}

Expand All @@ -48,4 +69,23 @@ sort_versions() {
LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}'
}

print_tags() {
local should_fetch=$1

if [ "$should_fetch" = '--fetch' ]; then
local default_branch='master'
local remote=
remote=$(git config "branch.$default_branch.remote") || exit 1
git fetch "$remote" --tags || exit 1
fi

if [ "$(get_asdf_config_value "use_release_candidates")" = "yes" ]; then
# Use the latest tag whether or not it is an RC
git tag | sort_versions || exit 1
else
# Exclude RC tags when selecting latest tag
git tag | sort_versions | grep -vi "rc" || exit 1
fi
}

update_command "$@"
248 changes: 248 additions & 0 deletions lib/utils-tty.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
# shellcheck shell=bash

tty.fullscreen_init() {
stty -echo
term.cursor_hide -p
term.cursor_savepos -p
term.screen_save -p

term.erase_saved_lines -p
read -r g_tty_height g_tty_width < <(stty size)
}

tty.fullscreen_deinit() {
term.screen_restore -p
term.cursor_restorepos -p
term.cursor_show -p
stty echo
}

tty.all_save() {
term.cursor_savepos -p
term.screen_save -p
}

tty.all_restore() {
term.screen_restore -p
term.cursor_restorepos -p
}

# backwards
tty._backwards_all() {
value_idx=0
}

tty._backwards_full_screen() {
if ((value_idx - g_tty_height > 0)); then
value_idx=$((value_idx - g_tty_height))
else
value_idx=0
fi
}

tty._backwards_half_screen() {
if ((value_idx - (g_tty_height/2) > 0)); then
value_idx=$((value_idx - (g_tty_height/2)))
else
value_idx=0
fi
}

tty._backwards_one() {
if ((value_idx > 0)); then
value_idx=$((value_idx-1))
fi
}

# forwards
tty._forwards_full_screen() {
local array_length=$1

if ((value_idx + g_tty_height < array_length)); then
value_idx=$((value_idx + g_tty_height))
else
value_idx=$((array_length-1))
fi
}

tty._forwards_half_screen() {
local array_length=$1

if ((value_idx + (g_tty_height/2) < array_length)); then
value_idx=$((value_idx + (g_tty_height/2)))
else
value_idx=$((array_length-1))
fi
}

tty._forwards_one() {
local array_length=$1

if ((value_idx+1 < array_length)); then
value_idx=$((value_idx+1))
fi
}

tty._forwards_all() {
local array_length=$1

value_idx=$((array_length-1))
}

tty._print_list() {
local index="$1"
if ! shift; then
display_error 'Failed to shift'
exit 1
fi

# index represents the center (ex. 17)

local start=$((index - (g_tty_height / 2)))
local end=$((start + g_tty_height))

term.cursor_to -p 0 0

local i=
local str=
local prefix=
for ((i=start; i<end; i++)); do
if ((i != start)); then
term.cursor_down -p 1
fi

if ((index+1 == i)); then
prefix='> '
else
prefix=' '
fi

# Greater than zero since "$0"
if ((i > 0 && i<$#+1)); then
str="${prefix}${*:$i:1}"
else
str="${prefix}\033[1;30m~\033[0m"
fi

printf '\r'
term.erase_line_end -p
# shellcheck disable=SC2059
printf "$str"
done; unset -v i
}

tty.array_select() {
unset -v REPLY; REPLY=
local initial_value="$1"
local arr_name="$2"
local -n arr="$arr_name"

if (( ${#arr[@]} == 0)); then
display_error "Array must not be empty"
exit 1
fi

local value_is_in_array=no
local value_idx=
local i=
for ((i=0; i < ${#arr[@]}; i++)); do
if [ "${arr[$i]}" = "$initial_value" ]; then
value_is_in_array=yes
value_idx=$i
break
fi
done; unset -v i
if [ "$value_is_in_array" = 'no' ]; then
display_error "Value '$initial_value' not found in array '$arr_name'"
exit 1
fi
unset -v value_is_in_array

declare -g g_tty_height
declare -g g_tty_width
tty.fullscreen_init
trap.sigint_tty() {
tty.fullscreen_deinit
}
trap.sigcont_tty() {
tty.fullscreen_init
}
trap 'trap.sigint_tty' 'EXIT'
trap 'trap.sigcont_tty' 'SIGCONT'

tty._print_list "$value_idx" "${arr[@]}"
while :; do
local key=
if ! read -rsN1 key; then
display_error 'Could not read input'
exit 1
fi

case $key in
g) tty._backwards_all ;;
$'\x02') tty._backwards_full_screen ;; # C-b
$'\x15') tty._backwards_half_screen ;; # C-u
k|$'\x10') tty._backwards_one ;; # k, C-p
$'\x06') tty._forwards_full_screen ${#arr[@]} ;; # C-f
$'\x04') tty._forwards_half_screen ${#arr[@]} ;; # C-d
j|$'\x0e') tty._forwards_one ${#arr[@]} ;; # j, C-n
G) tty._forwards_all ${#arr[@]} ;;
$'\n'|$'\x0d') break ;; # enter (success)
q|$'\x7f') # q, backspace (fail)
break
;;
$'\x1b') # escape
if ! read -rsN1 -t 0.1 key; then
# escape (fail)
break
fi

case $key in
$'\x5b')
if ! read -rsN1 -t 0.1 key; then
# escape (fail)
break
fi

case $key in
$'\x41') tty._backwards_one ;; # up
$'\x42') tty._forwards_one ${#arr[@]} ;; # down
$'\x43') tty._forwards_one ${#arr[@]} ;; # right
$'\x44') tty._backwards_one ;; # left
$'\x48') tty._backwards_all ;; # home
$'\x46') tty._forwards_all ${#arr[@]} ;; # end
$'\x35')
if ! read -rsN1 -t 0.1 key; then
# escape (fail)
break
fi

case $key in
$'\x7e') tty._backwards_full_screen ;; # pageup
esac
;;
$'\x36')
if ! read -rsN1 -t 0.1 key; then
# escape (fail)
break
fi

case "$key" in
$'\x7e') tty._forwards_full_screen ${#arr[@]} ;; # pagedown
esac
esac
;;
esac
;;
esac

tty._print_list "$value_idx" "${arr[@]}"
done
unset -v key
tty.fullscreen_deinit

trap - 'EXIT'
trap - 'SIGCONT'

REPLY=${arr[$value_idx]}
}
Loading

0 comments on commit c8aa635

Please sign in to comment.