Skip to content

Commit f59e2f1

Browse files
committed
feat: support fuzzy matching version numbers
Make it even easier to support migrating off other Ruby version managers.
1 parent cfcda01 commit f59e2f1

File tree

2 files changed

+213
-7
lines changed

2 files changed

+213
-7
lines changed

bin/parse-legacy-file

Lines changed: 204 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
#!/usr/bin/env bash
22

3+
# shellcheck source=/dev/null
4+
source "$(dirname "$0")/../lib/utils.sh"
5+
36
get_legacy_version() {
4-
current_file="$1"
7+
local current_file="$1"
8+
local basename
59
basename="$(basename -- "$current_file")"
10+
local ruby_version=""
611

712
if [ "$basename" == "Gemfile" ]; then
8-
RUBY_VERSION="$(grep '^\s*ruby' "$current_file" |
13+
ruby_version="$(grep '^\s*ruby' "$current_file" |
914
sed -e 's/[[:space:]]/ /g' -e 's/#.*//' -e 's/[()]//' \
1015
-e 's/engine:/:engine =>/' -e 's/engine_version:/:engine_version =>/' \
1116
-e "s/.*:engine *=> *['\"]\([^'\"]*\).*:engine_version *=> *['\"]\([^'\"]*\).*/\2__ENGINE__\1/" \
@@ -18,11 +23,204 @@ get_legacy_version() {
1823
# Get version from .ruby-version file (filters out 'ruby-' prefix if it exists).
1924
# The .ruby-version is used by rbenv and now rvm.
2025
ruby_version="$(cat "$current_file")"
21-
ruby_prefix="ruby-"
22-
RUBY_VERSION="${ruby_version/#$ruby_prefix/}"
26+
local ruby_prefix="ruby-"
27+
ruby_version="${ruby_version/#$ruby_prefix/}"
28+
fi
29+
30+
ruby_version="$(printf '%s' "$ruby_version" | tr -d '\r' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
31+
32+
echo "$ruby_version"
33+
}
34+
35+
prefix_match() {
36+
local candidate="$1"
37+
local prefix="$2"
38+
39+
if [ -z "$prefix" ]; then
40+
return 1
41+
fi
42+
43+
if [ "$candidate" = "$prefix" ]; then
44+
return 0
45+
fi
46+
47+
local prefix_length=${#prefix}
48+
if [ "${candidate:0:prefix_length}" != "$prefix" ]; then
49+
return 1
50+
fi
51+
52+
local next_char="${candidate:prefix_length:1}"
53+
case "$next_char" in
54+
""|"."|"-"|"_"|"+" )
55+
return 0
56+
;;
57+
*)
58+
return 1
59+
;;
60+
esac
61+
}
62+
63+
compare_versions() {
64+
local left="$1"
65+
local right="$2"
66+
local -a left_parts=()
67+
local -a right_parts=()
68+
IFS='._+-' read -ra left_parts <<<"$left"
69+
IFS='._+-' read -ra right_parts <<<"$right"
70+
local max_len=${#left_parts[@]}
71+
72+
if [ ${#right_parts[@]} -gt "$max_len" ]; then
73+
max_len=${#right_parts[@]}
74+
fi
75+
76+
local i
77+
for ((i = 0; i < max_len; i++)); do
78+
local part_left="${left_parts[i]-}"
79+
local part_right="${right_parts[i]-}"
80+
81+
if [ "$part_left" = "$part_right" ]; then
82+
continue
83+
fi
84+
85+
if [ -z "$part_left" ]; then
86+
return 2
87+
fi
88+
89+
if [ -z "$part_right" ]; then
90+
return 1
91+
fi
92+
93+
local left_is_num=0
94+
local right_is_num=0
95+
case "$part_left" in
96+
''|*[!0-9]*)
97+
left_is_num=0
98+
;;
99+
*)
100+
left_is_num=1
101+
;;
102+
esac
103+
104+
case "$part_right" in
105+
''|*[!0-9]*)
106+
right_is_num=0
107+
;;
108+
*)
109+
right_is_num=1
110+
;;
111+
esac
112+
113+
if [ "$left_is_num" -eq 1 ] && [ "$right_is_num" -eq 1 ]; then
114+
if ((10#$part_left > 10#$part_right)); then
115+
return 1
116+
fi
117+
return 2
118+
fi
119+
120+
if [ "$left_is_num" -eq 1 ] && [ "$right_is_num" -eq 0 ]; then
121+
return 1
122+
fi
123+
124+
if [ "$left_is_num" -eq 0 ] && [ "$right_is_num" -eq 1 ]; then
125+
return 2
126+
fi
127+
128+
if [[ "$part_left" > "$part_right" ]]; then
129+
return 1
130+
fi
131+
132+
return 2
133+
done
134+
135+
return 0
136+
}
137+
138+
latest_match() {
139+
local prefix="$1"
140+
local best=""
141+
local candidate
142+
143+
while IFS= read -r candidate; do
144+
[ -n "$candidate" ] || continue
145+
if prefix_match "$candidate" "$prefix"; then
146+
if [ -z "$best" ]; then
147+
best="$candidate"
148+
continue
149+
fi
150+
151+
compare_versions "$candidate" "$best"
152+
case $? in
153+
1)
154+
best="$candidate"
155+
;;
156+
esac
157+
fi
158+
done
159+
160+
if [ -n "$best" ]; then
161+
echo "$best"
162+
fi
163+
}
164+
165+
resolve_requested_version() {
166+
local requested="$1"
167+
local installs_dir
168+
local match
169+
local definitions=""
170+
local set_e_enabled=0
171+
local exit_code=0
172+
173+
if [ "$requested" = "system" ]; then
174+
echo "$requested"
175+
return
176+
fi
177+
178+
installs_dir="${ASDF_DATA_DIR:-${ASDF_DIR:-$HOME/.asdf}}/installs/ruby"
179+
180+
if [ -d "$installs_dir" ]; then
181+
match="$(
182+
for path in "$installs_dir"/*; do
183+
[ -d "$path" ] || continue
184+
basename "$path"
185+
done | latest_match "$requested"
186+
)"
187+
188+
if [ -n "$match" ]; then
189+
echo "$match"
190+
return
191+
fi
192+
fi
193+
194+
if [[ $- == *e* ]]; then
195+
set_e_enabled=1
196+
set +e
197+
fi
198+
definitions="$(ruby_build_definitions 2>/dev/null)"
199+
exit_code=$?
200+
if [ $set_e_enabled -eq 1 ]; then
201+
set -e
202+
fi
203+
204+
if [ $exit_code -eq 0 ] && [ -n "$definitions" ]; then
205+
match="$(printf '%s\n' "$definitions" | latest_match "$requested")"
206+
if [ -n "$match" ]; then
207+
echo "$match"
208+
return
209+
fi
210+
fi
211+
212+
echo "$requested"
213+
}
214+
215+
main() {
216+
local requested_version
217+
requested_version="$(get_legacy_version "$1")"
218+
219+
if [ -z "$requested_version" ]; then
220+
exit 0
23221
fi
24222

25-
echo "$RUBY_VERSION"
223+
resolve_requested_version "$requested_version"
26224
}
27225

28-
get_legacy_version "$1"
226+
main "$1"

lib/utils.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,11 @@ download_ruby_build() {
6262
}
6363

6464
asdf_ruby_plugin_path() {
65+
local source_path="${BASH_SOURCE[0]:-$0}"
66+
local script_dir
67+
script_dir="$(cd "$(dirname "$source_path")" >/dev/null 2>&1 && pwd)"
6568
# shellcheck disable=SC2005
66-
echo "$(dirname "$(dirname "$0")")"
69+
echo "$(dirname "$script_dir")"
6770
}
6871
ruby_build_dir() {
6972
echo "$(asdf_ruby_plugin_path)/ruby-build"
@@ -76,3 +79,8 @@ ruby_build_source_dir() {
7679
ruby_build_path() {
7780
echo "$(ruby_build_dir)/bin/ruby-build"
7881
}
82+
83+
ruby_build_definitions() {
84+
ensure_ruby_build_setup
85+
"$(ruby_build_path)" --definitions | grep -v "topaz-dev"
86+
}

0 commit comments

Comments
 (0)