1
0
Fork 0
mirror of https://github.com/rbenv/ruby-build.git synced 2025-06-26 21:51:00 +02:00
rbenv-ruby-build/bin/ruby-build
Mislav Marohnić 93c50bbaf0
Show progress of downloaded files in the terminal
This connects the stderr of download utilities like curl and wget to the
original stderr of the process so that they can detect a terminal and
print progress bars to it.
2023-11-07 10:17:54 +01:00

1582 lines
42 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Usage: ruby-build [-kpv] <definition> <prefix>
# ruby-build --definitions
# ruby-build --version
#
# -k/--keep Do not remove source tree after installation
# -p/--patch Apply a patch from stdin before building
# -v/--verbose Verbose mode: print compilation status to stdout
# -4/--ipv4 Resolve names to IPv4 addresses only
# -6/--ipv6 Resolve names to IPv6 addresses only
# --definitions List all local definitions
# -l/--list List latest stable releases for each Ruby
# --version Show version of ruby-build
#
RUBY_BUILD_VERSION="20231025"
OLDIFS="$IFS"
# Have shell functions inherit the ERR trap.
set -E
# Some functions need to be able to write to the original process stderr
# stream, since fd 2 would often have been redirected elsewhere. To enable
# this, ruby-build initializes two additional file descriptors:
#
# 3: the original stderr
# 4: the log file
exec 3<&2
lib() {
parse_options() {
OPTIONS=()
ARGUMENTS=()
EXTRA_ARGUMENTS=()
local arg option index
while [ $# -gt 0 ]; do
arg="$1"
if [ "$arg" == "--" ]; then
shift 1
break
elif [ "${arg:0:1}" = "-" ]; then
if [ "${arg:1:1}" = "-" ]; then
OPTIONS[${#OPTIONS[*]}]="${arg:2}"
else
index=1
while option="${arg:$index:1}"; do
[ -n "$option" ] || break
OPTIONS[${#OPTIONS[*]}]="$option"
index=$((index+1))
done
fi
shift 1
else
ARGUMENTS[${#ARGUMENTS[*]}]="$arg"
shift 1
fi
done
EXTRA_ARGUMENTS=("$@")
}
if [ "$1" == "--${FUNCNAME[0]}" ]; then
declare -f "${FUNCNAME[0]}"
echo "${FUNCNAME[0]} \"\$1\";"
exit
fi
}
lib "$1"
resolve_link() {
$(type -p greadlink readlink | head -1) "$1"
}
abs_dirname() {
local path="$1"
local cwd
cwd="$(pwd || true)"
while [ -n "$path" ]; do
cd "${path%/*}" || return 1
local name="${path##*/}"
path="$(resolve_link "$name" || true)"
done
pwd
cd "$cwd" || return 1
}
capitalize() {
# shellcheck disable=SC2018,SC2019
printf "%s" "$1" | tr 'a-z' 'A-Z'
}
sanitize() {
printf "%s" "$1" | sed "s/[^A-Za-z0-9.-]/_/g; s/__*/_/g"
}
colorize() {
if [ -t 1 ]; then printf "\e[%sm%s\e[m" "$1" "$2"
else echo -n "$2"
fi
}
print_command() {
local arg
local tmpdir="${TMPDIR%/}"
for arg; do
arg="${arg//$tmpdir\//\$TMPDIR/}"
arg="${arg//$HOME\//\$HOME/}"
case "$arg" in
*\'* | *\$* )
printf ' "%s"' "$arg" ;;
*' '* )
printf " '%s'" "$arg" ;;
* )
printf ' %s' "$arg" ;;
esac
done
printf '\n'
}
# Log the full invocation of an external command.
log_command() {
local msg
msg="->$(print_command "$@")"
colorize 36 "$msg"
echo
[ -n "$VERBOSE" ] || printf "%s\n" "$msg" >&4
local status=0
"$@" || status="$?"
if [ "$status" -ne 0 ]; then
echo "external command failed with status $status" >&4
fi
return "$status"
}
# Log the full invocation of an external command and capture its output.
capture_command() {
local msg
msg="->$(print_command "$@")"
colorize 36 "$msg"
echo
# In verbose mode, connect the subcommand to original stdout & stderr.
local cmd_stdout=1
local cmd_stderr=3
if [ -z "$VERBOSE" ]; then
printf "%s\n" "$msg" >&4
# In normal mode, redirect all subcommand output to LOG_PATH.
cmd_stdout=4
cmd_stderr=4
fi
local status=0
# shellcheck disable=SC2261
"$@" 2>&$cmd_stderr >&$cmd_stdout || status="$?"
if [ "$status" -ne 0 ]; then
echo "external command failed with status $status" >&4
fi
return "$status"
}
log_info() {
colorize 1 "==> $*"
echo
[ -n "$VERBOSE" ] || echo "==> $*" >&4
}
log_notice() {
echo "ruby-build: $*"
}
os_information() {
if type -p lsb_release >/dev/null; then
lsb_release -sir | xargs echo
elif type -p sw_vers >/dev/null; then
echo "$(sw_vers -productName) $(sw_vers -productVersion)"
elif [ -r /etc/os-release ]; then
# shellcheck disable=SC1091
source /etc/os-release
# shellcheck disable=SC2153
echo "$NAME $VERSION_ID"
else
local os
os="$(cat /etc/{centos,redhat,fedora,system}-release /etc/debian_version 2>/dev/null | head -1)"
echo "${os:-$(uname -sr)}"
fi
}
is_mac() {
[ "$(uname -s)" = "Darwin" ] || return 1
[ $# -eq 0 ] || [ "$(osx_version)" -ge "$1" ]
}
is_freebsd() {
[ "$(uname -s)" = "FreeBSD" ]
}
freebsd_package_prefix() {
local package="$1"
pkg info --prefix "$package" 2>/dev/null | cut -wf2
}
# 9.1 -> 901
# 10.9 -> 1009
# 10.10 -> 1010
osx_version() {
local ver
IFS=. read -d "" -r -a ver <<<"$(sw_vers -productVersion)" || true
IFS="$OLDIFS"
echo $(( ver[0]*100 + ver[1] ))
}
build_failed() {
{ echo
colorize '31;1' "BUILD FAILED"
echo " ($(os_information) on $(uname -m) using $(version))"
echo
if ! rmdir "${BUILD_PATH}" 2>/dev/null; then
echo "You can inspect the build directory at ${BUILD_PATH}"
if [ -n "$(head -1 "$LOG_PATH" 2>/dev/null)" ]; then
colorize 33 "See the full build log at ${LOG_PATH}"
printf "\n"
fi
fi
} >&3
exit 1
}
num_cpu_cores() {
local num
case "$(uname -s)" in
Darwin | *BSD )
num="$(sysctl -n hw.ncpu 2>/dev/null || true)"
;;
SunOS )
num="$(getconf NPROCESSORS_ONLN 2>/dev/null || true)"
;;
* )
num="$({ getconf _NPROCESSORS_ONLN ||
grep -c ^processor /proc/cpuinfo; } 2>/dev/null)"
num="${num#0}"
;;
esac
echo "${num:-2}"
}
install_package() {
install_package_using "tarball" 1 "$@"
}
install_git() {
install_package_using "git" 2 "$@"
}
install_package_using() {
local package_type="$1"
local package_type_nargs="$2"
local package_name="$3"
shift 3
local fetch_args=( "$package_name" "${@:1:$package_type_nargs}" )
local make_args=( "$package_name" )
local arg last_arg
for arg in "${@:$(( package_type_nargs + 1 ))}"; do
if [ "$last_arg" = "--if" ]; then
if [[ $arg == *:* ]]; then
# Support colon-separated sub-argument, e.g. `needs_openssl:1.1`
"${arg%:*}" "$package_name" "${arg#*:}" || return 0
else
"$arg" "$package_name" || return 0
fi
elif [ "$arg" != "--if" ]; then
make_args["${#make_args[@]}"]="$arg"
fi
last_arg="$arg"
done
# shellcheck disable=SC2164
pushd "$BUILD_PATH" >&4
"fetch_${package_type}" "${fetch_args[@]}"
make_package "${make_args[@]}"
# shellcheck disable=SC2164
popd >&4
{ echo "Installed ${package_name} to ${PREFIX_PATH}"
echo
} >&2
}
make_package() {
local package_name="$1"
shift
# shellcheck disable=SC2164
pushd "$package_name" >&4
before_install_package "$package_name"
build_package "$package_name" "$@"
after_install_package "$package_name"
# shellcheck disable=SC2164
popd >&4
}
compute_sha2() {
local output
if type shasum &>/dev/null; then
output="$(shasum -a 256 -b)" || return 1
echo "${output% *}"
elif type openssl &>/dev/null; then
local openssl
openssl="$(command -v "$(brew --prefix openssl 2>/dev/null || true)"/bin/openssl openssl | head -1)"
output="$("$openssl" dgst -sha256 2>/dev/null)" || return 1
echo "${output##* }"
elif type sha256sum &>/dev/null; then
output="$(sha256sum -b)" || return 1
echo "${output%% *}"
else
return 1
fi
}
compute_md5() {
local output
if type md5 &>/dev/null; then
md5 -q
elif type openssl &>/dev/null; then
output="$(openssl md5)" || return 1
echo "${output##* }"
elif type md5sum &>/dev/null; then
output="$(md5sum -b)" || return 1
echo "${output%% *}"
else
return 1
fi
}
has_checksum_support() {
local checksum_command="$1"
local has_checksum_var="HAS_CHECKSUM_SUPPORT_${checksum_command}"
if [ -z "${!has_checksum_var+defined}" ]; then
if "$checksum_command" <<<"test" >/dev/null; then
printf -v "$has_checksum_var" 0 # success
else
printf -v "$has_checksum_var" 1 # error
fi
fi
return "${!has_checksum_var}"
}
verify_checksum() {
local checksum_command
local filename="$1"
local expected_checksum
expected_checksum="$(tr 'A-F' 'a-f' <<<"$2")"
# If the specified filename doesn't exist, return success
[ -e "$filename" ] || return 0
case "${#expected_checksum}" in
0) return 0 ;; # empty checksum; return success
32) checksum_command="compute_md5" ;;
64) checksum_command="compute_sha2" ;;
*)
{ echo
echo "unexpected checksum length: ${#expected_checksum} (${expected_checksum})"
echo "expected 0 (no checksum), 32 (MD5), or 64 (SHA2-256)"
echo
} >&4
return 1 ;;
esac
# If chosen provided checksum algorithm isn't supported, return success
has_checksum_support "$checksum_command" || return 0
# If the computed checksum is empty, return failure
local computed_checksum
computed_checksum="$("$checksum_command" < "$filename" | tr 'A-F' 'a-f')"
[ -n "$computed_checksum" ] || return 1
if [ "$expected_checksum" != "$computed_checksum" ]; then
{ echo
echo "checksum mismatch: ${filename} (file is corrupt)"
echo "expected $expected_checksum, got $computed_checksum"
echo
} >&4
return 1
fi
}
http() {
local method="$1"
[ -n "$2" ] || return 1
shift 1
RUBY_BUILD_HTTP_CLIENT="${RUBY_BUILD_HTTP_CLIENT:-$(detect_http_client 2>&3)}"
[ -n "$RUBY_BUILD_HTTP_CLIENT" ] || return 1
# http_get_curl, http_get_wget, etc.
"http_${method}_${RUBY_BUILD_HTTP_CLIENT}" "$@"
}
detect_http_client() {
local client
for client in aria2c curl wget; do
if type "$client" &>/dev/null; then
echo "$client"
return
fi
done
echo "error: install \`curl\`, \`wget\`, or \`aria2c\` to download packages" >&2
return 1
}
http_head_aria2c() {
# shellcheck disable=SC2086
aria2c --dry-run --no-conf=true $ARIA2_OPTS "$1" >/dev/null
}
http_get_aria2c() {
# shellcheck disable=SC2086
log_command aria2c --allow-overwrite=true --no-conf=true --console-log-level=warn --stderr $ARIA2_OPTS -o "$2" "$1" 2>&3
}
http_head_curl() {
# shellcheck disable=SC2086
curl -qsILf $CURL_OPTS "$1" >/dev/null
}
http_get_curl() {
# shellcheck disable=SC2086
log_command curl -q -fL $CURL_OPTS -o "$2" "$1" 2>&3
}
http_head_wget() {
# shellcheck disable=SC2086
wget -q --spider $WGET_OPTS "$1" >/dev/null
}
http_get_wget() {
# shellcheck disable=SC2086
log_command wget -nv --show-progress $WGET_OPTS -O "$2" "$1" 2>&3
}
fetch_tarball() {
local package_name="$1"
local package_url="$2"
local mirror_url
local checksum
local extracted_dir
if is_ruby_package "$1" && [ -n "$RUBY_BUILD_TARBALL_OVERRIDE" ]; then
package_url="$RUBY_BUILD_TARBALL_OVERRIDE"
fi
if [ "$package_url" != "${package_url/\#}" ]; then
checksum="${package_url#*#}"
package_url="${package_url%%#*}"
if [ -n "$RUBY_BUILD_MIRROR_URL" ]; then
if [[ -z "$RUBY_BUILD_DEFAULT_MIRROR" || $package_url != */cache.ruby-lang.org/* ]]; then
mirror_url="${RUBY_BUILD_MIRROR_URL}/$checksum"
fi
elif [ -n "$RUBY_BUILD_MIRROR_PACKAGE_URL" ]; then
mirror_url="$RUBY_BUILD_MIRROR_PACKAGE_URL"
fi
fi
local tar_args="xzf"
local package_filename="${package_name}.tar.gz"
if [ "$package_url" != "${package_url%bz2}" ]; then
if ! type -p bzip2 >/dev/null; then
echo "warning: bzip2 not found; consider installing \`bzip2\` package" >&4
fi
package_filename="${package_filename%.gz}.bz2"
tar_args="${tar_args/z/j}"
fi
if ! reuse_existing_tarball "$package_filename" "$checksum"; then
local tarball_filename
tarball_filename="$(basename "$package_url")"
log_info "Downloading ${tarball_filename}..."
# shellcheck disable=SC2015
http head "$mirror_url" &&
download_tarball "$mirror_url" "$package_filename" "$checksum" ||
download_tarball "$package_url" "$package_filename" "$checksum"
fi
log_command tar "$tar_args" "$package_filename" >/dev/null
if [ ! -d "$package_name" ]; then
extracted_dir="$(find_extracted_directory)"
mv "$extracted_dir" "$package_name"
fi
[ -n "$KEEP_BUILD_PATH" ] || rm -f "$package_filename"
}
find_extracted_directory() {
for f in *; do
if [ -d "$f" ]; then
echo "$f"
return
fi
done
echo "Extracted directory not found" >&2
return 1
}
reuse_existing_tarball() {
local package_filename="$1"
local checksum="$2"
# Reuse existing file in build location
if [ -e "$package_filename" ] && verify_checksum "$package_filename" "$checksum"; then
return 0
fi
# Reuse previously downloaded file in cache location
[ -n "$RUBY_BUILD_CACHE_PATH" ] || return 1
local cached_package_filename="${RUBY_BUILD_CACHE_PATH}/$package_filename"
[ -e "$cached_package_filename" ] || return 1
verify_checksum "$cached_package_filename" "$checksum" || return 1
ln -s "$cached_package_filename" "$package_filename" || return 1
}
download_tarball() {
local package_url="$1"
[ -n "$package_url" ] || return 1
local package_filename="$2"
local checksum="$3"
if http get "$package_url" "$package_filename"; then
verify_checksum "$package_filename" "$checksum" || return 1
else
echo "error: failed to download $package_filename" >&2
return 1
fi
if [ -n "$RUBY_BUILD_CACHE_PATH" ]; then
local cached_package_filename="${RUBY_BUILD_CACHE_PATH}/$package_filename"
mv "$package_filename" "$cached_package_filename"
ln -s "$cached_package_filename" "$package_filename"
fi
}
fetch_git() {
local package_name="$1"
local git_url="$2"
local git_ref="$3"
echo "Cloning ${git_url}..." >&2
if ! type git &>/dev/null; then
echo "error: please install \`git\` and try again" >&2
exit 1
fi
if [ -n "$RUBY_BUILD_CACHE_PATH" ]; then
local cache_dir
cache_dir="$RUBY_BUILD_CACHE_PATH/$(sanitize "$git_url")"
if [ -e "$cache_dir" ]; then
git -C "$cache_dir" fetch --force "$git_url" "+${git_ref}:${git_ref}" >&4 2>&1
else
git clone --bare --branch "$git_ref" "$git_url" "$cache_dir" >&4 2>&1
fi
git_url="$cache_dir"
fi
if [ -e "${package_name}" ]; then
git -C "$package_name" fetch --depth 1 origin "+${git_ref}" >&4 2>&1
git -C "$package_name" checkout -q -B "$git_ref" "origin/${git_ref}" >&4 2>&1
else
git clone --depth 1 --branch "$git_ref" "$git_url" "${package_name}" >&4 2>&1
fi
}
build_package() {
local package_name="$1"
shift
if [ "$#" -eq 0 ]; then
local commands="standard"
else
local commands="$*"
fi
log_info "Installing ${package_name}..."
[ -n "$HAS_PATCH" ] && apply_ruby_patch "$package_name"
for command in $commands; do
"build_package_${command}" "$package_name"
done
}
package_option() {
local package_name="$1"
local command_name="$2"
local variable
# e.g. RUBY_CONFIGURE_OPTS_ARRAY, OPENSSL_MAKE_OPTS_ARRAY
variable="$(capitalize "${package_name}_${command_name}")_OPTS_ARRAY"
local array="${variable}[@]"
shift 2
# shellcheck disable=SC2034
local value=( "${!array}" "$@" )
eval "$variable=( \"\${value[@]}\" )"
}
build_package_warn_eol() {
local package_name="$1"
{ echo
echo "WARNING: $package_name is past its end of life and is now unsupported."
echo "It no longer receives bug fixes or critical security updates."
echo
} >&3
}
build_package_warn_unsupported() {
local package_name="$1"
{ echo
echo "WARNING: $package_name is nearing its end of life."
echo "It only receives critical security updates, no bug fixes."
echo
} >&3
}
build_package_standard_build() {
local package_name="$1"
if [ "${MAKEOPTS+defined}" ]; then
MAKE_OPTS="$MAKEOPTS"
elif [ -z "${MAKE_OPTS+defined}" ]; then
MAKE_OPTS="-j $(num_cpu_cores)"
fi
# Support YAML_CONFIGURE_OPTS, RUBY_CONFIGURE_OPTS, etc.
local package_var_name
package_var_name="$(capitalize "${package_name%%-*}")"
local PACKAGE_CONFIGURE="${package_var_name}_CONFIGURE"
local PACKAGE_PREFIX_PATH="${package_var_name}_PREFIX_PATH"
local PACKAGE_CONFIGURE_OPTS="${package_var_name}_CONFIGURE_OPTS"
local PACKAGE_CONFIGURE_OPTS_ARRAY="${package_var_name}_CONFIGURE_OPTS_ARRAY[@]"
local PACKAGE_MAKE_OPTS="${package_var_name}_MAKE_OPTS"
local PACKAGE_MAKE_OPTS_ARRAY="${package_var_name}_MAKE_OPTS_ARRAY[@]"
local PACKAGE_CFLAGS="${package_var_name}_CFLAGS"
if [ "$package_var_name" = "RUBY" ]; then
if [[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-readline-dir=* ]]; then
use_homebrew_readline || use_freebsd_readline || true
fi
if [[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-libffi-dir=* ]]; then
use_freebsd_libffi || true
fi
if [[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-libyaml-dir=* ]]; then
use_homebrew_yaml || use_freebsd_yaml || true
fi
if [[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-gmp-dir=* ]]; then
use_homebrew_gmp || true
fi
if [[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-openssl-dir=* ]]; then
if is_freebsd && [ -f /usr/local/include/openssl/ssl.h ]; then
# use openssl installed from Ports Collection
package_option ruby configure --with-openssl-dir="/usr/local"
fi
fi
fi
( if [ "${CFLAGS+defined}" ] || [ "${!PACKAGE_CFLAGS+defined}" ]; then
export CFLAGS="$CFLAGS ${!PACKAGE_CFLAGS}"
fi
if [ -z "$CC" ] && is_mac 1010; then
export CC=clang
fi
# ./configure --prefix=/path/to/ruby
# shellcheck disable=SC2086,SC2153
capture_command ${!PACKAGE_CONFIGURE:-./configure} --prefix="${!PACKAGE_PREFIX_PATH:-$PREFIX_PATH}" \
"${!PACKAGE_CONFIGURE_OPTS_ARRAY}" $CONFIGURE_OPTS ${!PACKAGE_CONFIGURE_OPTS}
) || return $?
# make -j <num_cpu_cores>
# shellcheck disable=SC2086
capture_command "$MAKE" "${!PACKAGE_MAKE_OPTS_ARRAY}" $MAKE_OPTS ${!PACKAGE_MAKE_OPTS}
}
build_package_standard_install() {
local package_name="$1"
local package_var_name
package_var_name="$(capitalize "${package_name%%-*}")"
local PACKAGE_MAKE_INSTALL_OPTS="${package_var_name}_MAKE_INSTALL_OPTS"
local PACKAGE_MAKE_INSTALL_OPTS_ARRAY="${package_var_name}_MAKE_INSTALL_OPTS_ARRAY[@]"
# make install
# shellcheck disable=SC2086
capture_command "$MAKE" ${MAKE_INSTALL_TARGET:-install} "${!PACKAGE_MAKE_INSTALL_OPTS_ARRAY}" $MAKE_INSTALL_OPTS ${!PACKAGE_MAKE_INSTALL_OPTS}
}
build_package_standard_install_with_bundled_gems() {
capture_command "$MAKE" update-gems
capture_command "$MAKE" extract-gems
build_package_standard_install "$@"
}
# Backward Compatibility for standard function
build_package_standard() {
build_package_standard_build "$@"
build_package_standard_install "$@"
}
build_package_autoconf() {
capture_command autoreconf -i
}
build_package_ruby() {
capture_command "$RUBY_BIN" setup.rb
}
build_package_ree_installer() {
build_package_auto_tcltk
local options=()
is_mac && options+=(--no-tcmalloc)
local option
for option in "${RUBY_CONFIGURE_OPTS_ARRAY[@]}" $RUBY_CONFIGURE_OPTS; do
options+=(-c "$option")
done
# Work around install_useful_libraries crash with --dont-install-useful-gems
mkdir -p "$PREFIX_PATH/lib/ruby/gems/1.8/gems"
# shellcheck disable=SC2086
capture_command ./installer --auto "$PREFIX_PATH" --dont-install-useful-gems "${options[@]}" $CONFIGURE_OPTS
}
build_package_rbx() {
local package_name="$1"
{ [ ! -e "Gemfile" ] || bundle --path=vendor/bundle
if [ -n "$RUBY_BUILD_CACHE_PATH" ]; then
mkdir -p vendor
ln -s "$RUBY_BUILD_CACHE_PATH" vendor/prebuilt
fi
local opt
local -a configure_opts
for opt in "${RUBY_CONFIGURE_OPTS_ARRAY[@]}"; do
if [[ $opt == --with-openssl-dir=* ]]; then
local openssl_dir="${opt#*=}"
configure_opts[${#configure_opts[@]}]="--with-lib-dir=${openssl_dir}/lib"
configure_opts[${#configure_opts[@]}]="--with-include-dir=${openssl_dir}/include"
else
configure_opts[${#configure_opts[@]}]="$opt"
fi
done
# shellcheck disable=SC2086
RUBYOPT="-rrubygems $RUBYOPT" ./configure --prefix="$PREFIX_PATH" "${configure_opts[@]}" $RUBY_CONFIGURE_OPTS
rake install
fix_rbx_gem_binstubs "$PREFIX_PATH"
fix_rbx_irb "$PREFIX_PATH"
} >&4 2>&1
}
build_package_mruby() {
capture_command ./minirake
mkdir -p "$PREFIX_PATH"
cp -fR build/host/* include "$PREFIX_PATH"
ln -fs mruby "$PREFIX_PATH/bin/ruby"
ln -fs mirb "$PREFIX_PATH/bin/irb"
}
build_package_picoruby() {
capture_command ./minirake
mkdir -p "$PREFIX_PATH"
cp -fR build/host/* include "$PREFIX_PATH"
ln -fs picoruby "$PREFIX_PATH/bin/ruby"
ln -fs picoirb "$PREFIX_PATH/bin/irb"
}
build_package_jruby() {
build_package_copy
# shellcheck disable=SC2164
cd "${PREFIX_PATH}/bin"
ln -fs jruby ruby
chmod +x ruby
install_jruby_launcher
remove_windows_files
fix_jruby_shebangs
}
install_jruby_launcher() {
# shellcheck disable=SC2164
cd "${PREFIX_PATH}/bin"
# workaround for https://github.com/jruby/jruby/issues/7799
local jruby_version
jruby_version="$(./ruby -e 'puts JRUBY_VERSION' 2>/dev/null)"
[[ $jruby_version != "9.2."* ]] ||
capture_command ./ruby gem update -q --silent --system 3.3.26 --no-document --no-post-install-message
capture_command ./ruby gem install jruby-launcher --no-document
}
fix_jruby_shebangs() {
for file in "${PREFIX_PATH}/bin"/*; do
if [ "$(head -c 20 "$file" | LC_CTYPE=C tr -d '\0')" = "#!/usr/bin/env jruby" ]; then
sed -i.bak "1 s:.*:#\!${PREFIX_PATH}\/bin\/jruby:" "$file"
rm "$file".bak
fi
done
}
build_package_truffleruby() {
clean_prefix_path_truffleruby || return $?
build_package_copy
# shellcheck disable=SC2164
cd "${PREFIX_PATH}"
capture_command ./lib/truffle/post_install_hook.sh
}
build_package_truffleruby_graalvm() {
clean_prefix_path_truffleruby || return $?
PREFIX_PATH="${PREFIX_PATH}/graalvm" build_package_copy
if is_mac; then
# shellcheck disable=SC2164
cd "${PREFIX_PATH}/graalvm/Contents/Home"
else
# shellcheck disable=SC2164
cd "${PREFIX_PATH}/graalvm"
fi
if [ -e bin/gu ]; then
capture_command bin/gu install ruby
fi
local ruby_home
ruby_home=$(bin/ruby -e 'print RbConfig::CONFIG["prefix"]')
# Make gu available in PATH (useful to install other languages)
ln -s "$PWD/bin/gu" "$ruby_home/bin/gu"
# shellcheck disable=SC2164
cd "${PREFIX_PATH}"
ln -s "${ruby_home#"$PREFIX_PATH/"}/bin" .
capture_command "$ruby_home/lib/truffle/post_install_hook.sh"
}
build_package_artichoke() {
build_package_copy
mkdir -p "$PREFIX_PATH/bin"
# shellcheck disable=SC2164
cd "${PREFIX_PATH}/bin"
ln -fs ../artichoke ruby
ln -fs ../airb irb
ln -fs ../artichoke artichoke
ln -fs ../airb airb
}
remove_windows_files() {
# shellcheck disable=SC2164
cd "$PREFIX_PATH"
rm -f bin/*.exe bin/*.dll bin/*.bat bin/jruby.sh
}
clean_prefix_path_truffleruby() {
if [ -d "$PREFIX_PATH" ] &&
[ ! -e "$PREFIX_PATH/bin/truffleruby" ] &&
[ -n "$(ls -A "$PREFIX_PATH")" ]; then
echo
echo "ERROR: cannot install TruffleRuby to $PREFIX_PATH, which does not look like a valid TruffleRuby prefix" >&2
echo "TruffleRuby only supports being installed to a not existing directory, an empty directory, or replacing an existing TruffleRuby installation"
echo "See https://github.com/oracle/truffleruby/issues/1389 for details" >&2
return 1
fi
# Make sure there are no leftover files in $PREFIX_PATH
rm -rf "$PREFIX_PATH"
}
build_package_copy() {
mkdir -p "$PREFIX_PATH"
cp -fR . "$PREFIX_PATH"
}
before_install_package() {
local stub=1
}
after_install_package() {
local stub=1
}
fix_rbx_gem_binstubs() {
local prefix="$1"
local gemdir="${prefix}/gems/bin"
local bindir="${prefix}/bin"
local file binstub
# Symlink Rubinius' `gems/bin/` into `bin/`
if [ -d "$gemdir" ] && [ ! -L "$gemdir" ]; then
for file in "$gemdir"/*; do
binstub="${bindir}/${file##*/}"
rm -f "$binstub"
{ echo "#!${bindir}/ruby"
grep -v '^#!' "$file"
} > "$binstub"
chmod +x "$binstub"
done
rm -rf "$gemdir"
ln -s ../bin "$gemdir"
fi
}
fix_rbx_irb() {
local prefix="$1"
"${prefix}/bin/irb" --version &>/dev/null ||
capture_command "${prefix}/bin/gem" install rubysl-tracer -v '~> 2.0' --no-rdoc --no-ri ||
true
}
require_java() {
local required="$1"
local java_version version_string
java_version="$(java -version 2>&1 || true)"
version_string="$(grep 'java version' <<<"$java_version" | head -1 | grep -o '[0-9.]\+' | head -1 || true)"
[ -n "$version_string" ] || version_string="$(grep 'openjdk version' <<<"$java_version" | head -1 | grep -o '[0-9.]\+' | head -1 || true)"
IFS="."
# shellcheck disable=SC2206
local nums=($version_string)
IFS="$OLDIFS"
local found_version="${nums[0]}"
[ "$found_version" -gt 1 ] 2>/dev/null || found_version="${nums[1]}"
[ "$found_version" -ge "$required" ] 2>/dev/null && return 0
colorize 1 "ERROR" >&3
echo ": Java >= ${required} required, but your Java version was:" >&3
cat <<<"$java_version" >&3
return 1
}
# Kept for backward compatibility with JRuby <= 9.1.17 definitions.
require_java7() {
require_java 7
}
# Kept for backward compatibility with 3rd-party Ruby definitions.
require_gcc() {
local stub=1
}
# Kept for backward compatibility with 3rd-party Rubinius definitions.
# shellcheck disable=SC2034
require_llvm() {
local stub=1
}
needs_yaml() {
[[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-libyaml-dir=* ]] &&
! use_homebrew_yaml
}
use_homebrew_yaml() {
local libdir
libdir="$(brew --prefix libyaml 2>/dev/null || true)"
if [ -d "$libdir" ]; then
log_notice "using libyaml from homebrew"
package_option ruby configure --with-libyaml-dir="$libdir"
else
return 1
fi
}
use_freebsd_yaml() {
if is_freebsd; then
local libyaml_prefix
libyaml_prefix="$(freebsd_package_prefix libyaml)"
if [ -n "$libyaml_prefix" ]; then
package_option ruby configure --with-libyaml-dir="$libyaml_prefix"
fi
fi
}
use_homebrew_gmp() {
local libdir
libdir="$(brew --prefix gmp 2>/dev/null || true)"
if [ -d "$libdir" ]; then
log_notice "using gmp from homebrew"
package_option ruby configure --with-gmp-dir="$libdir"
else
return 1
fi
}
use_freebsd_readline() {
if is_freebsd; then
local readline_prefix libedit_prefix
readline_prefix="$(freebsd_package_prefix readline)"
libedit_prefix="$(freebsd_package_prefix libedit)"
if [ -n "$readline_prefix" ]; then
package_option ruby configure --with-readline-dir="$readline_prefix"
elif [ -n "$libedit_prefix" ]; then
package_option ruby configure --enable-libedit
package_option ruby configure --with-libedit-dir="$libedit_prefix"
fi
fi
}
use_homebrew_readline() {
local libdir
libdir="$(brew --prefix readline 2>/dev/null || true)"
if [ -d "$libdir" ]; then
log_notice "using readline from homebrew"
package_option ruby configure --with-readline-dir="$libdir"
else
return 1
fi
}
use_freebsd_libffi() {
if is_freebsd; then
local libffi_prefix
libffi_prefix="$(freebsd_package_prefix libffi)"
if [ -n "$libffi_prefix" ]; then
package_option ruby configure --with-libffi-dir="$libffi_prefix"
fi
fi
}
# macOS prevents linking to its system OpenSSL/LibreSSL installation, so
# it's basically useless for Ruby purposes.
has_broken_mac_openssl() {
is_mac || return 1
local openssl_version
openssl_version="$(/usr/bin/openssl version 2>/dev/null || true)"
[[ $openssl_version = "OpenSSL 0.9.8"?* || $openssl_version = "LibreSSL"* ]]
}
# Detect the OpenSSL version that a compiler can reasonably link to.
system_openssl_version() {
cc -xc -E - <<EOF 2>/dev/null | sed -n 's/"\{0,1\}OpenSSL \([0-9][0-9.]*\).*/\1/p'
#include <openssl/opensslv.h>
OPENSSL_VERSION_TEXT
EOF
}
# List all Homebrew-installed OpenSSL versions and their filesystem prefixes.
homebrew_openssl_versions() {
local formula version prefix
# https://github.com/orgs/Homebrew/discussions/4845
brew list 2>/dev/null | grep '^openssl@' | while read -r formula; do
prefix="$(brew --prefix "$formula" 2>/dev/null || true)"
[ -n "$prefix" ] || continue
version="$("$prefix"/bin/openssl version 2>/dev/null | sed -n 's/OpenSSL \([0-9][0-9.]*\).*/\1/p')"
[ -z "$version" ] || printf '%s %s %s\n' "$formula" "$version" "$prefix"
done
}
# Normalizes "X.Y.Z" into a comparable numeric value. Does not support prereleases.
# See also osx_version, require_java
normalize_semver() {
local ver
IFS=. read -d "" -r -a ver <<<"$1" || true
IFS="$OLDIFS"
# 3.1.23 -> 300_123
echo $(( ver[0]*100000 + ver[1]*100 + ver[2] ))
}
# Checks if system OpenSSL does NOT satisfy the version requirement
# between lower and upper bounds. This is used by build definitions to
# conditionally install per-ruby OpenSSL.
#
# If a compatible Homebrew-installed OpenSSL version is found during
# checking, Ruby will be linked to it and the check will return false.
needs_openssl() {
[[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-openssl-dir=* ]] || return 1
local system_version
if ! has_broken_mac_openssl; then
system_version="$(system_openssl_version)"
fi
# With no arguments, any system OpenSSL satisfies the check.
if [ $# -lt 2 ]; then
[ -z "$system_version" ] || return 1
return 0
fi
local lower_bound upper_bound
lower_bound="$(normalize_semver "${2%-*}")"
upper_bound="${2#*-}"
upper_bound="$(normalize_semver "${upper_bound//.x/.99}")"
system_version="$(normalize_semver "$system_version")"
# Return early if system openssl satisfies the requirement.
(( system_version < lower_bound || system_version >= upper_bound )) || return 1
# Look for the latest Homebrew-installed OpenSSL that satisfies the requirement
local brew_installs
brew_installs="$(homebrew_openssl_versions)"
[ -n "$brew_installs" ] || return 0
# Link to the highest-matching Homebrew OpenSSL
local versions homebrew_version formula version prefix
# shellcheck disable=SC2207
versions=( $(awk '{print $2}' <<<"$brew_installs" | sort_versions) )
local index="${#versions[@]}"
while [ $((index--)) -ge 0 ]; do
homebrew_version="$(normalize_semver "${versions[index]}")"
(( homebrew_version >= lower_bound && homebrew_version < upper_bound )) || continue
while read -r formula version prefix; do
[ "$version" = "${versions[index]}" ] || continue
log_notice "using $formula from homebrew"
package_option ruby configure --with-openssl-dir="$prefix"
return 1
done <<<"$brew_installs"
done
}
# Kept for backward compatibility with 3rd-party Ruby definitions.
needs_openssl_096_102() {
# openssl gem 1.1.1
needs_openssl "$1" "0.9.6-1.0.x"
}
# Kept for backward compatibility with 3rd-party Ruby definitions.
needs_openssl_101_111() {
# openssl gem 2.2.1
needs_openssl "$1" "1.0.1-1.x.x"
}
# Kept for backward compatibility with 3rd-party Ruby definitions.
needs_openssl_102_300() {
# openssl gem 3.0.0
needs_openssl "$1" "1.0.2-3.x.x"
}
# Kept for backward compatibility with 3rd-party Ruby definitions.
use_homebrew_openssl() {
local ssldir
ssldir="$(brew --prefix openssl@1.1 2>/dev/null || true)"
if [ -d "$ssldir" ]; then
log_notice "using openssl@1.1 from homebrew"
package_option ruby configure --with-openssl-dir="$ssldir"
else
colorize 1 "ERROR openssl@1.1 from Homebrew is required, run 'brew install openssl@1.1'"
return 1
fi
}
build_package_openssl() {
# Install to a subdirectory since we don't want shims for bin/openssl.
local OPENSSL_PREFIX_PATH="${PREFIX_PATH}/openssl"
# Put openssl.conf, certs, etc in ~/.rbenv/versions/*/openssl/ssl
OPENSSLDIR="${OPENSSLDIR:-$OPENSSL_PREFIX_PATH/ssl}"
# Tell Ruby to use this openssl for its extension.
package_option ruby configure --with-openssl-dir="$OPENSSL_PREFIX_PATH"
# Make sure pkg-config finds our build first.
export PKG_CONFIG_PATH="${OPENSSL_PREFIX_PATH}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
local nokerberos
[[ "$1" != openssl-1.0.* ]] || nokerberos=1
# Compile a shared lib with zlib dynamically linked.
package_option openssl configure --openssldir="$OPENSSLDIR" zlib-dynamic no-ssl3 shared ${nokerberos:+no-ssl2 no-krb5}
# Skip building OpenSSL docs, which is slow.
local make_target="install_sw install_ssldirs"
[[ "$1" != openssl-1.0.* ]] || make_target="install_sw" # OpenSSL 1.0 does not have `install_ssldirs`
OPENSSL_CONFIGURE="${OPENSSL_CONFIGURE:-./config}" MAKE_INSTALL_TARGET="$make_target" build_package_standard "$@"
local pem_file="$OPENSSLDIR/cert.pem"
if is_mac; then
# Extract root certs from the system keychain in .pem format.
security find-certificate -a -p /Library/Keychains/System.keychain > "$pem_file"
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >> "$pem_file"
elif [ -e /etc/pki/tls/cert.pem ]; then # RedHat
# See https://github.com/rubygems/rubygems/issues/2415#issuecomment-509806259
rm -rf "$OPENSSLDIR/certs" "$pem_file"
ln -s /etc/pki/tls/certs "$OPENSSLDIR/certs"
ln -s /etc/pki/tls/cert.pem "$pem_file"
elif [ -e /etc/ssl/certs/ca-certificates.crt ]; then # Debian
# See https://github.com/rubygems/rubygems/issues/2415#issuecomment-509806259
rm -rf "$OPENSSLDIR/certs" "$pem_file"
ln -s /etc/ssl/certs "$OPENSSLDIR/certs"
ln -s /etc/ssl/certs/ca-certificates.crt "$pem_file"
elif type -p openssl >/dev/null; then
# symlink to the system openssl certs
local SYSTEM_OPENSSLDIR
SYSTEM_OPENSSLDIR=$(openssl version -d 2>/dev/null | cut -d'"' -f2)
if [ -n "$SYSTEM_OPENSSLDIR" ]; then
ln -sf "$SYSTEM_OPENSSLDIR/cert.pem" "$OPENSSLDIR/cert.pem"
ln -snf "$SYSTEM_OPENSSLDIR/certs" "$OPENSSLDIR/certs"
fi
else
echo "Could not find OpenSSL certificates" >&2
exit 1
fi
}
# Post-install check that the openssl extension was built.
build_package_verify_openssl() {
# shellcheck disable=SC2016
"$RUBY_BIN" -e '
manager = ARGV[0]
packages = {
"apt-get" => Hash.new {|h,k| "lib#{k}-dev" }.update(
"openssl" => "libssl-dev",
"zlib" => "zlib1g-dev"
),
"yum" => Hash.new {|h,k| "#{k}-devel" }.update(
"yaml" => "libyaml-devel"
)
}
failed = %w[openssl readline zlib yaml].reject do |lib|
begin
require lib
rescue LoadError => e
$stderr.puts "Loading the Ruby #{lib} extension failed (#{e})"
end
end
if failed.size > 0
$stderr.puts "ERROR: Ruby install aborted due to missing extensions"
$stderr.print "Try running `%s install -y %s` to fetch missing dependencies.\n\n" % [
manager,
failed.map { |lib| packages.fetch(manager)[lib] }.join(" ")
] unless manager.empty?
$stderr.puts "Configure options used:"
require "rbconfig"; require "shellwords"
RbConfig::CONFIG.fetch("configure_args").shellsplit.each { |arg| $stderr.puts " #{arg}" }
exit 1
end
' "$(basename "$(type -p yum apt-get | head -1)")" >&4 2>&1
}
# Kept for backward compatibility with 3rd-party definitions.
build_package_ldflags_dirs() {
true
}
build_package_enable_shared() {
if [[ " ${RUBY_CONFIGURE_OPTS} ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *" --disable-shared"* ]]; then
package_option ruby configure --enable-shared
fi
}
build_package_auto_tcltk() {
if is_mac && [ ! -d /usr/include/X11 ]; then
if [ -d /opt/X11/include ]; then
if [[ "$CPPFLAGS" != *-I/opt/X11/include* ]]; then
export CPPFLAGS="-I/opt/X11/include $CPPFLAGS"
fi
else
package_option ruby configure --without-tk
fi
fi
}
rake() {
if [ -e "./Gemfile" ]; then
bundle exec rake "$@"
else
isolated_gem_dependency "rake --version" rake -v '~> 10.1.0'
command rake "$@"
fi
}
bundle() {
isolated_gem_dependency "bundle --version" bundler -v '~> 1.3.5'
command bundle "$@"
}
isolated_gem_dependency() {
set +E
( command $1 &>/dev/null ) || {
set -E
shift 1
isolated_gem_install "$@"
}
set -E
}
isolated_gem_install() {
export GEM_HOME="${PWD}/.gem"
export PATH="${GEM_HOME}/bin:${PATH}"
gem install "$@"
}
apply_ruby_patch() {
local patchfile
if is_ruby_package "$1"; then
patchfile="$(mktemp "${TMP}/ruby-patch.XXXXXX")"
cat "${2:--}" >"$patchfile"
local striplevel=0
grep -q '^--- a/' "$patchfile" && striplevel=1
log_command patch -p$striplevel --force -i "$patchfile"
fi
}
is_ruby_package() {
case "$1" in
ruby-* | jruby-* | rubinius-* | truffleruby[+-]* | mruby-* | picoruby-* )
return 0
;;
*)
return 1
;;
esac
}
version() {
local git_revision
# Read the revision from git if the remote points to "ruby-build" repository
if GIT_DIR="$RUBY_BUILD_INSTALL_PREFIX/.git" git remote -v 2>/dev/null | grep -q /ruby-build; then
git_revision="$(GIT_DIR="$RUBY_BUILD_INSTALL_PREFIX/.git" git describe --tags HEAD 2>/dev/null || true)"
git_revision="${git_revision#v}"
fi
echo "ruby-build ${git_revision:-$RUBY_BUILD_VERSION}"
}
usage() {
sed -ne '/^#/!q;s/.\{1,2\}//;1,2d;p' < "$0"
[ -z "$1" ] || exit "$1"
}
# list all versions
list_definitions() {
{ for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
[ -d "$DEFINITION_DIR" ] && ls "$DEFINITION_DIR"
done
} | sort_versions | uniq
}
# list only latest stable versions excluding RC, preview, dev and EoL'ed
list_maintained_versions() {
{ for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
[ -d "$DEFINITION_DIR" ] && \
grep -L -e warn_eol "$DEFINITION_DIR"/* 2>/dev/null | \
sed 's|.*/||' | \
grep -v -e '-rc[0-9]*$' -e '-preview[0-9]*$' -e '-dev$'
done
} | extract_latest_versions | sort_versions | uniq
}
extract_latest_versions() {
# sort in this function looks redundunt but it is necessary
# rbx-3.99 appears latest unless the sort
sed 'h; s/[-]/./g; s/.p\([[:digit:]]\)/.z.\1/; s/$/.z/; G; s/\n/ /' | \
LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | \
sed 's/[.]/ /; s/[0-9].*z //; s/^\([0-9].[0-9]\)/mri\1 \1/' | \
awk '{ latest[$1] =$2 } END{ for(key in latest) { print latest[key] } }'
}
sort_versions() {
sed 'h; s/[-]/./g; s/.p\([[:digit:]]\)/.z.\1/; s/$/.z/; G; s/\n/ /' | \
LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}'
}
unset VERBOSE
unset KEEP_BUILD_PATH
unset HAS_PATCH
unset IPV4
unset IPV6
unset EARLY_EXIT
RUBY_BUILD_INSTALL_PREFIX="$(abs_dirname "$0")/.."
# shellcheck disable=SC2206
IFS=: RUBY_BUILD_DEFINITIONS=($RUBY_BUILD_DEFINITIONS ${RUBY_BUILD_ROOT:-$RUBY_BUILD_INSTALL_PREFIX}/share/ruby-build)
IFS="$OLDIFS"
parse_options "$@"
for option in "${OPTIONS[@]}"; do
case "$option" in
"h" | "help" )
EARLY_EXIT=help
;;
"definitions" )
EARLY_EXIT=list_definitions
;;
"l" | "list")
EARLY_EXIT=list_maintained_versions
;;
"k" | "keep" )
KEEP_BUILD_PATH=true
;;
"v" | "verbose" )
VERBOSE=true
;;
"p" | "patch" )
HAS_PATCH=true
;;
"4" | "ipv4")
IPV4=true
;;
"6" | "ipv6")
IPV6=true
;;
"version" )
EARLY_EXIT=version
;;
* )
printf "ruby-build: invalid flag '%s'\n" "$option" >&2
EARLY_EXIT=usage_error
;;
esac
done
DEFINITION_PATH="${ARGUMENTS[0]}"
PREFIX_PATH="${ARGUMENTS[1]}"
if [ -z "$EARLY_EXIT" ] && [ -z "$DEFINITION_PATH" ]; then
echo "ruby-build: missing definition argument" >&2
EARLY_EXIT=usage_error
fi
if [ -z "$EARLY_EXIT" ] && [ -z "$PREFIX_PATH" ]; then
echo "ruby-build: missing prefix argument" >&2
EARLY_EXIT=usage_error
fi
if [ "${#ARGUMENTS[@]}" -gt 2 ]; then
echo "ruby-build: expected at most 2 arguments, got [${ARGUMENTS[*]}]" >&2
EARLY_EXIT=usage_error
fi
if [ "${#EXTRA_ARGUMENTS[@]}" -gt 0 ]; then
RUBY_CONFIGURE_OPTS_ARRAY=("${EXTRA_ARGUMENTS[@]}")
fi
case "$EARLY_EXIT" in
help )
version
echo
usage 0
;;
version | list_definitions | list_maintained_versions )
"$EARLY_EXIT"
exit 0
;;
usage_error )
echo >&2
usage 1 >&2
;;
'' )
;;
* )
echo "unimplemented EARLY_EXIT: $EARLY_EXIT" >&2
exit 1
;;
esac
# expand the <definition> argument to full path of the definition file
if [ ! -f "$DEFINITION_PATH" ]; then
for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do
if [ -f "${DEFINITION_DIR}/${DEFINITION_PATH}" ]; then
DEFINITION_PATH="${DEFINITION_DIR}/${DEFINITION_PATH}"
break
fi
done
if [ ! -f "$DEFINITION_PATH" ]; then
echo "ruby-build: definition not found: ${DEFINITION_PATH}" >&2
exit 2
fi
fi
# normalize the <prefix> argument
if [ "${PREFIX_PATH#/}" = "$PREFIX_PATH" ]; then
PREFIX_PATH="${PWD}/${PREFIX_PATH}"
fi
if [ -z "$TMPDIR" ]; then
TMP="/tmp"
else
TMP="${TMPDIR%/}"
fi
# Check if TMPDIR is accessible and can hold executables.
tmp_executable="${TMP}/ruby-build-test.$$"
noexec=""
if mkdir -p "$TMP" && touch "$tmp_executable" 2>/dev/null; then
cat > "$tmp_executable" <<-EOF
#!${BASH}
exit 0
EOF
chmod +x "$tmp_executable"
else
echo "ruby-build: TMPDIR=$TMP is set to a non-accessible location" >&2
exit 1
fi
"$tmp_executable" 2>/dev/null || noexec=1
rm -f "$tmp_executable"
if [ -n "$noexec" ]; then
echo "ruby-build: TMPDIR=$TMP cannot hold executables (partition possibly mounted with \`noexec\`)" >&2
exit 1
fi
if [ -z "$MAKE" ]; then
if is_freebsd && [[ ${ARGUMENTS[0]} == jruby-* ]]; then
# jruby-launcher requires gmake: https://github.com/ruby/ruby/pull/8591
export MAKE="gmake"
else
export MAKE="make"
fi
fi
if [ -n "$RUBY_BUILD_CACHE_PATH" ] && [ -d "$RUBY_BUILD_CACHE_PATH" ]; then
RUBY_BUILD_CACHE_PATH="${RUBY_BUILD_CACHE_PATH%/}"
else
unset RUBY_BUILD_CACHE_PATH
fi
if [ -z "$RUBY_BUILD_MIRROR_URL" ] && [ -z "$RUBY_BUILD_MIRROR_PACKAGE_URL" ]; then
RUBY_BUILD_MIRROR_URL="https://dqw8nmjcqpjn7.cloudfront.net"
RUBY_BUILD_DEFAULT_MIRROR=1
else
RUBY_BUILD_MIRROR_URL="${RUBY_BUILD_MIRROR_URL%/}"
RUBY_BUILD_DEFAULT_MIRROR=
fi
if [ -n "$RUBY_BUILD_SKIP_MIRROR" ] || ! has_checksum_support compute_sha2; then
unset RUBY_BUILD_MIRROR_URL RUBY_BUILD_MIRROR_PACKAGE_URL
fi
ARIA2_OPTS="${RUBY_BUILD_ARIA2_OPTS} ${IPV4+--disable-ipv6=true} ${IPV6+--disable-ipv6=false}"
CURL_OPTS="${RUBY_BUILD_CURL_OPTS} ${IPV4+--ipv4} ${IPV6+--ipv6}"
WGET_OPTS="${RUBY_BUILD_WGET_OPTS} ${IPV4+--inet4-only} ${IPV6+--inet6-only}"
SEED="$(date "+%Y%m%d%H%M%S").$$"
LOG_PATH="${TMP}/ruby-build.${SEED}.log"
RUBY_BIN="${PREFIX_PATH}/bin/ruby"
if [ -z "$RUBY_BUILD_BUILD_PATH" ]; then
BUILD_PATH="$(mktemp -d "${LOG_PATH%.log}.XXXXXX")"
else
BUILD_PATH="$RUBY_BUILD_BUILD_PATH"
fi
if [ -n "$VERBOSE" ]; then
# open the original stdout at fd 4
exec 4<&1
else
# open the log file at fd 4
exec 4<> "$LOG_PATH"
fi
unset RUBYOPT
unset RUBYLIB
trap build_failed ERR
mkdir -p "$BUILD_PATH"
# shellcheck disable=SC1090
source "$DEFINITION_PATH"
[ -z "${KEEP_BUILD_PATH}" ] && rm -fr "$BUILD_PATH"
trap - ERR