Skip to content

Commit 92d57fd

Browse files
byrootmislav
andauthored
Support building with version prefix (#2610)
* 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 ``` * Improve version name resolution from prefix - `ruby-build --resolve` now prints canonical definition names, always stripping the "ruby-" prefix from output (e.g. "ruby-3.4" => "3.4.9"). - Fix sorting versions so that "jruby" correctly resolves to "jruby-10.x" instead of to "jruby-9.x". - Support bare "ruby" argument to select the latest CRuby version, since that was already possible for "jruby", "mruby", et al. - Case-normalize version inputs so that arguments like "JRuby" or "TruffleRuby" resolve to their lowercase definitions. - Simplify definition file lookup: all code paths now go through resolve_version. - Restore the named-pipe + `--dir` check to correctly abort early. - Update README and man page: bump Ruby version numbers in examples, add Ruby implementations section, document the `--resolve` option. * Clarify what ruby-build considers to be "latest" Ruby version * Print usage error message if `--resolve` wasn't passed an argument --------- Co-authored-by: Mislav Marohnić <git@mislav.net>
1 parent 9061a95 commit 92d57fd

8 files changed

Lines changed: 392 additions & 57 deletions

File tree

README.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ PREFIX=/usr/local ./ruby-build-*/install.sh
4242
# As a standalone program
4343
$ ruby-build --list # lists latest stable releases for each Ruby
4444
$ ruby-build --definitions # lists all definitions, including outdated ones
45-
$ ruby-build 3.2.2 ~/.rubies/ruby-3.2.2 # installs Ruby 3.2.2
46-
$ ruby-build -d ruby-3.2.2 ~/.rubies # alternate form for the previous example
45+
$ ruby-build 3.4.9 ~/.rubies/ruby-3.4.9 # installs Ruby 3.4.9
46+
$ ruby-build -d ruby-3.4.9 ~/.rubies # alternate form for the previous example
47+
$ ruby-build -d ruby-3.4 ~/.rubies # installs latest Ruby 3.4.x
4748

4849
# As an rbenv plugin
49-
$ rbenv install 3.2.2 # installs Ruby 3.2.2 to ~/.rbenv/versions/3.2.2
50+
$ rbenv install 3.4.9 # installs Ruby 3.4.9 to ~/.rbenv/versions/3.4.9
51+
$ rbenv install 3 # installs latest Ruby 3.x
5052
```
5153

5254
> [!WARNING]
@@ -61,6 +63,28 @@ Basically, what ruby-build does when installing a Ruby version is this:
6163

6264
Depending on the context, ruby-build does a little bit more than the above: for example, it will try to link Ruby to the appropriate OpenSSL version, even if that means downloading and compiling OpenSSL itself; it will discover and link to Homebrew-installed instances of some libraries like libyaml and readline, etc.
6365

66+
### Ruby versions
67+
68+
When listing "latest" Ruby versions, such as in `ruby-build --list` output, ruby-build only knows of Ruby versions that are bundled with this project. That means that when a new Ruby version comes out, ruby-build will not know about it immediately— you will have to upgrade ruby-build before you can use it to install the new Ruby version. This is because ruby-build bundles [definition files](#custom-build-definitions) for each individual Ruby version.
69+
70+
If it's important to you that your installer tool always consults remote resources to download the list of latest Ruby versions (without having to upgrade the tool itself), check out [ruby-install][] as an alternative to ruby-build.
71+
72+
### Ruby implementations
73+
74+
ruby-build ships with definitions for the following Ruby implementations, denoted by version prefixes in the `ruby-build --list` output:
75+
76+
- [CRuby][]: listed in ruby-build as unprefixed version numbers in the `X.Y.Z` format. This is the main Ruby implementation that most people use and is also historically known as "MRI". ruby-build allows adding the `ruby-` prefix to CRuby version numbers for compatibility with other version managers.
77+
78+
- `jruby`: [JRuby][] is a high-performance Ruby implementation with real threading built on top of the Java virtual machine (JVM).
79+
80+
- `mruby`: [mruby][] is a lightweight, embeddable Ruby implementation for microcontrollers.
81+
82+
- `picoruby`: [PicoRuby][] is an alternative mruby implementation for one-chip microcontrollers.
83+
84+
- `truffleruby`: The Native standalone distribution of [TruffleRuby][], an implementation of Ruby on top of GraalVM's Truffle framework.
85+
86+
- `truffleruby+graalvm`: The JVM standalone distribution of TruffleRuby.
87+
6488
### Advanced Usage
6589

6690
#### Custom Build Definitions
@@ -197,3 +221,9 @@ Be sure to include the full build log for build failures.
197221
[wiki]: https://github.com/rbenv/ruby-build/wiki
198222
[build-env]: https://github.com/rbenv/ruby-build/wiki#suggested-build-environment
199223
[issue tracker]: https://github.com/rbenv/ruby-build/issues
224+
[cruby]: https://www.ruby-lang.org/
225+
[truffleruby]: https://truffleruby.dev/
226+
[picoruby]: https://github.com/picoruby/picoruby#readme
227+
[mruby]: https://mruby.org/
228+
[jruby]: https://www.jruby.org/
229+
[ruby-install]: https://github.com/postmodern/ruby-install#readme

bin/rbenv-install

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,6 @@ done
134134

135135
[ "${#ARGUMENTS[@]}" -le 1 ] || usage 1 >&2
136136

137-
unset VERSION_NAME
138-
139137
# The first argument contains the definition to install. If the
140138
# argument is missing, try to install whatever local app-specific
141139
# version is specified by rbenv. Show usage instructions if a local
@@ -144,6 +142,12 @@ DEFINITION="${ARGUMENTS[0]}"
144142
[ -n "$DEFINITION" ] || DEFINITION="$(rbenv-local 2>/dev/null || true)"
145143
[ -n "$DEFINITION" ] || usage 1 >&2
146144

145+
if VERSION_NAME="$(ruby-build --resolve "$DEFINITION")"; then
146+
DEFINITION="$VERSION_NAME"
147+
else
148+
unset VERSION_NAME
149+
fi
150+
147151
# Define `before_install` and `after_install` functions that allow
148152
# plugin hooks to register a string of code for execution before or
149153
# after the installation process.

bin/ruby-build

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
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
89
# --definitions List all local definitions, including outdated ones
10+
# --resolve Print the latest stable definition name matching a version prefix
911
# --version Show version of ruby-build
1012
#
1113
# -d, --dir Install the Ruby in <prefix>/<definition> instead of <prefix>
@@ -1411,6 +1413,36 @@ list_maintained_versions() {
14111413
} | extract_latest_versions | sort_versions | uniq
14121414
}
14131415

1416+
# resolve a version prefix to the exact version name for which exists a
1417+
# definition file. Example: "ruby-3" => "3.4.9"
1418+
resolve_version() {
1419+
local version="${1#ruby-}"
1420+
1421+
# Look for an exact match first.
1422+
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
1423+
if [ -f "${DEFINITION_DIR}/${version}" ]; then
1424+
echo "$version"
1425+
return 0
1426+
fi
1427+
done
1428+
1429+
local grep_pattern="${version%.}"
1430+
if [ "$grep_pattern" = "ruby" ]; then
1431+
# Special case to select the latest CRuby.
1432+
grep_pattern="[0-9]"
1433+
else
1434+
grep_pattern="$(tr 'A-Z' 'a-z' <<<"${grep_pattern//./\\.}")"
1435+
fi
1436+
1437+
version=$(list_definitions | \
1438+
grep -e "^${grep_pattern}[-.]" | \
1439+
grep -v -e '-rc[0-9]*$' -e '-preview[0-9]*$' -e '-dev$' | \
1440+
tail -n 1)
1441+
1442+
[ -n "$version" ] || return 1
1443+
echo "$version"
1444+
}
1445+
14141446
extract_latest_versions() {
14151447
# sort in this function looks redundunt but it is necessary
14161448
# rbx-3.99 appears latest unless the sort
@@ -1453,6 +1485,14 @@ for option in "${OPTIONS[@]}"; do
14531485
"l" | "list")
14541486
EARLY_EXIT=list_maintained_versions
14551487
;;
1488+
"resolve")
1489+
if [ "${#ARGUMENTS[*]}" -eq 1 ]; then
1490+
EARLY_EXIT=resolve_version
1491+
else
1492+
echo "ruby-build: '--resolve' needs an argument" >&2
1493+
EARLY_EXIT=usage_error
1494+
fi
1495+
;;
14561496
"d" | "dir")
14571497
APPEND_DEFINITION_TO_PREFIX=true
14581498
;;
@@ -1503,12 +1543,9 @@ if [ "${#EXTRA_ARGUMENTS[@]}" -gt 0 ]; then
15031543
RUBY_CONFIGURE_OPTS_ARRAY=("${EXTRA_ARGUMENTS[@]}")
15041544
fi
15051545

