From b36b7a6d20bc8b766f2fffd3b4131e390c9b378a Mon Sep 17 00:00:00 2001 From: Stephan Garland Date: Sun, 15 Jan 2023 13:16:03 -0500 Subject: [PATCH 1/3] feat: added gitlab support, simplified version sorting with ls-remote This allows for easier access to both GitHub and GitLab releases, without having to modify anything new. It also simplifies sorting by using git ls-remote's built-in --sort functionality. Since not all projects strictly follow semver, attempts were made to normalize it, such as if there is no `-` between a patch version and `rc`, `prerelease`, etc. NOTE: this does require git >= 2.18.0, so that is checked for. It also removes the -C - parameter from curl, which was attempting to resume downloads, querying the server for the byte range to do so. This is not universally supported, and if the server doesn't support it, the download will fail. Finally, where possible, it uses shell built-ins like parameter substitution over calling external commands. If this isn't possible, it minimizes the number of spawned subshells by combining commands rather than piping. This speeds up the asdf ecosystem as a whole, by minimizing syscalls. --- template/bin/list-all | 2 +- template/lib/utils.bash | 50 ++++++++++++++++++++++++++++------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/template/bin/list-all b/template/bin/list-all index 943371e..55bf7b1 100755 --- a/template/bin/list-all +++ b/template/bin/list-all @@ -8,4 +8,4 @@ plugin_dir=$(dirname "$(dirname "$current_script_path")") # shellcheck source=../lib/utils.bash source "${plugin_dir}/lib/utils.bash" -list_all_versions | sort_versions | xargs echo +list_all_versions | xargs echo diff --git a/template/lib/utils.bash b/template/lib/utils.bash index 85a1c69..3f75a87 100755 --- a/template/lib/utils.bash +++ b/template/lib/utils.bash @@ -2,10 +2,20 @@ set -euo pipefail -# TODO: Ensure this is the correct GitHub homepage where releases can be downloaded for . -GH_REPO="" +GIT_VERSION=$(git --version) +GIT_VERSION=${GIT_VERSION##* } +# TODO: Ensure this is the correct GitHub/GitLab homepage where releases can be downloaded for . +REPO="" TOOL_NAME="" TOOL_TEST="" +IS_GITHUB=$( + [[ "$REPO" =~ "github" ]] + echo $? +) + +git_supports_sort() { + awk '{ split($0,a,"."); if ((a[1] < 2) || (a[2] < 18)) { print "1" } else { print "0" } }' <<<"$1" +} fail() { echo -e "asdf-$TOOL_NAME: $*" @@ -14,26 +24,30 @@ fail() { curl_opts=(-fsSL) -# NOTE: You might want to remove this if is not hosted on GitHub releases. +if [ $(git_supports_sort "${GIT_VERSION}") -eq 1 ]; then + printf "must have git >= 2.18.0, have ${GIT_VERSION}\n" + exit 1 +fi + +# NOTE: You might want to remove this if is not hosted on GitHub or GitLab releases. if [ -n "${GITHUB_API_TOKEN:-}" ]; then curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITHUB_API_TOKEN") +elif [ -n "${GITLAB_API_TOKEN:-}" ]; then + curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITLAB_API_TOKEN") fi -sort_versions() { - sed 'h; s/[+-]/./g; s/.p\([[:digit:]]\)/.z\1/; s/$/.z/; G; s/\n/ /' | - LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}' -} - -list_github_tags() { - git ls-remote --tags --refs "$GH_REPO" | - grep -o 'refs/tags/.*' | cut -d/ -f3- | - sed 's/^v//' # NOTE: You might want to adapt this sed to remove non-version strings from tags +list_remote_tags() { + git -c 'versionsort.suffix=a' -c 'versionsort.suffix=b' \ + -c 'versionsort.suffix=r' -c 'versionsort.suffix=p' \ + -c 'versionsort.suffix=-' -c 'versionsort.suffix=_' \ + ls-remote --exit-code --tags --refs --sort="version:refname" "$REPO" | + awk -F'[/v]' '{ print $NF }' || fail "no releases found" } list_all_versions() { # TODO: Adapt this. By default we simply list the tag names from GitHub releases. # Change this function if has other means of determining installable versions. - list_github_tags + list_remote_tags } download_release() { @@ -42,10 +56,14 @@ download_release() { filename="$2" # TODO: Adapt the release URL convention for - url="$GH_REPO/archive/v${version}.tar.gz" - + if [ $IS_GITHUB -eq 0 ]; then + url="$REPO/archive/v${version}.tar.gz" + else + url="$REPO/-/archive/${version}/${TOOL_NAME}-${version}.tar.gz" + fi + printf "%s: %s\n" "url" "$url" echo "* Downloading $TOOL_NAME release $version..." - curl "${curl_opts[@]}" -o "$filename" -C - "$url" || fail "Could not download $url" + curl "${curl_opts[@]}" -o "$filename" "$url" || fail "Could not download $url" } install_version() { From 2b483fddbf9e584188b880625d3edf92cd7ed81c Mon Sep 17 00:00:00 2001 From: Stephan Garland Date: Sun, 15 Jan 2023 18:13:09 -0500 Subject: [PATCH 2/3] fix: adds a regex requiring that the tag match some vague form of semver, in that it must start with a digit --- template/lib/utils.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/lib/utils.bash b/template/lib/utils.bash index 3f75a87..714377f 100755 --- a/template/lib/utils.bash +++ b/template/lib/utils.bash @@ -41,7 +41,7 @@ list_remote_tags() { -c 'versionsort.suffix=r' -c 'versionsort.suffix=p' \ -c 'versionsort.suffix=-' -c 'versionsort.suffix=_' \ ls-remote --exit-code --tags --refs --sort="version:refname" "$REPO" | - awk -F'[/v]' '{ print $NF }' || fail "no releases found" + awk -F'[/v]' '$NF ~ /^[0-9]+.*/ { print $NF }' || fail "no releases found" } list_all_versions() { From 3d909beefd8389ece388c91d9a8b2cd76f892566 Mon Sep 17 00:00:00 2001 From: Stephan Garland Date: Thu, 19 Jan 2023 20:18:43 -0500 Subject: [PATCH 3/3] fix: adds a fallback check for user's git ls-remote not supporting sort --- template/lib/utils.bash | 42 ++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/template/lib/utils.bash b/template/lib/utils.bash index 714377f..2acb2fb 100755 --- a/template/lib/utils.bash +++ b/template/lib/utils.bash @@ -2,6 +2,7 @@ set -euo pipefail +GIT_REMINDER_FILE="${ASDF_INSTALL_PATH}/.upgradegit" GIT_VERSION=$(git --version) GIT_VERSION=${GIT_VERSION##* } # TODO: Ensure this is the correct GitHub/GitLab homepage where releases can be downloaded for . @@ -24,9 +25,15 @@ fail() { curl_opts=(-fsSL) -if [ $(git_supports_sort "${GIT_VERSION}") -eq 1 ]; then - printf "must have git >= 2.18.0, have ${GIT_VERSION}\n" - exit 1 +if [ $(git_supports_sort "${GIT_VERSION}") -eq 0 ]; then + rm -f "${GIT_REMINDER_FILE}" + GIT_SUPPORTS_SORT=0 +else + GIT_SUPPORTS_SORT=1 + if [ ! -f "${GIT_REMINDER_FILE}" ]; then + printf "consider upgrading git to a version >= 2.18.0 for faster asdf - you have v${GIT_VERSION}\n" + touch "${GIT_REMINDER_FILE}" + fi fi # NOTE: You might want to remove this if is not hosted on GitHub or GitLab releases. @@ -36,18 +43,35 @@ elif [ -n "${GITLAB_API_TOKEN:-}" ]; then curl_opts=("${curl_opts[@]}" -H "Authorization: token $GITLAB_API_TOKEN") fi +# NOTE: If doesn't issue releases according to something resembling semver, +# you will need to edit the awk regex. list_remote_tags() { - git -c 'versionsort.suffix=a' -c 'versionsort.suffix=b' \ - -c 'versionsort.suffix=r' -c 'versionsort.suffix=p' \ - -c 'versionsort.suffix=-' -c 'versionsort.suffix=_' \ - ls-remote --exit-code --tags --refs --sort="version:refname" "$REPO" | - awk -F'[/v]' '$NF ~ /^[0-9]+.*/ { print $NF }' || fail "no releases found" + if [ ${GIT_SUPPORTS_SORT} -eq 0 ]; then + git -c 'versionsort.suffix=a' -c 'versionsort.suffix=b' \ + -c 'versionsort.suffix=r' -c 'versionsort.suffix=p' \ + -c 'versionsort.suffix=-' -c 'versionsort.suffix=_' \ + ls-remote --exit-code --tags --refs --sort="version:refname" "$REPO" | + awk -F'[/v]' '$NF ~ /^[0-9]+.*/ { print $NF }' || fail "no releases found" + else + git ls-remote --exit-code --tags --refs "$REPO" | + awk -F'[/v]' '$NF ~ /^[0-9]+.*/ { print $NF }' || fail "no releases found" + fi } list_all_versions() { # TODO: Adapt this. By default we simply list the tag names from GitHub releases. # Change this function if has other means of determining installable versions. - list_remote_tags + if [ ${GIT_SUPPORTS_SORT} -eq 0 ]; then + list_remote_tags + else + list_remote_tags | sort_versions + fi +} + +# NOTE: This is a fallback for if the user's installed version of git doesn't support sorting. +sort_versions() { + sed 'h; s/[+-]/./g; s/.p\([[:digit:]]\)/.z\1/; s/$/.z/; G; s/\n/ /' | + LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}' } download_release() {