Skip to content

Commit 3172bf5

Browse files
committed
Support building with version prefix
Commonly in CI pipelines and other scripts, users may want to install the latest from a specific series, e.g. `3.4` or `jruby-10.0`. ```bash $ bin/ruby-build 3.4 /tmp/3.4 ... Downloading ruby-3.4.9.tar.gz... $ bin/ruby-build 4.0 /tmp/4.0 ... Downloading ruby-4.0.2.tar.gz... ``` Also support `--resolve`: ```bash $ bin/ruby-build --resolve 3.4 3.4.9 ```
1 parent aa270b3 commit 3172bf5

4 files changed

Lines changed: 139 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ $ ruby-build --list # lists latest stable releases for ea
4444
$ ruby-build --definitions # lists all definitions, including outdated ones
4545
$ ruby-build 3.2.2 ~/.rubies/ruby-3.2.2 # installs Ruby 3.2.2
4646
$ ruby-build -d ruby-3.2.2 ~/.rubies # alternate form for the previous example
47+
$ ruby-build -d 3.2 ~/.rubies/ # installs latest "ruby-3.2" (3.2.10)
4748

4849
# As an rbenv plugin
4950
$ rbenv install 3.2.2 # installs Ruby 3.2.2 to ~/.rbenv/versions/3.2.2

bin/ruby-build

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
#
33
# Usage: ruby-build [-dvpk] <definition> <prefix> [-- <configure-args...>]
44
# ruby-build {--list|--definitions}
5+
# ruby-build {--resolve} <version>
56
# ruby-build --version
67
#
78
# -l, --list List latest stable releases for each Ruby
9+
# -r, --resolve Find the most recent version matching a prefix.
810
# --definitions List all local definitions, including outdated ones
911
# --version Show version of ruby-build
1012
#
@@ -1401,6 +1403,52 @@ list_maintained_versions() {
14011403
} | extract_latest_versions | sort_versions | uniq
14021404
}
14031405

1406+
filter_version_prefix()
1407+
{
1408+
match=1
1409+
prefix="$1"
1410+
if [[ "${prefix}" = "ruby" ]]; then
1411+
# Filter MRI versions
1412+
grep -e '^[0-9]'
1413+
elif echo "${prefix}" | grep -e '^\([0-9]\|[a-z\+]\+-[0-9]\)' > /dev/null; then
1414+
# Filter by version prefix
1415+
while IFS= read -r version; do
1416+
if [[ "${version}" = "${prefix}" ]] || [[ "${version}" = "${prefix}."* ]]; then
1417+
match=0
1418+
echo "${version}"
1419+
fi
1420+
done
1421+
else
1422+
# Filter by implementation
1423+
while IFS= read -r version; do
1424+
if [[ "${version}" = "${prefix}-"* ]]; then
1425+
match=0
1426+
echo "${version}"
1427+
fi
1428+
done
1429+
fi
1430+
return $match
1431+
}
1432+
1433+
resolve() {
1434+
prefix="${1%.}"
1435+
prefix="${prefix#ruby-}"
1436+
1437+
list_definitions | \
1438+
grep -v -e '-rc[0-9]*$' -e '-preview[0-9]*$' -e '-dev$' | \
1439+
filter_version_prefix "${prefix}" | \
1440+
LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | \
1441+
tail -n 1
1442+
}
1443+
1444+
resolve_version() {
1445+
version=$(resolve "$@")
1446+
if [[ -z "${version}" ]]; then
1447+
exit 1
1448+
fi
1449+
echo "${version}"
1450+
}
1451+
14041452
extract_latest_versions() {
14051453
# sort in this function looks redundunt but it is necessary
14061454
# rbx-3.99 appears latest unless the sort
@@ -1443,6 +1491,9 @@ for option in "${OPTIONS[@]}"; do
14431491
"l" | "list")
14441492
EARLY_EXIT=list_maintained_versions
14451493
;;
1494+
"resolve")
1495+
EARLY_EXIT=resolve_version
1496+
;;
14461497
"d" | "dir")
14471498
APPEND_DEFINITION_TO_PREFIX=true
14481499
;;
@@ -1493,6 +1544,7 @@ if [ "${#EXTRA_ARGUMENTS[@]}" -gt 0 ]; then
14931544
RUBY_CONFIGURE_OPTS_ARRAY=("${EXTRA_ARGUMENTS[@]}")
14941545
fi
14951546

1547+
ORIGINAL_PREFIX_PATH="${PREFIX_PATH}"
14961548
if [ "$APPEND_DEFINITION_TO_PREFIX" = "true" ]; then
14971549
if [ -p "$DEFINITION_PATH" ]; then
14981550
echo "ruby-build: using named pipes in combination with \`--dir' is not possible" >&2
@@ -1507,8 +1559,9 @@ help )
15071559
echo
15081560
usage 0
15091561
;;
1510-
version | list_definitions | list_maintained_versions )
1511-
"$EARLY_EXIT"
1562+
version | list_definitions | list_maintained_versions | resolve_version )
1563+
shift
1564+
"$EARLY_EXIT" "$@"
15121565
exit 0
15131566
;;
15141567
usage_error )
@@ -1543,6 +1596,19 @@ if [[ ! -f "$DEFINITION_PATH" && ! -p "$DEFINITION_PATH" ]]; then
15431596
done
15441597
fi
15451598