1506-
if [ "$APPEND_DEFINITION_TO_PREFIX" = "true" ]; then
1507-
if [ -p "$DEFINITION_PATH" ]; then
1508-
echo "ruby-build: using named pipes in combination with \`--dir' is not possible" >&2
1509-
EARLY_EXIT=usage_error
1510-
fi
1511-
PREFIX_PATH="$PREFIX_PATH/$(basename "$DEFINITION_PATH")"
1546+
if [[ "$APPEND_DEFINITION_TO_PREFIX" = "true" && -p "$DEFINITION_PATH" ]]; then
1547+
echo "ruby-build: using named pipes in combination with \`--dir' is not possible" >&2
1548+
EARLY_EXIT=usage_error
15121549
fi
15131550

15141551
case "$EARLY_EXIT" in
@@ -1521,6 +1558,10 @@ version | list_definitions | list_maintained_versions )
15211558
"$EARLY_EXIT"
15221559
exit 0
15231560
;;
1561+
resolve_version )
1562+
resolve_version "${ARGUMENTS[0]}" || exit 1
1563+
exit 0
1564+
;;
15241565
usage_error )
15251566
echo >&2
15261567
usage 1 >&2
@@ -1533,30 +1574,29 @@ usage_error )
15331574
;;
15341575
esac
15351576

