From e4ed6669c49f19a0751d0c038dd04646f87e7594 Mon Sep 17 00:00:00 2001 From: gru Date: Thu, 9 Apr 2026 09:08:43 +0200 Subject: [PATCH] Update install-ruby-rvm.sh --- install-ruby-rvm.sh | 372 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 312 insertions(+), 60 deletions(-) diff --git a/install-ruby-rvm.sh b/install-ruby-rvm.sh index b6dea27..6a84029 100644 --- a/install-ruby-rvm.sh +++ b/install-ruby-rvm.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Recompile Openssl 1.1.1w on RHEL9+ and install Old Rubies -# Mateusz GruszczyƄski @linuxiarz.pl +# Recompile OpenSSL 1.1.1w on RHEL9+ and install old Rubies +# Mateusz GruszczyƄski @liuxiarz.pl set -eo pipefail @@ -8,25 +8,111 @@ OPENSSL_VERSION="1.1.1w" OPENSSL_PREFIX="/opt/openssl111" SRC_DIR="/usr/local/src" -if [ "${EUID}" -ne 0 ]; then - echo "ERROR: run this script as root" - exit 1 -fi +FORCE_OPENSSL=0 +WEB_PROXY="" +TARGET_RUBY_VERSION="" -if [ $# -ne 1 ]; then - echo "Usage: $0 2.7.X" - exit 1 -fi +usage() { + cat <&2 exit 1 -fi +} + +log() { + echo "$*" +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +package_installed() { + local pkg="$1" + + rpm -q "${pkg}" >/dev/null 2>&1 && return 0 + rpm -q --whatprovides "${pkg}" >/dev/null 2>&1 && return 0 + + return 1 +} + +parse_args() { + while [ $# -gt 0 ]; do + case "$1" in + --version) + shift + [ $# -gt 0 ] || die "--version requires a value" + [ -z "${TARGET_RUBY_VERSION}" ] || die "Ruby version already provided: ${TARGET_RUBY_VERSION}" + TARGET_RUBY_VERSION="$1" + ;; + --force-openssl) + FORCE_OPENSSL=1 + ;; + --webproxy) + shift + [ $# -gt 0 ] || die "--webproxy requires a value" + WEB_PROXY="$1" + ;; + -h|--help) + usage + exit 0 + ;; + -*) + die "unknown option: $1" + ;; + *) + [ -z "${TARGET_RUBY_VERSION}" ] || die "Ruby version already provided: ${TARGET_RUBY_VERSION}" + TARGET_RUBY_VERSION="$1" + ;; + esac + shift + done + + [ -n "${TARGET_RUBY_VERSION}" ] || die "missing Ruby version, use --version 2.7.X" + + if [[ ! "${TARGET_RUBY_VERSION}" =~ ^2\.7\.[0-9]+$ ]]; then + die "only Ruby 2.7.X is allowed, e.g. 2.7.9" + fi +} + +apply_proxy_env() { + if [ -n "${WEB_PROXY}" ]; then + export http_proxy="${WEB_PROXY}" + export https_proxy="${WEB_PROXY}" + export ftp_proxy="${WEB_PROXY}" + export all_proxy="${WEB_PROXY}" + + export HTTP_PROXY="${WEB_PROXY}" + export HTTPS_PROXY="${WEB_PROXY}" + export FTP_PROXY="${WEB_PROXY}" + export ALL_PROXY="${WEB_PROXY}" + + log "Using web proxy: ${WEB_PROXY}" + fi +} load_rvm() { + export rvm_silence_path_mismatch_check_flag=1 + if [ -s /etc/profile.d/rvm.sh ]; then . /etc/profile.d/rvm.sh elif [ -s /usr/local/rvm/scripts/rvm ]; then @@ -34,27 +120,97 @@ load_rvm() { elif [ -s /root/.rvm/scripts/rvm ]; then . /root/.rvm/scripts/rvm else - echo "ERROR: RVM was not found" - exit 1 + die "RVM was not found" fi if ! command -v rvm >/dev/null 2>&1; then - echo "ERROR: RVM is not available in this shell" - exit 1 + die "RVM is not available in this shell" fi } -ruby_already_installed() { - if command -v ruby >/dev/null 2>&1; then - current_ruby_version="$(ruby -e 'print RUBY_VERSION' 2>/dev/null || true)" - if [ "${current_ruby_version}" = "${RUBY_VERSION}" ]; then - echo "Ruby ${RUBY_VERSION} is already available in PATH" - return 0 +download_file() { + local url="$1" + local output="$2" + + if command_exists wget; then + if [ -n "${WEB_PROXY}" ]; then + wget \ + -e use_proxy=yes \ + -e "http_proxy=${WEB_PROXY}" \ + -e "https_proxy=${WEB_PROXY}" \ + -O "${output}" \ + "${url}" + else + wget -O "${output}" "${url}" fi + return fi - if rvm list strings | grep -Fxq "ruby-${RUBY_VERSION}"; then - echo "Ruby ${RUBY_VERSION} is already installed in RVM" + if command_exists curl; then + if [ -n "${WEB_PROXY}" ]; then + curl --proxy "${WEB_PROXY}" -fL -o "${output}" "${url}" + else + curl -fL -o "${output}" "${url}" + fi + return + fi + + die "neither wget nor curl is available" +} + +openssl_installation_ok() { + local openssl_bin="${OPENSSL_PREFIX}/bin/openssl" + local version_output + + [ -x "${openssl_bin}" ] || return 1 + [ -d "${OPENSSL_PREFIX}/include/openssl" ] || return 1 + [ -f "${OPENSSL_PREFIX}/lib/libssl.so" ] || [ -f "${OPENSSL_PREFIX}/lib64/libssl.so" ] || return 1 + [ -f "${OPENSSL_PREFIX}/lib/libcrypto.so" ] || [ -f "${OPENSSL_PREFIX}/lib64/libcrypto.so" ] || return 1 + + version_output="$( + LD_LIBRARY_PATH="${OPENSSL_PREFIX}/lib:${OPENSSL_PREFIX}/lib64:${LD_LIBRARY_PATH:-}" \ + "${openssl_bin}" version 2>/dev/null || true + )" + + [[ "${version_output}" == OpenSSL\ ${OPENSSL_VERSION}* ]] +} + +ruby_in_path_ok() { + local ruby_version openssl_version + + command_exists ruby || return 1 + + ruby_version="$(ruby -e 'print RUBY_VERSION' 2>/dev/null || true)" + [ "${ruby_version}" = "${TARGET_RUBY_VERSION}" ] || return 1 + + openssl_version="$(ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION' 2>/dev/null || true)" + [[ "${openssl_version}" == OpenSSL\ ${OPENSSL_VERSION}* ]] +} + +ruby_in_rvm_present() { + rvm list strings | grep -Fxq "ruby-${TARGET_RUBY_VERSION}" +} + +ruby_in_rvm_ok() { + local ruby_version openssl_version + + ruby_in_rvm_present || return 1 + + ruby_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -e 'print RUBY_VERSION' 2>/dev/null || true)" + [ "${ruby_version}" = "${TARGET_RUBY_VERSION}" ] || return 1 + + openssl_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION' 2>/dev/null || true)" + [[ "${openssl_version}" == OpenSSL\ ${OPENSSL_VERSION}* ]] +} + +ruby_already_installed() { + if ruby_in_rvm_ok; then + log "Ruby ${TARGET_RUBY_VERSION} is already installed in RVM and linked with OpenSSL ${OPENSSL_VERSION}" + return 0 + fi + + if ruby_in_path_ok; then + log "Ruby ${TARGET_RUBY_VERSION} is already available in PATH and linked with OpenSSL ${OPENSSL_VERSION}" return 0 fi @@ -62,29 +218,86 @@ ruby_already_installed() { } install_build_dependencies() { - echo "[1/6] Installing build dependencies" - dnf groupinstall -y "Development Tools" - dnf install -y \ - curl tar xz bzip2 git perl-core pkgconfig \ - zlib-devel readline-devel libyaml-devel libffi-devel \ - gdbm-devel ncurses-devel gmp-devel autoconf automake libtool bison + log "[1/6] Checking build dependencies" + + local missing_packages=() + local packages=( + curl + wget + tar + xz + bzip2 + git + perl-core + pkgconfig + zlib-devel + readline-devel + libyaml-devel + libffi-devel + gdbm-devel + ncurses-devel + gmp-devel + autoconf + automake + libtool + bison + ) + + local pkg + for pkg in "${packages[@]}"; do + if ! package_installed "${pkg}"; then + missing_packages+=("${pkg}") + fi + done + + local need_devtools=0 + if ! command_exists gcc || ! command_exists g++ || ! command_exists make; then + need_devtools=1 + fi + + if [ "${need_devtools}" -eq 0 ] && [ "${#missing_packages[@]}" -eq 0 ]; then + log "All required build dependencies are already installed" + return 0 + fi + + if [ "${need_devtools}" -eq 1 ]; then + log "Installing missing group: Development Tools" + dnf groupinstall -y "Development Tools" + fi + + if [ "${#missing_packages[@]}" -gt 0 ]; then + log "Installing missing packages: ${missing_packages[*]}" + dnf install -y "${missing_packages[@]}" + fi } install_openssl() { - echo "[2/6] Preparing OpenSSL ${OPENSSL_VERSION}" + local tarball="openssl-${OPENSSL_VERSION}.tar.gz" + local srcdir="openssl-${OPENSSL_VERSION}" + local url="https://www.openssl.org/source/old/1.1.1/${tarball}" + + if [ "${FORCE_OPENSSL}" -eq 0 ] && openssl_installation_ok; then + log "[2/6] OpenSSL ${OPENSSL_VERSION} already exists and works in ${OPENSSL_PREFIX}, skipping" + return 0 + fi + + log "[2/6] Preparing OpenSSL ${OPENSSL_VERSION}" mkdir -p "${SRC_DIR}" mkdir -p "${OPENSSL_PREFIX}" cd "${SRC_DIR}" - if [ ! -f "openssl-${OPENSSL_VERSION}.tar.gz" ]; then - curl -fLO "https://www.openssl.org/source/old/1.1.1/openssl-${OPENSSL_VERSION}.tar.gz" + if [ ! -f "${tarball}" ] || [ "${FORCE_OPENSSL}" -eq 1 ]; then + rm -f "${tarball}" + download_file "${url}" "${tarball}" + else + log "Using existing source archive: ${SRC_DIR}/${tarball}" fi - rm -rf "openssl-${OPENSSL_VERSION}" - tar xf "openssl-${OPENSSL_VERSION}.tar.gz" - cd "openssl-${OPENSSL_VERSION}" + rm -rf "${srcdir}" + tar xf "${tarball}" + cd "${srcdir}" - echo "[3/6] Building OpenSSL into ${OPENSSL_PREFIX}" + log "[3/6] Building OpenSSL into ${OPENSSL_PREFIX}" ./config \ --prefix="${OPENSSL_PREFIX}" \ --openssldir="${OPENSSL_PREFIX}" \ @@ -93,41 +306,80 @@ install_openssl() { make -j"$(nproc)" rm -rf "${OPENSSL_PREFIX:?}/"* make install_sw + + openssl_installation_ok || die "OpenSSL ${OPENSSL_VERSION} verification failed after build" } install_ruby_with_rvm() { - echo "[4/6] Configuring RVM build environment" + local -a rvm_args + local action="install" + + log "[4/6] Configuring RVM build environment" rvm autolibs disable export CPPFLAGS="-I${OPENSSL_PREFIX}/include" export CFLAGS="-I${OPENSSL_PREFIX}/include" - export LDFLAGS="-L${OPENSSL_PREFIX}/lib -Wl,-rpath,${OPENSSL_PREFIX}/lib" - export PKG_CONFIG_PATH="${OPENSSL_PREFIX}/lib/pkgconfig" + export LDFLAGS="-L${OPENSSL_PREFIX}/lib -L${OPENSSL_PREFIX}/lib64 -Wl,-rpath,${OPENSSL_PREFIX}/lib -Wl,-rpath,${OPENSSL_PREFIX}/lib64" + export PKG_CONFIG_PATH="${OPENSSL_PREFIX}/lib/pkgconfig:${OPENSSL_PREFIX}/lib64/pkgconfig" export RUBY_CONFIGURE_OPTS="--with-openssl-dir=${OPENSSL_PREFIX}" - echo "[5/6] Installing Ruby ${RUBY_VERSION} with RVM" - rvm install "${RUBY_VERSION}" --with-openssl-dir="${OPENSSL_PREFIX}" + if ruby_in_rvm_present; then + action="reinstall" + fi + + rvm_args=("${action}" "${TARGET_RUBY_VERSION}" "--with-openssl-dir=${OPENSSL_PREFIX}") + + if [ -n "${WEB_PROXY}" ]; then + rvm_args+=("--proxy" "${WEB_PROXY}") + fi + + log "[5/6] ${action^}ing Ruby ${TARGET_RUBY_VERSION} with RVM" + rvm "${rvm_args[@]}" } verify_installation() { - echo "[6/6] Verifying installation" - rvm use "${RUBY_VERSION}" >/dev/null + log "[6/6] Verifying installation" - installed_ruby_version="$(ruby -e 'print RUBY_VERSION')" - installed_openssl_version="$(ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION')" + local installed_ruby_version installed_openssl_version - echo "Installed Ruby version: ${installed_ruby_version}" - echo "Linked OpenSSL version: ${installed_openssl_version}" + if ruby_in_rvm_ok; then + installed_ruby_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -e 'print RUBY_VERSION')" + installed_openssl_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION')" + elif ruby_in_path_ok; then + installed_ruby_version="$(ruby -e 'print RUBY_VERSION')" + installed_openssl_version="$(ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION')" + else + die "Ruby ${TARGET_RUBY_VERSION} verification failed" + fi + + log "Installed Ruby version: ${installed_ruby_version}" + log "Linked OpenSSL version: ${installed_openssl_version}" } -load_rvm +main() { + [ "${EUID}" -eq 0 ] || die "run this script as root" -if ruby_already_installed; then - echo "Nothing to do" - exit 0 -fi + parse_args "$@" + log "Requested Ruby version: ${TARGET_RUBY_VERSION}" + apply_proxy_env + load_rvm -install_build_dependencies -install_openssl -install_ruby_with_rvm -verify_installation \ No newline at end of file + if ruby_already_installed; then + log "Nothing to do" + exit 0 + fi + + install_build_dependencies + install_openssl + + if ruby_already_installed; then + log "Ruby is already installed after OpenSSL verification/build, skipping RVM build" + verify_installation + exit 0 + fi + + install_ruby_with_rvm + verify_installation +} + +main "$@" \ No newline at end of file