Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ PREFIX=/usr/local ./ruby-build-*/install.sh
# As a standalone program
$ ruby-build --list # lists latest stable releases for each Ruby
$ ruby-build --definitions # lists all definitions, including outdated ones
$ ruby-build 3.2.2 ~/.rubies/ruby-3.2.2 # installs Ruby 3.2.2
$ ruby-build -d ruby-3.2.2 ~/.rubies # alternate form for the previous example
$ ruby-build 3.4.9 ~/.rubies/ruby-3.4.9 # installs Ruby 3.4.9
$ ruby-build -d ruby-3.4.9 ~/.rubies # alternate form for the previous example
$ ruby-build -d ruby-3.4 ~/.rubies # installs latest Ruby 3.4.x

# As an rbenv plugin
$ rbenv install 3.2.2 # installs Ruby 3.2.2 to ~/.rbenv/versions/3.2.2
$ rbenv install 3.4.9 # installs Ruby 3.4.9 to ~/.rbenv/versions/3.4.9
$ rbenv install 3 # installs latest Ruby 3.x
```

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

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.

### Ruby versions

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.

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.

### Ruby implementations

ruby-build ships with definitions for the following Ruby implementations, denoted by version prefixes in the `ruby-build --list` output:

- [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.

- `jruby`: [JRuby][] is a high-performance Ruby implementation with real threading built on top of the Java virtual machine (JVM).

- `mruby`: [mruby][] is a lightweight, embeddable Ruby implementation for microcontrollers.

- `picoruby`: [PicoRuby][] is an alternative mruby implementation for one-chip microcontrollers.

- `truffleruby`: The Native standalone distribution of [TruffleRuby][], an implementation of Ruby on top of GraalVM's Truffle framework.

- `truffleruby+graalvm`: The JVM standalone distribution of TruffleRuby.

### Advanced Usage

#### Custom Build Definitions
Expand Down Expand Up @@ -197,3 +221,9 @@ Be sure to include the full build log for build failures.
[wiki]: https://github.com/rbenv/ruby-build/wiki
[build-env]: https://github.com/rbenv/ruby-build/wiki#suggested-build-environment
[issue tracker]: https://github.com/rbenv/ruby-build/issues
[cruby]: https://www.ruby-lang.org/
[truffleruby]: https://truffleruby.dev/
[picoruby]: https://github.com/picoruby/picoruby#readme
[mruby]: https://mruby.org/
[jruby]: https://www.jruby.org/
[ruby-install]: https://github.com/postmodern/ruby-install#readme
8 changes: 6 additions & 2 deletions bin/rbenv-install
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ done

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

unset VERSION_NAME

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

if VERSION_NAME="$(ruby-build --resolve "$DEFINITION")"; then
DEFINITION="$VERSION_NAME"
else
unset VERSION_NAME
fi

# Define `before_install` and `after_install` functions that allow
# plugin hooks to register a string of code for execution before or
# after the installation process.
Expand Down
86 changes: 63 additions & 23 deletions bin/ruby-build
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#
# Usage: ruby-build [-dvpk] <definition> <prefix> [-- <configure-args...>]
# ruby-build {--list|--definitions}
# ruby-build --resolve <version>
# ruby-build --version
#
# -l, --list List latest stable releases for each Ruby
# --definitions List all local definitions, including outdated ones
# --resolve Print the latest stable definition name matching a version prefix
# --version Show version of ruby-build
#
# -d, --dir Install the Ruby in <prefix>/<definition> instead of <prefix>
Expand Down Expand Up @@ -1411,6 +1413,36 @@ list_maintained_versions() {
} | extract_latest_versions | sort_versions | uniq
}

# resolve a version prefix to the exact version name for which exists a
# definition file. Example: "ruby-3" => "3.4.9"
resolve_version() {
local version="${1#ruby-}"

# Look for an exact match first.
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
if [ -f "${DEFINITION_DIR}/${version}" ]; then
echo "$version"
return 0
fi
done

local grep_pattern="${version%.}"
if [ "$grep_pattern" = "ruby" ]; then
# Special case to select the latest CRuby.
grep_pattern="[0-9]"
else
grep_pattern="$(tr 'A-Z' 'a-z' <<<"${grep_pattern//./\\.}")"
fi

version=$(list_definitions | \
grep -e "^${grep_pattern}[-.]" | \
grep -v -e '-rc[0-9]*$' -e '-preview[0-9]*$' -e '-dev$' | \
tail -n 1)

[ -n "$version" ] || return 1
echo "$version"
}

extract_latest_versions() {
# sort in this function looks redundunt but it is necessary
# rbx-3.99 appears latest unless the sort
Expand Down Expand Up @@ -1453,6 +1485,14 @@ for option in "${OPTIONS[@]}"; do
"l" | "list")
EARLY_EXIT=list_maintained_versions
;;
"resolve")
if [ "${#ARGUMENTS[*]}" -eq 1 ]; then
EARLY_EXIT=resolve_version
else
echo "ruby-build: '--resolve' needs an argument" >&2
EARLY_EXIT=usage_error
fi
;;
"d" | "dir")
APPEND_DEFINITION_TO_PREFIX=true
;;
Expand Down Expand Up @@ -1503,12 +1543,9 @@ if [ "${#EXTRA_ARGUMENTS[@]}" -gt 0 ]; then
RUBY_CONFIGURE_OPTS_ARRAY=("${EXTRA_ARGUMENTS[@]}")
fi

if [ "$APPEND_DEFINITION_TO_PREFIX" = "true" ]; then
if [ -p "$DEFINITION_PATH" ]; then
echo "ruby-build: using named pipes in combination with \`--dir' is not possible" >&2
EARLY_EXIT=usage_error
fi
PREFIX_PATH="$PREFIX_PATH/$(basename "$DEFINITION_PATH")"
if [[ "$APPEND_DEFINITION_TO_PREFIX" = "true" && -p "$DEFINITION_PATH" ]]; then
echo "ruby-build: using named pipes in combination with \`--dir' is not possible" >&2
EARLY_EXIT=usage_error
fi

case "$EARLY_EXIT" in
Expand All @@ -1521,6 +1558,10 @@ version | list_definitions | list_maintained_versions )
"$EARLY_EXIT"
exit 0
;;
resolve_version )
resolve_version "${ARGUMENTS[0]}" || exit 1
exit 0
;;
usage_error )
echo >&2
usage 1 >&2
Expand All @@ -1533,30 +1574,29 @@ usage_error )
;;
esac

VERSION_NAME_PREFIX=""

# expand the <definition> argument to full path of the definition file
if [[ ! -f "$DEFINITION_PATH" && ! -p "$DEFINITION_PATH" ]]; then
if ! VERSION_NAME="$(resolve_version "$DEFINITION_PATH")"; then
echo "ruby-build: definition not found: ${DEFINITION_PATH}" >&2
exit 2
fi

if [[ $DEFINITION_PATH == ruby-* && $VERSION_NAME != ruby-* ]]; then
VERSION_NAME_PREFIX="ruby-"
fi

for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
if [ -f "${DEFINITION_DIR}/${DEFINITION_PATH}" ]; then
DEFINITION_PATH="${DEFINITION_DIR}/${DEFINITION_PATH}"
if [ -f "${DEFINITION_DIR}/${VERSION_NAME}" ]; then
DEFINITION_PATH="${DEFINITION_DIR}/${VERSION_NAME}"
break
fi
done
fi

# If the given definition is like ruby-X.Y.Z, search again with X.Y.Z
if [[ "$DEFINITION_PATH" =~ ^ruby-[0-9] ]]; then
DEFINITION_PATH="${DEFINITION_PATH#ruby-}"
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
if [ -f "${DEFINITION_DIR}/${DEFINITION_PATH}" ]; then
DEFINITION_PATH="${DEFINITION_DIR}/${DEFINITION_PATH}"
break
fi
done
fi

if [ ! -f "$DEFINITION_PATH" ]; then
echo "ruby-build: definition not found: ${DEFINITION_PATH}" >&2
exit 2
fi
if [ "$APPEND_DEFINITION_TO_PREFIX" = "true" ]; then
PREFIX_PATH="$PREFIX_PATH/${VERSION_NAME_PREFIX}$(basename "$DEFINITION_PATH")"
fi

# normalize the <prefix> argument
Expand Down
Loading