-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
#!/usr/bin/env bash | ||
# vim: ft=bash | ||
# | ||
# @uthor Konstantin Gredeskoul | ||
# @project Bashmatic | ||
# @repo https://github.com/kigster/bashmatic | ||
# | ||
# This script installs Ruby with Jemalloc, YJIT and OpenSSL bindings. | ||
# The version of ruby is read from .ruby-version file in the current | ||
# directory, any directory above the current, or the version can be | ||
# passed as an argument, eg: | ||
# | ||
# @example Passing via arguments | ||
# ruby-install [ -f | --force ] 3.3.5 | ||
# | ||
# @example Reading .ruby-version | ||
# echo '3.3.5' > .ruby-version | ||
# ruby-install [ -f | --force ] | ||
# | ||
# @description | ||
# By the default, the installer will skip existing installations | ||
# with the same ruby version. If you pass -f or --force, however, | ||
# any existing installation will be entirely replaced. | ||
|
||
# We'll be catching $? manually, so for now turn off automatic erroring. | ||
set +e | ||
|
||
export ruby_version_file_path=.ruby-version | ||
export ruby_version_from_file= | ||
export project_dir="$(pwd -P)" | ||
export current_dir="${project_dir}" | ||
export osname="$(uname -s | tr '[:upper:]' '[:lower:]')" | ||
export rbenv_force_reinstall=false | ||
export option_quiet=false | ||
|
||
if [[ "$*" =~ -f|--force ]]; then | ||
export rbenv_force_reinstall=true | ||
fi | ||
|
||
if [[ "$*" =~ -q|--quiet ]]; then | ||
export option_quiet=true | ||
fi | ||
|
||
# ┌────────────────────────────────────────────────────────────────────────┐ | ||
# │ Helper Functions │ | ||
# └────────────────────────────────────────────────────────────────────────┘ | ||
log.arrows() { | ||
printf "❯❯❯ " | ||
} | ||
|
||
log.ts() { | ||
printf '%10.10s %10.10s' $(date '+%Y-%m-%d %T%P') | ||
} | ||
|
||
log.info() { | ||
local line="$*" | ||
printf "\e[7;34m %s | INFO \e[0;34m ${line:0:70} \e[0m\n" "$(log.ts)" | ||
} | ||
|
||
log.question() { | ||
local line="$*" | ||
printf "\e[7;35m %s | INPUT \e[0;35m ${line:0:70}\e[0m\e[1;33m " "$(log.ts)" | ||
} | ||
|
||
log.warn() { | ||
local line="$*" | ||
printf "\e[7;33m %s | WARN \e[0;33m ${line:0:70} \e[0m\n" "$(log.ts)" | ||
} | ||
|
||
log.error() { | ||
local line="$*" | ||
printf "\e[7;31m %s | ERROR \e[0;31m ${line:0:70} \e[0m\n" "$(log.ts)" | ||
} | ||
|
||
is.a-function () { | ||
if [[ -n $1 ]] && typeset -f "$1" > /dev/null 2>&1; then | ||
return 0; | ||
else | ||
return 1; | ||
fi | ||
} | ||
|
||
# ┌────────────────────────────────────────────────────────────────────────┐ | ||
# │ Ruby Validations │ | ||
# └────────────────────────────────────────────────────────────────────────┘ | ||
function ruby.version-valid() { | ||
local rv="${1:-${ruby_version}}" | ||
|
||
[[ ${rv} =~ ^([0-9]\.[0-9]+\.[0-9]+)$ ]] | ||
} | ||
|
||
# @description | ||
# This is perhaps the main function that attempts to guess which version | ||
# we should be installing, assuming one wasn't provided as an CLI argument. | ||
# The functions scans the current and all of the parent directories for | ||
# the file .ruby-version | ||
function ruby.detect-version() { | ||
while true; do | ||
if [[ "$1" =~ -f|--force|-q|--quiet ]]; then | ||
shift | ||
else | ||
break | ||
fi | ||
done | ||
|
||
local rv="${1}" | ||
|
||
ruby.version-valid "${rv}" && { | ||
log.info "Using Ruby Version passed as an argument:" | ||
log.info " * Ruby v${rv}" | ||
export ruby_version="$rv" | ||
return 0 | ||
} | ||
|
||
# otherwise seed .ruby-version in this and all parent folders | ||
|
||
while true; do | ||
if [[ -s "${current_dir}/${ruby_version_file_path}" ]]; then | ||
export ruby_version_from_file="$(/usr/bin/cat "${current_dir}/${ruby_version_file_path}" | tr -d '\n')" | ||
|
||
ruby.version-valid "${ruby_version_from_file}" && { | ||
log.info "Found file ${ruby_version_file_path} in" | ||
log.info "$(log.arrows)\e[1;31m${current_dir}" | ||
export ruby_version="${ruby_version_from_file}" | ||
break | ||
} | ||
fi | ||
|
||
# Otherwise try the folder above | ||
current_dir="$(dirname "${current_dir}")" | ||
[[ ${current_dir} == "/" ]] && break | ||
done | ||
|
||
if [[ -z ${ruby_version} ]]; then | ||
log.error "Can't find ${ruby_version_file_path} locally or in parent folders." | ||
log.error "Nor was ruby-version passed as an argument." | ||
echo | ||
log.warn "$(log.arrows) Please manually enter the desired Ruby Version:" | ||
log.question "What version should we install?" | ||
read ruby_version | ||
fi | ||
printf "\e[0m\n" | ||
|
||
if ruby.version-valid "${ruby_version}"; then | ||
log.info "Ruby Version to be installed is: \e[1;31m${ruby_version}" | ||
else | ||
log.error " Unable to detect ruby version, either from STDIN, .ruby-version file, etc." | ||
exit 1 | ||
fi | ||
} | ||
|
||
function ruby.begin-install() { | ||
ruby.version-valid "${ruby_version}" || { | ||
log.error "Can not install Ruby with invalid version." | ||
log.error "Detected version [v${ruby_version}]" | ||
exit 1 | ||
} | ||
|
||
log.info "OS detected: \033[1;31m${osname}" | ||
|
||
if ${rbenv_force_reinstall}; then | ||
log.warn "Force-installing version ${ruby_version} due to --force flag." | ||
else | ||
echo | ||
read -n 1 -s -r -p "Press any key to continue with the installation, or [Ctrl-C] to abort." | ||
echo; echo | ||
fi | ||
|
||
if ruby.version-valid "${ruby_version}"; then | ||
log.info "Starting installation of Ruby v${ruby_version}..." | ||
fi | ||
} | ||
|
||
# ┌────────────────────────────────────────────────────────────────────────┐ | ||
# │ Installation │ | ||
# └────────────────────────────────────────────────────────────────────────┘ | ||
# | ||
# @description Actually install Ruby, invoking OS-specific pre-install configurations. | ||
function ruby.install() { | ||
local version="$1" | ||
|
||
export ruby_version="${version}" | ||
|
||
ruby.begin-install | ||
|
||
local pre_install_function="ruby.pre-install-${osname}" | ||
if is.a-function "${pre_install_function}"; then | ||
${pre_install_function} ${version} | ||
fi | ||
|
||
local time_begin=$(date '+%s') | ||
|
||
# Build Ruby while enabling YJIT and JEMALLOC | ||
# Construct CLI flags for rbenv inst | ||
local extra_flags= | ||
if ${rbenv_force_reinstall}; then | ||
extra_flags="${extra_flags} --force" | ||
else | ||
extra_flags="${extra_flags} --skip-existing" | ||
fi | ||
|
||
if [[ ${option_quiet} == "false" ]]; then | ||
extra_flags="${extra_flags} --verbose" | ||
fi | ||
|
||
${option_quiet} && log.warn "Building Ruby ${version}, please wait..." | ||
${option_quiet} || log.warn "Building Ruby ${version} in verbose mode:" | ||
|
||
# Use up to 8 cores to compile ruby | ||
[[ -n ${RUBY_MAKE_OPTS} ]] || export RUBY_MAKE_OPTS="-j 8" | ||
|
||
rbenv install ${extra_flags} ${version} | ||
|
||
local time_finish=$(date '+%s') | ||
local duration=$(( time_begin - time_finish )) | ||
log.info "Ruby v${version} has been built in ${duration} seconds." | ||
|
||
set -e | ||
rbenv local ${version} | ||
export RUBY_YJIT_ENABLE=1 | ||
log.info "Ruby Interpreter:" | ||
log.warn " $(log.arrows)$(ruby -v)" | ||
} | ||
|
||
function ruby.pre-install-darwin() { | ||
local version="$1" | ||
|
||
log.info "ruby.pre-install-darwin()" | ||
|
||
if command -v brew >/dev/null; then | ||
echo "Found brew located at $(command -v brew)" | ||
else | ||
echo "Please install homebrew, by following instructions here:" | ||
echo "https://brew.sh" | ||
exit 1 | ||
fi | ||
|
||
set -x | ||
|
||
brew update && brew upgrade rbenv ruby-build || true | ||
brew install jemalloc rust openssl@3 | ||
|
||
export RUBY_CFLAGS="-Wno-error=implicit-function-declaration" | ||
export CPPFLAGS="-I$HOMEBREW_PREFIX/opt/jemalloc/include" | ||
export LDFLAGS="-L$HOMEBREW_PREFIX/opt/jemalloc/lib" | ||
export RUBY_CONFIGURE_OPTS="--enable-yjit --with-jemalloc" | ||
|
||
local openssl_dir=/opt/homebrew/opt/openssl | ||
if [[ -d ${openssl_dir} ]]; then | ||
export RUBY_CONFIGURE_OPTS="${RUBY_CONFIGURE_OPTS} --with-openssl-dir=${openssl_dir}" | ||
fi | ||
set +x | ||
} | ||
|
||
function ruby.pre-install-linux() { | ||
local version="$1" | ||
log.info "ruby.pre-install-linux()" | ||
|
||
set -x | ||
sudo apt-get install libjemalloc2 rustc | ||
export RUBY_CONFIGURE_OPTS="--enable-yjit --with-jemalloc --with-openssl" | ||
set +x | ||
} | ||
|
||
# sets ${ruby_version} | ||
ruby.detect-version "$@" | ||
ruby.install "${ruby_version}" |