From 30697b2d250c4f85cbc75653c03031fab22bef51 Mon Sep 17 00:00:00 2001 From: Philip Theus Date: Wed, 14 Jan 2026 20:06:15 +0100 Subject: [PATCH 1/3] Automatically fetch latest ruby-build version with 24h cache --- .gitignore | 2 + README.md | 20 ++++++---- lib/utils.sh | 104 +++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 107 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 8b254c4..38487e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ ruby-build +ruby-build-source +.ruby-build-version-cache diff --git a/README.md b/README.md index b730da7..d2bf636 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,20 @@ RUBY_APPLY_PATCHES=$'dir/1.patch\n2.patch\nhttp://example.com/3.patch' asdf inst RUBY_APPLY_PATCHES=$(curl -s https://raw.githubusercontent.com/rvm/rvm/master/patchsets/ruby/2.1.1/railsexpress) asdf install ruby 2.1.1 ``` -> [!NOTE] -> This plugin does not automatically fetch new Ruby versions. Running `asdf plugin update ruby` will update asdf-ruby and ensure the latest versions of Ruby are available to install. If the desired ruby version is still not showing up see the below [Troubleshooting](https://github.com/asdf-vm/asdf-ruby?tab=readme-ov-file#troubleshooting) section. +By default asdf-ruby automatically fetches the latest release of ruby-build, so new Ruby versions are available as soon as ruby-build supports them. -By default asdf-ruby uses a recent release of ruby-build, however instead you can choose your own branch/tag through the `ASDF_RUBY_BUILD_VERSION` variable: +You can override this behavior with the following environment variables: -``` -ASDF_RUBY_BUILD_VERSION=master asdf install ruby 2.6.4 -``` +- `ASDF_RUBY_BUILD_VERSION` - Pin to a specific ruby-build version/branch/tag: + ``` + ASDF_RUBY_BUILD_VERSION=v20240101 asdf install ruby 3.3.0 + ASDF_RUBY_BUILD_VERSION=master asdf install ruby 3.3.0 + ``` + +- `ASDF_RUBY_BUILD_CACHE_CLEAR` - Bypass the 24-hour cache and fetch the latest version: + ``` + ASDF_RUBY_BUILD_CACHE_CLEAR=1 asdf list-all ruby + ``` ## Default gems @@ -68,7 +74,7 @@ note that you might have to change `.ruby-version` to include full version (e.g. ## Troubleshooting > [!NOTE] -> The most common issue reported for this plugin is a missing Ruby version. If you are not seeing a recent Ruby version in the list of available Ruby versions it's likely due to having an older version of this plugin. Run `asdf plugin update ruby` to get the most recent list of Ruby versions. If it is still not showing up then this plugin's `RUBY_BUILD_VERSION` in lib/utils.sh likely needs updated with the latest ruby-build release https://github.com/rbenv/ruby-build/releases. Please check for an existing PR before submitting a new one. If there is not one, please fork the repo and submit one. If this plugin's ruby-build needs updated, you can workaround it with `ASDF_RUBY_BUILD_VERSION`. A note in the above [Use](https://github.com/asdf-vm/asdf-ruby?tab=readme-ov-file#use) section describes how to do this. +> If you are not seeing a recent Ruby version, try bypassing the version cache with `ASDF_RUBY_BUILD_CACHE_CLEAR=1 asdf list-all ruby` to fetch the latest ruby-build version. If the version still doesn't appear, check ruby-build's releases at https://github.com/rbenv/ruby-build/releases to see if it's been added yet. If you are moving to asdf-ruby from another Ruby version manager, it is recommended to completely uninstall the old Ruby version manager before installing asdf-ruby. diff --git a/lib/utils.sh b/lib/utils.sh index b3ffec8..e06300b 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -1,8 +1,5 @@ #!/usr/bin/env bash -RUBY_BUILD_VERSION="${ASDF_RUBY_BUILD_VERSION:-v20260503}" -RUBY_BUILD_TAG="$RUBY_BUILD_VERSION" - echoerr() { echo >&2 -e "\033[0;31m$1\033[0m" } @@ -17,11 +14,18 @@ ensure_ruby_build_setup() { } ensure_ruby_build_installed() { - local current_ruby_build_version + local current_ruby_build_version target_version + + target_version="$(get_ruby_build_version)" if [ ! -f "$(ruby_build_path)" ]; then - download_ruby_build - else + # No ruby-build installed - we must have a version to download + if [ -z "$target_version" ]; then + errorexit "Could not determine ruby-build version. Check your network connection." + fi + download_ruby_build "$target_version" + elif [ -n "$target_version" ]; then + # ruby-build exists and we have a target version - check if update needed current_ruby_build_version="$("$(ruby_build_path)" --version | cut -d ' ' -f2)" # If ruby-build version does not start with 'v', # add 'v' to beginning of version @@ -29,18 +33,20 @@ ensure_ruby_build_installed() { if [ ${current_ruby_build_version:0:1} != "v" ]; then current_ruby_build_version="v$current_ruby_build_version" fi - if [ "$current_ruby_build_version" != "$RUBY_BUILD_VERSION" ]; then + if [ "$current_ruby_build_version" != "$target_version" ]; then # If the ruby-build directory already exists and the version does not # match, remove it and download the correct version rm -rf "$(ruby_build_dir)" - download_ruby_build + download_ruby_build "$target_version" fi fi + # If ruby-build exists but we couldn't get a target version, just use what's installed } download_ruby_build() { + local version="$1" # Print to stderr so asdf doesn't assume this string is a list of versions - echoerr "Downloading ruby-build..." + echoerr "Downloading ruby-build ${version}..." # shellcheck disable=SC2155 local build_dir="$(ruby_build_source_dir)" @@ -51,11 +57,13 @@ download_ruby_build() { git clone https://github.com/rbenv/ruby-build.git "$build_dir" >/dev/null 2>&1 ( cd "$build_dir" || exit - git checkout "$RUBY_BUILD_TAG" >/dev/null 2>&1 + git checkout "$version" >/dev/null 2>&1 ) - # Install in the ruby-build dir - PREFIX="$(ruby_build_dir)" "$build_dir/install.sh" + # Install in the ruby-build dir (must use absolute path as install.sh changes directory) + local install_dir + install_dir="$(cd "$(asdf_ruby_plugin_path)" && pwd)/ruby-build" + PREFIX="$install_dir" "$build_dir/install.sh" # Remove ruby-build source dir rm -rf "$build_dir" @@ -76,3 +84,75 @@ ruby_build_source_dir() { ruby_build_path() { echo "$(ruby_build_dir)/bin/ruby-build" } + +ruby_build_version_cache_path() { + echo "$(asdf_ruby_plugin_path)/.ruby-build-version-cache" +} + +# Get file modification time in seconds since epoch (cross-platform) +get_file_mtime() { + local file="$1" + # Try GNU stat first (Linux), then BSD stat (macOS) + stat -c %Y "$file" 2>/dev/null || stat -f %m "$file" 2>/dev/null +} + +# Fetch the latest ruby-build version tag from GitHub +fetch_latest_ruby_build_version() { + git ls-remote --tags --sort=-version:refname https://github.com/rbenv/ruby-build.git 2>/dev/null | + grep -oE 'refs/tags/v[0-9]+$' | + head -1 | + sed 's|refs/tags/||' +} + +# Get the ruby-build version to use, with caching +# Priority: ASDF_RUBY_BUILD_VERSION env var > cached latest > fetched latest > installed version +get_ruby_build_version() { + # If user explicitly set a version, use that + if [ -n "${ASDF_RUBY_BUILD_VERSION:-}" ]; then + echo "$ASDF_RUBY_BUILD_VERSION" + return 0 + fi + + local cache_file + cache_file="$(ruby_build_version_cache_path)" + + # Check cache first (unless ASDF_RUBY_BUILD_CACHE_CLEAR is set) + if [ -z "${ASDF_RUBY_BUILD_CACHE_CLEAR:-}" ] && [ -f "$cache_file" ]; then + local cache_mtime current_time age + cache_mtime="$(get_file_mtime "$cache_file")" + current_time="$(date +%s)" + age=$((current_time - cache_mtime)) + + # Cache for 24 hours + if [ "$age" -lt 86400 ]; then + cat "$cache_file" + return 0 + fi + fi + + # Fetch latest version from GitHub + local latest_version + latest_version="$(fetch_latest_ruby_build_version)" + + if [ -n "$latest_version" ]; then + echo "$latest_version" >"$cache_file" + echo "$latest_version" + return 0 + fi + + # Fallback: if ruby-build is already installed, use its version + # (if we can't reach GitHub, we likely can't download a new version anyway) + if [ -f "$(ruby_build_path)" ]; then + local installed_version + installed_version="$("$(ruby_build_path)" --version | cut -d ' ' -f2)" + if [ "${installed_version:0:1}" != "v" ]; then + installed_version="v$installed_version" + fi + echoerr "Warning: Could not fetch latest ruby-build version, using installed version ${installed_version}" + echo "$installed_version" + return 0 + fi + + # No version available + return 1 +} From 171fa54318fc832ae8ba1cf2efa694cb1edfbaed Mon Sep 17 00:00:00 2001 From: Philip Theus Date: Wed, 14 Jan 2026 20:50:33 +0100 Subject: [PATCH 2/3] Remove version cache --- .gitignore | 1 - README.md | 18 ++++++------------ lib/utils.sh | 33 ++------------------------------- 3 files changed, 8 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index 38487e9..a02b3bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ ruby-build ruby-build-source -.ruby-build-version-cache diff --git a/README.md b/README.md index d2bf636..61b7fed 100644 --- a/README.md +++ b/README.md @@ -29,18 +29,12 @@ RUBY_APPLY_PATCHES=$(curl -s https://raw.githubusercontent.com/rvm/rvm/master/pa By default asdf-ruby automatically fetches the latest release of ruby-build, so new Ruby versions are available as soon as ruby-build supports them. -You can override this behavior with the following environment variables: +You can pin to a specific ruby-build version/branch/tag with the `ASDF_RUBY_BUILD_VERSION` environment variable: -- `ASDF_RUBY_BUILD_VERSION` - Pin to a specific ruby-build version/branch/tag: - ``` - ASDF_RUBY_BUILD_VERSION=v20240101 asdf install ruby 3.3.0 - ASDF_RUBY_BUILD_VERSION=master asdf install ruby 3.3.0 - ``` - -- `ASDF_RUBY_BUILD_CACHE_CLEAR` - Bypass the 24-hour cache and fetch the latest version: - ``` - ASDF_RUBY_BUILD_CACHE_CLEAR=1 asdf list-all ruby - ``` +``` +ASDF_RUBY_BUILD_VERSION=v20240101 asdf install ruby 3.3.0 +ASDF_RUBY_BUILD_VERSION=master asdf install ruby 3.3.0 +``` ## Default gems @@ -74,7 +68,7 @@ note that you might have to change `.ruby-version` to include full version (e.g. ## Troubleshooting > [!NOTE] -> If you are not seeing a recent Ruby version, try bypassing the version cache with `ASDF_RUBY_BUILD_CACHE_CLEAR=1 asdf list-all ruby` to fetch the latest ruby-build version. If the version still doesn't appear, check ruby-build's releases at https://github.com/rbenv/ruby-build/releases to see if it's been added yet. +> If you are not seeing a recent Ruby version, check ruby-build's releases at https://github.com/rbenv/ruby-build/releases to see if it's been added yet. If you are moving to asdf-ruby from another Ruby version manager, it is recommended to completely uninstall the old Ruby version manager before installing asdf-ruby. diff --git a/lib/utils.sh b/lib/utils.sh index e06300b..08cb741 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -85,17 +85,6 @@ ruby_build_path() { echo "$(ruby_build_dir)/bin/ruby-build" } -ruby_build_version_cache_path() { - echo "$(asdf_ruby_plugin_path)/.ruby-build-version-cache" -} - -# Get file modification time in seconds since epoch (cross-platform) -get_file_mtime() { - local file="$1" - # Try GNU stat first (Linux), then BSD stat (macOS) - stat -c %Y "$file" 2>/dev/null || stat -f %m "$file" 2>/dev/null -} - # Fetch the latest ruby-build version tag from GitHub fetch_latest_ruby_build_version() { git ls-remote --tags --sort=-version:refname https://github.com/rbenv/ruby-build.git 2>/dev/null | @@ -104,8 +93,8 @@ fetch_latest_ruby_build_version() { sed 's|refs/tags/||' } -# Get the ruby-build version to use, with caching -# Priority: ASDF_RUBY_BUILD_VERSION env var > cached latest > fetched latest > installed version +# Get the ruby-build version to use +# Priority: ASDF_RUBY_BUILD_VERSION env var > fetched latest > installed version get_ruby_build_version() { # If user explicitly set a version, use that if [ -n "${ASDF_RUBY_BUILD_VERSION:-}" ]; then @@ -113,29 +102,11 @@ get_ruby_build_version() { return 0 fi - local cache_file - cache_file="$(ruby_build_version_cache_path)" - - # Check cache first (unless ASDF_RUBY_BUILD_CACHE_CLEAR is set) - if [ -z "${ASDF_RUBY_BUILD_CACHE_CLEAR:-}" ] && [ -f "$cache_file" ]; then - local cache_mtime current_time age - cache_mtime="$(get_file_mtime "$cache_file")" - current_time="$(date +%s)" - age=$((current_time - cache_mtime)) - - # Cache for 24 hours - if [ "$age" -lt 86400 ]; then - cat "$cache_file" - return 0 - fi - fi - # Fetch latest version from GitHub local latest_version latest_version="$(fetch_latest_ruby_build_version)" if [ -n "$latest_version" ]; then - echo "$latest_version" >"$cache_file" echo "$latest_version" return 0 fi From 09a30b10b96d98b85261e494a164fa71c860b419 Mon Sep 17 00:00:00 2001 From: Philip Theus Date: Mon, 4 May 2026 14:34:59 -0400 Subject: [PATCH 3/3] take inspiration from asdf-nodejs, speed up fetches --- README.md | 2 + lib/utils.sh | 164 ++++++++++++++++++++++++--------------------------- 2 files changed, 80 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index 61b7fed..7e3a584 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ ASDF_RUBY_BUILD_VERSION=v20240101 asdf install ruby 3.3.0 ASDF_RUBY_BUILD_VERSION=master asdf install ruby 3.3.0 ``` +Set `ASDF_RUBY_SKIP_RUBY_BUILD_UPDATE=1` to skip the network check and reuse whatever ruby-build refs are already cached locally. + ## Default gems asdf-ruby can automatically install a set of default gems right after diff --git a/lib/utils.sh b/lib/utils.sh index 08cb741..f0034d9 100644 --- a/lib/utils.sh +++ b/lib/utils.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +RUBY_BUILD_REPOSITORY="https://github.com/rbenv/ruby-build.git" + echoerr() { echo >&2 -e "\033[0;31m$1\033[0m" } @@ -14,65 +16,98 @@ ensure_ruby_build_setup() { } ensure_ruby_build_installed() { - local current_ruby_build_version target_version - - target_version="$(get_ruby_build_version)" + local source_dir target_ref + source_dir="$(ruby_build_source_dir)" - if [ ! -f "$(ruby_build_path)" ]; then - # No ruby-build installed - we must have a version to download - if [ -z "$target_version" ]; then - errorexit "Could not determine ruby-build version. Check your network connection." - fi - download_ruby_build "$target_version" - elif [ -n "$target_version" ]; then - # ruby-build exists and we have a target version - check if update needed - current_ruby_build_version="$("$(ruby_build_path)" --version | cut -d ' ' -f2)" - # If ruby-build version does not start with 'v', - # add 'v' to beginning of version - # shellcheck disable=SC2086 - if [ ${current_ruby_build_version:0:1} != "v" ]; then - current_ruby_build_version="v$current_ruby_build_version" - fi - if [ "$current_ruby_build_version" != "$target_version" ]; then - # If the ruby-build directory already exists and the version does not - # match, remove it and download the correct version - rm -rf "$(ruby_build_dir)" - download_ruby_build "$target_version" + if ! ensure_ruby_build_source "$source_dir"; then + if [ -f "$(ruby_build_path)" ]; then + echoerr "Warning: Could not access ruby-build source; using existing installation." + return 0 fi + errorexit "Failed to clone ruby-build. Check your network connection." + fi + + target_ref="$(resolve_ruby_build_ref "$source_dir")" || + errorexit "Could not determine ruby-build version." + + if needs_install "$target_ref"; then + install_ruby_build "$source_dir" "$target_ref" + fi +} + +# Maintain a persistent clone of ruby-build. Cheap `git fetch` on each install +# keeps tag list current; set ASDF_RUBY_SKIP_RUBY_BUILD_UPDATE=1 to bypass. +ensure_ruby_build_source() { + local source_dir="$1" + + if [ ! -d "$source_dir/.git" ]; then + echoerr "Cloning ruby-build..." + rm -rf "$source_dir" + git clone "$RUBY_BUILD_REPOSITORY" "$source_dir" >/dev/null 2>&1 || return 1 + return 0 + fi + + if [ -n "${ASDF_RUBY_SKIP_RUBY_BUILD_UPDATE:-}" ]; then + return 0 fi - # If ruby-build exists but we couldn't get a target version, just use what's installed + + git -C "$source_dir" fetch --tags --prune origin >/dev/null 2>&1 || + echoerr "Warning: Could not update ruby-build, using cached refs." + return 0 } -download_ruby_build() { - local version="$1" - # Print to stderr so asdf doesn't assume this string is a list of versions - echoerr "Downloading ruby-build ${version}..." - # shellcheck disable=SC2155 - local build_dir="$(ruby_build_source_dir)" +# Pick the ref to check out: explicit env var > latest release tag. +resolve_ruby_build_ref() { + local source_dir="$1" - # Remove directory in case it still exists from last download - rm -rf "$build_dir" + if [ -n "${ASDF_RUBY_BUILD_VERSION:-}" ]; then + echo "$ASDF_RUBY_BUILD_VERSION" + return 0 + fi - # Clone down and checkout the correct ruby-build version - git clone https://github.com/rbenv/ruby-build.git "$build_dir" >/dev/null 2>&1 - ( - cd "$build_dir" || exit - git checkout "$version" >/dev/null 2>&1 - ) + local latest + latest="$(git -C "$source_dir" tag --list 'v*' --sort=-v:refname | head -1)" + if [ -n "$latest" ]; then + echo "$latest" + return 0 + fi + return 1 +} + +needs_install() { + local target_ref="$1" installed_version + [ ! -f "$(ruby_build_path)" ] && return 0 - # Install in the ruby-build dir (must use absolute path as install.sh changes directory) + installed_version="$("$(ruby_build_path)" --version | cut -d ' ' -f2)" + if [ "${installed_version:0:1}" != "v" ]; then + installed_version="v$installed_version" + fi + [ "$installed_version" != "$target_ref" ] +} + +install_ruby_build() { + local source_dir="$1" ref="$2" + echoerr "Installing ruby-build ${ref}..." + + local checkout_ref="$ref" + if git -C "$source_dir" show-ref --verify --quiet "refs/remotes/origin/$ref"; then + checkout_ref="origin/$ref" + fi + git -C "$source_dir" checkout --detach "$checkout_ref" >/dev/null 2>&1 || + errorexit "Failed to checkout ruby-build ref ${ref}." + + rm -rf "$(ruby_build_dir)" local install_dir install_dir="$(cd "$(asdf_ruby_plugin_path)" && pwd)/ruby-build" - PREFIX="$install_dir" "$build_dir/install.sh" - - # Remove ruby-build source dir - rm -rf "$build_dir" + PREFIX="$install_dir" "$source_dir/install.sh" || + errorexit "Failed to install ruby-build." } asdf_ruby_plugin_path() { # shellcheck disable=SC2005 echo "$(dirname "$(dirname "$0")")" } + ruby_build_dir() { echo "$(asdf_ruby_plugin_path)/ruby-build" } @@ -84,46 +119,3 @@ ruby_build_source_dir() { ruby_build_path() { echo "$(ruby_build_dir)/bin/ruby-build" } - -# Fetch the latest ruby-build version tag from GitHub -fetch_latest_ruby_build_version() { - git ls-remote --tags --sort=-version:refname https://github.com/rbenv/ruby-build.git 2>/dev/null | - grep -oE 'refs/tags/v[0-9]+$' | - head -1 | - sed 's|refs/tags/||' -} - -# Get the ruby-build version to use -# Priority: ASDF_RUBY_BUILD_VERSION env var > fetched latest > installed version -get_ruby_build_version() { - # If user explicitly set a version, use that - if [ -n "${ASDF_RUBY_BUILD_VERSION:-}" ]; then - echo "$ASDF_RUBY_BUILD_VERSION" - return 0 - fi - - # Fetch latest version from GitHub - local latest_version - latest_version="$(fetch_latest_ruby_build_version)" - - if [ -n "$latest_version" ]; then - echo "$latest_version" - return 0 - fi - - # Fallback: if ruby-build is already installed, use its version - # (if we can't reach GitHub, we likely can't download a new version anyway) - if [ -f "$(ruby_build_path)" ]; then - local installed_version - installed_version="$("$(ruby_build_path)" --version | cut -d ' ' -f2)" - if [ "${installed_version:0:1}" != "v" ]; then - installed_version="v$installed_version" - fi - echoerr "Warning: Could not fetch latest ruby-build version, using installed version ${installed_version}" - echo "$installed_version" - return 0 - fi - - # No version available - return 1 -}