1599+
if [ ! -f "$DEFINITION_PATH" ]; then
1600+
fully_qualified_version=$(resolve "$DEFINITION_PATH")
1601+
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
1602+
if [ -f "${DEFINITION_DIR}/${fully_qualified_version}" ]; then
1603+
DEFINITION_PATH="${DEFINITION_DIR}/${fully_qualified_version}"
1604+
if [ "$APPEND_DEFINITION_TO_PREFIX" = "true" ]; then
1605+
PREFIX_PATH="$ORIGINAL_PREFIX_PATH/$(basename "$DEFINITION_PATH")"
1606+
fi
1607+
break
1608+
fi
1609+
done
1610+
fi
1611+
15461612
if [ ! -f "$DEFINITION_PATH" ]; then
15471613
echo "ruby-build: definition not found: ${DEFINITION_PATH}" >&2
15481614
exit 2

test/definitions.bats

100644100755
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,76 @@ NUM_DEFINITIONS="$(ls "$BATS_TEST_DIRNAME"/../share/ruby-build | wc -l)"
6060
assert_success ""
6161
}
6262

63+
@test "installing definition by prefix" {
64+
export RUBY_BUILD_DEFINITIONS="${TMP}/definitions"
65+
mkdir -p "${TMP}/definitions"
66+
67+
echo false > "${TMP}/definitions/1.8.6"
68+
echo false > "${TMP}/definitions/1.9.3"
69+
echo true > "${TMP}/definitions/1.9.10"
70+
echo false > "${TMP}/definitions/1.90.0"
71+
echo false > "${TMP}/definitions/2.0.0"
72+
73+
run bin/ruby-build "1.9" "${TMP}/install"
74+
assert_success ""
75+
}
76+
77+
@test "resolve definition by version prefix" {
78+
export RUBY_BUILD_DEFINITIONS="${TMP}/definitions"
79+
mkdir -p "${TMP}/definitions"
80+
81+
touch "${TMP}/definitions/1.8.6"
82+
touch "${TMP}/definitions/1.9.3"
83+
touch "${TMP}/definitions/1.9.10"
84+
touch "${TMP}/definitions/1.90.0"
85+
touch "${TMP}/definitions/2.0.0"
86+
87+
run bin/ruby-build --resolve "1.9" "${TMP}/install"
88+
assert_success "1.9.10"
89+
}
90+
91+
@test "resolve definition with ruby prefix" {
92+
export RUBY_BUILD_DEFINITIONS="${TMP}/definitions"
93+
mkdir -p "${TMP}/definitions"
94+
95+
touch "${TMP}/definitions/1.8.6"
96+
touch "${TMP}/definitions/1.9.3"
97+
touch "${TMP}/definitions/1.9.10"
98+
touch "${TMP}/definitions/1.90.0"
99+
touch "${TMP}/definitions/2.0.0"
100+
101+
run bin/ruby-build --resolve "ruby-1.9" "${TMP}/install"
102+
assert_success "1.9.10"
103+
}
104+
105+
@test "resolve definition by implementation name" {
106+
export RUBY_BUILD_DEFINITIONS="${TMP}/definitions"
107+
mkdir -p "${TMP}/definitions"
108+
109+
touch "${TMP}/definitions/foo-1.8.6"
110+
touch "${TMP}/definitions/foo-1.9.3"
111+
touch "${TMP}/definitions/1.9.10"
112+
touch "${TMP}/definitions/1.90.0"
113+
touch "${TMP}/definitions/2.0.0"
114+
115+
run bin/ruby-build --resolve "foo" "${TMP}/install"
116+
assert_success "foo-1.9.3"
117+
}
118+
119+
@test "resolve definition by implementation name and version" {
120+
export RUBY_BUILD_DEFINITIONS="${TMP}/definitions"
121+
mkdir -p "${TMP}/definitions"
122+
123+
touch "${TMP}/definitions/foo-1.8.6"
124+
touch "${TMP}/definitions/foo-1.9.3"
125+
touch "${TMP}/definitions/1.9.10"
126+
touch "${TMP}/definitions/1.90.0"
127+
touch "${TMP}/definitions/2.0.0"
128+
129+
run bin/ruby-build --resolve "foo-1.8" "${TMP}/install"
130+
assert_success "foo-1.8.6"
131+
}
132+
63133
@test "installing nonexistent definition" {
64134
run ruby-build "nonexistent" "${TMP}/install"
65135
assert [ "$status" -eq 2 ]

test/installer.bats

100644100755
File mode changed.

0 commit comments

Comments
 (0)