1577+
VERSION_NAME_PREFIX=""
1578+
15361579
# expand the <definition> argument to full path of the definition file
15371580
if [[ ! -f "$DEFINITION_PATH" && ! -p "$DEFINITION_PATH" ]]; then
1581+
if ! VERSION_NAME="$(resolve_version "$DEFINITION_PATH")"; then
1582+
echo "ruby-build: definition not found: ${DEFINITION_PATH}" >&2
1583+
exit 2
1584+
fi
1585+
1586+
if [[ $DEFINITION_PATH == ruby-* && $VERSION_NAME != ruby-* ]]; then
1587+
VERSION_NAME_PREFIX="ruby-"
1588+
fi
1589+
15381590
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
1539-
if [ -f "${DEFINITION_DIR}/${DEFINITION_PATH}" ]; then
1540-
DEFINITION_PATH="${DEFINITION_DIR}/${DEFINITION_PATH}"
1591+
if [ -f "${DEFINITION_DIR}/${VERSION_NAME}" ]; then
1592+
DEFINITION_PATH="${DEFINITION_DIR}/${VERSION_NAME}"
15411593
break
15421594
fi
15431595
done
1596+
fi
15441597

1545-
# If the given definition is like ruby-X.Y.Z, search again with X.Y.Z
1546-
if [[ "$DEFINITION_PATH" =~ ^ruby-[0-9] ]]; then
1547-
DEFINITION_PATH="${DEFINITION_PATH#ruby-}"
1548-
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
1549-
if [ -f "${DEFINITION_DIR}/${DEFINITION_PATH}" ]; then
1550-
DEFINITION_PATH="${DEFINITION_DIR}/${DEFINITION_PATH}"
1551-
break
1552-
fi
1553-
done
1554-
fi
1555-
1556-
if [ ! -f "$DEFINITION_PATH" ]; then
1557-
echo "ruby-build: definition not found: ${DEFINITION_PATH}" >&2
1558-
exit 2
1559-
fi
1598+
if [ "$APPEND_DEFINITION_TO_PREFIX" = "true" ]; then
1599+
PREFIX_PATH="$PREFIX_PATH/${VERSION_NAME_PREFIX}$(basename "$DEFINITION_PATH")"
15601600
fi
15611601

15621602
# normalize the <prefix> argument

0 commit comments

Comments
 (0)