#!/usr/bin/env bash # # Summary: Install a Ruby version using ruby-build # # Usage: rbenv install [-f] [-kvp] # rbenv install [-f] [-kvp] # rbenv install -l|--list # # -l/--list List all available versions # -f/--force Install even if the version appears to be installed already # -s/--skip-existing Skip if the version appears to be installed already # # ruby-build options: # # -k/--keep Keep source tree in $RBENV_BUILD_ROOT after installation # (defaults to $RBENV_ROOT/sources) # -v/--verbose Verbose mode: print compilation status to stdout # -p/--patch Apply a patch from stdin before building # # For detailed information on installing Ruby versions with # ruby-build, including a list of environment variables for adjusting # compilation, see: https://github.com/sstephenson/ruby-build#usage # set -e [ -n "$RBENV_DEBUG" ] && set -x # Provide rbenv completions if [ "$1" = "--complete" ]; then exec ruby-build --definitions fi if [ -z "$RBENV_ROOT" ]; then RBENV_ROOT="${HOME}/.rbenv" fi # Load shared library functions eval "$(ruby-build --lib)" usage() { # We can remove the sed fallback once rbenv 0.4.0 is widely available. rbenv-help install 2>/dev/null || sed -ne '/^#/!q;s/.//;s/.//;1,4d;p' < "$0" [ -z "$1" ] || exit "$1" } definitions() { local query="$1" ruby-build --definitions | $(type -p ggrep grep | head -1) -F "$query" || true } indent() { sed 's/^/ /' } unset FORCE unset SKIP_EXISTING unset KEEP unset VERBOSE unset HAS_PATCH parse_options "$@" for option in "${OPTIONS[@]}"; do case "$option" in "h" | "help" ) usage 0 ;; "l" | "list" ) echo "Available versions:" definitions | indent exit ;; "f" | "force" ) FORCE=true ;; "s" | "skip-existing" ) SKIP_EXISTING=true ;; "k" | "keep" ) [ -n "${RBENV_BUILD_ROOT}" ] || RBENV_BUILD_ROOT="${RBENV_ROOT}/sources" ;; "v" | "verbose" ) VERBOSE="-v" ;; "p" | "patch" ) HAS_PATCH="-p" ;; "version" ) exec ruby-build --version ;; * ) usage 1 ;; esac done 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 # version is not specified. DEFINITION="${ARGUMENTS[0]}" [ -n "$DEFINITION" ] || DEFINITION="$(rbenv-local 2>/dev/null || true)" [ -n "$DEFINITION" ] || usage 1 # 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. declare -a before_hooks after_hooks before_install() { local hook="$1" before_hooks["${#before_hooks[@]}"]="$hook" } after_install() { local hook="$1" after_hooks["${#after_hooks[@]}"]="$hook" } OLDIFS="$IFS" IFS=$'\n' scripts=(`rbenv-hooks install`) IFS="$OLDIFS" for script in "${scripts[@]}"; do source "$script"; done # Set VERSION_NAME from $DEFINITION, if it is not already set. Then # compute the installation prefix. [ -n "$VERSION_NAME" ] || VERSION_NAME="${DEFINITION##*/}" PREFIX="${RBENV_ROOT}/versions/${VERSION_NAME}" [ -d "${PREFIX}" ] && PREFIX_EXISTS=1 # If the installation prefix exists, prompt for confirmation unless # the --force option was specified. if [ -d "${PREFIX}/bin" ]; then if [ -z "$FORCE" ] && [ -z "$SKIP_EXISTING" ]; then echo "rbenv: $PREFIX already exists" >&2 read -p "continue with installation? (y/N) " case "$REPLY" in y* | Y* ) ;; * ) exit 1 ;; esac elif [ -n "$SKIP_EXISTING" ]; then # Since we know the ruby version is already installed, and are opting to # not force installation of existing versions, we just `exit 0` here to # leave things happy exit 0 fi fi # If RBENV_BUILD_ROOT is set, always pass keep options to ruby-build. if [ -n "${RBENV_BUILD_ROOT}" ]; then export RUBY_BUILD_BUILD_PATH="${RBENV_BUILD_ROOT}/${VERSION_NAME}" KEEP="-k" fi # Set RUBY_BUILD_CACHE_PATH to $RBENV_ROOT/cache, if the directory # exists and the variable is not already set. if [ -z "${RUBY_BUILD_CACHE_PATH}" ] && [ -d "${RBENV_ROOT}/cache" ]; then export RUBY_BUILD_CACHE_PATH="${RBENV_ROOT}/cache" fi # Default RBENV_VERSION to the globally-specified Ruby version. (The # REE installer requires an existing Ruby installation to run. An # unsatisfied local .ruby-version file can cause the installer to # fail.) export RBENV_VERSION="$(rbenv-global 2>/dev/null || true)" # Execute `before_install` hooks. for hook in "${before_hooks[@]}"; do eval "$hook"; done # Plan cleanup on unsuccessful installation. cleanup() { [ -z "${PREFIX_EXISTS}" ] && rm -rf "$PREFIX" } trap cleanup SIGINT # Invoke `ruby-build` and record the exit status in $STATUS. STATUS=0 ruby-build $KEEP $VERBOSE $HAS_PATCH "$DEFINITION" "$PREFIX" || STATUS="$?" # Display a more helpful message if the definition wasn't found. if [ "$STATUS" == "2" ]; then { candidates="$(definitions "$DEFINITION")" if [ -n "$candidates" ]; then echo echo "The following versions contain \`$DEFINITION' in the name:" echo "$candidates" | indent fi echo echo "You can list all available versions with \`rbenv install --list'." echo echo "If the version you're looking for is not present, first try upgrading" echo "ruby-build. If it's still missing, open a request on the ruby-build" echo "issue tracker: https://github.com/sstephenson/ruby-build/issues" } >&2 fi # Execute `after_install` hooks. for hook in "${after_hooks[@]}"; do eval "$hook"; done # Run `rbenv-rehash` after a successful installation. if [ "$STATUS" == "0" ]; then rbenv-rehash else cleanup fi exit "$STATUS"