pax_global_header00006660000000000000000000000064136407535740014530gustar00rootroot0000000000000052 comment=ba9c14f852966b5a6ff3d262cb8ec1f5cf14c575 ruby-build-20200401/000077500000000000000000000000001364075357400140405ustar00rootroot00000000000000ruby-build-20200401/.github/000077500000000000000000000000001364075357400154005ustar00rootroot00000000000000ruby-build-20200401/.github/workflows/000077500000000000000000000000001364075357400174355ustar00rootroot00000000000000ruby-build-20200401/.github/workflows/release.yml000066400000000000000000000005551364075357400216050ustar00rootroot00000000000000name: Release on: push: tags: 'v*' jobs: homebrew: name: Bump Homebrew formula runs-on: ubuntu-latest steps: - uses: mislav/bump-homebrew-formula-action@v1.4 if: "!contains(github.ref, '-')" # skip prereleases with: formula-name: ruby-build env: COMMITTER_TOKEN: ${{ secrets.COMMITTER_TOKEN }} ruby-build-20200401/.gitignore000066400000000000000000000000061364075357400160240ustar00rootroot00000000000000/bats ruby-build-20200401/.travis.yml000066400000000000000000000007601364075357400161540ustar00rootroot00000000000000sudo: false os: - osx - linux install: git clone --depth 1 https://github.com/sstephenson/bats.git script: PATH="./bats/bin:$PATH" script/test language: c notifications: email: on_success: never env: global: - AMAZON_S3_BUCKET=ruby-build-mirror - AMAZON_ACCESS_KEY_ID=AKIAJKAUQVHU6X4CODDQ - secure: LTSvDP2o72nbECDwWsfwnsiETF4VpqrYN3y/ve68AZIMzfNWDB5vhqzMLU1ltFnSNxd71gTCGX2OEcsxdrfnG+Msu52v8FtJ7lz/b9xn83gGYrGnmEMzARtd1fnuzlWQh/1eNL9jrNl8FDhgjoTqKl2gF6fZBsQxcHRnvRSXcqE= ruby-build-20200401/CONDUCT.md000066400000000000000000000064761364075357400154760ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting one of the project maintainers listed below. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Project Maintainers * Sam Stephenson <> * Mislav Marohnić <> * Erik Michaels-Ober <> ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ruby-build-20200401/LICENSE000066400000000000000000000020471364075357400150500ustar00rootroot00000000000000Copyright (c) 2012-2013 Sam Stephenson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-build-20200401/README.md000066400000000000000000000164611364075357400153270ustar00rootroot00000000000000# ruby-build ruby-build is a command-line utility that makes it easy to install virtually any version of Ruby, from source. It is available as a plugin for [rbenv][] that provides the `rbenv install` command, or as a standalone program. ## Installation ```sh # Using Homebrew on macOS $ brew install ruby-build # As an rbenv plugin $ mkdir -p "$(rbenv root)"/plugins $ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build # As a standalone program $ git clone https://github.com/rbenv/ruby-build.git $ PREFIX=/usr/local ./ruby-build/install.sh ``` ### Upgrading ```sh # Via Homebrew $ brew update && brew upgrade ruby-build # As an rbenv plugin $ git -C "$(rbenv root)"/plugins/ruby-build pull ``` ## Usage ### Basic Usage ```sh # As an rbenv plugin $ rbenv install --list # lists all available versions of Ruby $ rbenv install 2.2.0 # installs Ruby 2.2.0 to ~/.rbenv/versions # As a standalone program $ ruby-build --definitions # lists all available versions of Ruby $ ruby-build 2.2.0 ~/local/ruby-2.2.0 # installs Ruby 2.2.0 to ~/local/ruby-2.2.0 ``` ruby-build does not check for system dependencies before downloading and attempting to compile the Ruby source. Please ensure that [all requisite libraries][build-env] are available on your system. ### Advanced Usage #### Custom Build Definitions If you wish to develop and install a version of Ruby that is not yet supported by ruby-build, you may specify the path to a custom “build definition file” in place of a Ruby version number. Use the [default build definitions][definitions] as a template for your custom definitions. #### Custom Build Configuration The build process may be configured through the following environment variables: | Variable | Function | | ------------------------ | ------------------------------------------------------------------------------------------------ | | `TMPDIR` | Where temporary files are stored. | | `RUBY_BUILD_BUILD_PATH` | Where sources are downloaded and built. (Default: a timestamped subdirectory of `TMPDIR`) | | `RUBY_BUILD_CACHE_PATH` | Where to cache downloaded package files. (Default: `~/.rbenv/cache` if invoked as rbenv plugin) | | `RUBY_BUILD_HTTP_CLIENT` | One of `aria2c`, `curl`, or `wget` to use for downloading. (Default: first one found in PATH) | | `RUBY_BUILD_ARIA2_OPTS` | Additional options to pass to `aria2c` for downloading. | | `RUBY_BUILD_CURL_OPTS` | Additional options to pass to `curl` for downloading. | | `RUBY_BUILD_WGET_OPTS` | Additional options to pass to `wget` for downloading. | | `RUBY_BUILD_MIRROR_URL` | Custom mirror URL root. | | `RUBY_BUILD_SKIP_MIRROR` | Bypass the download mirror and fetch all package files from their original URLs. | | `RUBY_BUILD_ROOT` | Custom build definition directory. (Default: `share/ruby-build`) | | `RUBY_BUILD_DEFINITIONS` | Additional paths to search for build definitions. (Colon-separated list) | | `CC` | Path to the C compiler. | | `RUBY_CFLAGS` | Additional `CFLAGS` options (_e.g.,_ to override `-O3`). | | `CONFIGURE_OPTS` | Additional `./configure` options. | | `MAKE` | Custom `make` command (_e.g.,_ `gmake`). | | `MAKE_OPTS` / `MAKEOPTS` | Additional `make` options. | | `MAKE_INSTALL_OPTS` | Additional `make install` options. | | `RUBY_CONFIGURE_OPTS` | Additional `./configure` options (applies only to Ruby source). | | `RUBY_MAKE_OPTS` | Additional `make` options (applies only to Ruby source). | | `RUBY_MAKE_INSTALL_OPTS` | Additional `make install` options (applies only to Ruby source). | #### Applying Patches Both `rbenv install` and `ruby-build` support the `--patch` (`-p`) flag to apply a patch to the Ruby (/JRuby/Rubinius/TruffleRuby) source code before building. Patches are read from `STDIN`: ```sh # applying a single patch $ rbenv install --patch 1.9.3-p429 < /path/to/ruby.patch # applying a patch from HTTP $ rbenv install --patch 1.9.3-p429 < <(curl -sSL http://git.io/ruby.patch) # applying multiple patches $ cat fix1.patch fix2.patch | rbenv install --patch 1.9.3-p429 ``` #### Checksum Verification If you have the `shasum`, `openssl`, or `sha256sum` tool installed, ruby-build will automatically verify the SHA2 checksum of each downloaded package before installing it. Checksums are optional and specified as anchors on the package URL in each definition. All definitions bundled with ruby-build include checksums. #### Package Mirrors To speed up downloads, ruby-build fetches package files from a mirror hosted on Amazon CloudFront. To benefit from this, the packages must specify their checksum: ```sh # example: install_package "ruby-2.6.5" "https://ruby-lang.org/ruby-2.6.5.tgz#" ``` ruby-build will first try to fetch this package from `$RUBY_BUILD_MIRROR_URL/` (note: this is the complete URL), where `` is the checksum for the file. It will fall back to downloading the package from the original location if: - the package was not found on the mirror; - the mirror is down; - the download is corrupt, i.e. the file's checksum doesn't match; - no tool is available to calculate the checksum; or - `RUBY_BUILD_SKIP_MIRROR` is enabled. You may specify a custom mirror by setting `RUBY_BUILD_MIRROR_URL`. The default ruby-build download mirror is sponsored by [Basecamp](https://basecamp.com/). #### Keeping the build directory after installation Both `ruby-build` and `rbenv install` accept the `-k` or `--keep` flag, which tells ruby-build to keep the downloaded source after installation. This can be useful if you need to use `gdb` and `memprof` with Ruby. Source code will be kept in a parallel directory tree `~/.rbenv/sources` when using `--keep` with the `rbenv install` command. You should specify the location of the source code with the `RUBY_BUILD_BUILD_PATH` environment variable when using `--keep` with `ruby-build`. ## Getting Help Please see the [ruby-build wiki][wiki] for solutions to common problems. If you can't find an answer on the wiki, open an issue on the [issue tracker][]. Be sure to include the full build log for build failures. [rbenv]: https://github.com/rbenv/rbenv [definitions]: https://github.com/rbenv/ruby-build/tree/master/share/ruby-build [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 ruby-build-20200401/bin/000077500000000000000000000000001364075357400146105ustar00rootroot00000000000000ruby-build-20200401/bin/rbenv-install000077500000000000000000000142651364075357400173260ustar00rootroot00000000000000#!/usr/bin/env bash # # Summary: Install a Ruby version using ruby-build # # Usage: rbenv install [-f|-s] [-kpv] # rbenv install [-f|-s] [-kpv] # rbenv install -l|--list # rbenv install --version # # -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) # -p/--patch Apply a patch from stdin before building # -v/--verbose Verbose mode: print compilation status to stdout # --version Show version of ruby-build # # For detailed information on installing Ruby versions with # ruby-build, including a list of environment variables for adjusting # compilation, see: https://github.com/rbenv/ruby-build#usage # set -e [ -n "$RBENV_DEBUG" ] && set -x # Add `share/ruby-build/` directory from each rbenv plugin to the list of # paths where build definitions are looked up. shopt -s nullglob for plugin_path in "$RBENV_ROOT"/plugins/*/share/ruby-build; do RUBY_BUILD_DEFINITIONS="${RUBY_BUILD_DEFINITIONS}:${plugin_path}" done export RUBY_BUILD_DEFINITIONS shopt -u nullglob # Provide rbenv completions if [ "$1" = "--complete" ]; then echo --list echo --force echo --skip-existing echo --keep echo --patch echo --verbose echo --version exec ruby-build --definitions fi # Load shared library functions eval "$(ruby-build --lib)" usage() { rbenv-help install 2>/dev/null [ -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" ) ruby-build --definitions 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 >&2 ;; esac 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 # version is not specified. DEFINITION="${ARGUMENTS[0]}" [ -n "$DEFINITION" ] || DEFINITION="$(rbenv-local 2>/dev/null || true)" [ -n "$DEFINITION" ] || usage 1 >&2 # 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")" here="$(dirname "${0%/*}")" if [ -n "$candidates" ]; then echo echo "The following versions contain \`$DEFINITION' in the name:" echo "$candidates" | indent fi echo echo "See all available versions with \`rbenv install --list'." echo echo -n "If the version you need is missing, try upgrading ruby-build" if [ "$here" != "${here#$(brew --prefix 2>/dev/null)}" ]; then printf ":\n\n" echo " brew update && brew upgrade ruby-build" elif [ -d "${here}/.git" ]; then printf ":\n\n" echo " git -C ${here} pull" else printf ".\n" fi } >&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" ruby-build-20200401/bin/rbenv-uninstall000077500000000000000000000031421364075357400176610ustar00rootroot00000000000000#!/usr/bin/env bash # # Summary: Uninstall a specific Ruby version # # Usage: rbenv uninstall [-f|--force] # # -f Attempt to remove the specified version without prompting # for confirmation. If the version does not exist, do not # display an error message. # # See `rbenv versions` for a complete list of installed versions. # set -e # Provide rbenv completions if [ "$1" = "--complete" ]; then echo --force exec rbenv versions --bare fi usage() { rbenv-help uninstall 2>/dev/null [ -z "$1" ] || exit "$1" } if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage 0 fi unset FORCE if [ "$1" = "-f" ] || [ "$1" = "--force" ]; then FORCE=true shift fi [ "$#" -eq 1 ] || usage 1 >&2 DEFINITION="$1" case "$DEFINITION" in "" | -* ) usage 1 >&2 ;; esac declare -a before_hooks after_hooks before_uninstall() { local hook="$1" before_hooks["${#before_hooks[@]}"]="$hook" } after_uninstall() { local hook="$1" after_hooks["${#after_hooks[@]}"]="$hook" } OLDIFS="$IFS" IFS=$'\n' scripts=(`rbenv-hooks uninstall`) IFS="$OLDIFS" for script in "${scripts[@]}"; do source "$script"; done VERSION_NAME="${DEFINITION##*/}" PREFIX="${RBENV_ROOT}/versions/${VERSION_NAME}" if [ -z "$FORCE" ]; then if [ ! -d "$PREFIX" ]; then echo "rbenv: version \`$VERSION_NAME' not installed" >&2 exit 1 fi read -p "rbenv: remove $PREFIX? [yN] " case "$REPLY" in y* | Y* ) ;; * ) exit 1 ;; esac fi for hook in "${before_hooks[@]}"; do eval "$hook"; done if [ -d "$PREFIX" ]; then rm -rf "$PREFIX" rbenv-rehash fi for hook in "${after_hooks[@]}"; do eval "$hook"; done ruby-build-20200401/bin/ruby-build000077500000000000000000001062661364075357400166270ustar00rootroot00000000000000#!/usr/bin/env bash # # Usage: ruby-build [-kpv] # 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 built-in definitions # --version Show version of ruby-build # RUBY_BUILD_VERSION="20200401" OLDIFS="$IFS" set -E exec 3<&2 # preserve original stderr at fd 3 lib() { parse_options() { OPTIONS=() ARGUMENTS=() local arg option index for arg in "$@"; do if [ "${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 else ARGUMENTS[${#ARGUMENTS[*]}]="$arg" fi done } if [ "$1" == "--$FUNCNAME" ]; then declare -f "$FUNCNAME" echo "$FUNCNAME \"\$1\";" exit fi } lib "$1" resolve_link() { $(type -p greadlink readlink | head -1) "$1" } abs_dirname() { local cwd="$(pwd)" local path="$1" while [ -n "$path" ]; do cd "${path%/*}" local name="${path##*/}" path="$(resolve_link "$name" || true)" done pwd cd "$cwd" } capitalize() { 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 } os_information() { if type -p lsb_release >/dev/null; then lsb_release -sir | xargs echo elif type -p sw_vers >/dev/null; then echo "OS X $(sw_vers -productVersion)" elif [ -r /etc/os-release ]; then source /etc/os-release echo "$NAME" $VERSION_ID else local 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)" "$@" ] } # 9.1 -> 901 # 10.9 -> 1009 # 10.10 -> 1010 osx_version() { local -a ver IFS=. ver=( `sw_vers -productVersion` ) IFS="$OLDIFS" echo $(( ${ver[0]}*100 + ${ver[1]} )) } build_failed() { { echo colorize 1 "BUILD FAILED" echo " ($(os_information) using $(version))" echo if ! rmdir "${BUILD_PATH}" 2>/dev/null; then echo "Inspect or clean up the working tree at ${BUILD_PATH}" if file_is_not_empty "$LOG_PATH"; then colorize 33 "Results logged to ${LOG_PATH}" printf "\n\n" echo "Last 10 log lines:" tail -n 10 "$LOG_PATH" fi fi } >&3 exit 1 } file_is_not_empty() { local filename="$1" local line_count="$(wc -l "$filename" 2>/dev/null || true)" if [ -n "$line_count" ]; then words=( $line_count ) [ "${words[0]}" -gt 0 ] else return 1 fi } 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_svn() { install_package_using "svn" 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 "$arg" || return 0 elif [ "$arg" != "--if" ]; then make_args["${#make_args[@]}"]="$arg" fi last_arg="$arg" done pushd "$BUILD_PATH" >&4 "fetch_${package_type}" "${fetch_args[@]}" make_package "${make_args[@]}" popd >&4 { echo "Installed ${package_name} to ${PREFIX_PATH}" echo } >&2 } make_package() { local package_name="$1" shift pushd "$package_name" >&4 before_install_package "$package_name" build_package "$package_name" $* after_install_package "$package_name" 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="$(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 printf -v "$has_checksum_var" "$(echo test | "$checksum_command" >/dev/null; echo $?)" fi return "${!has_checksum_var}" } verify_checksum() { local checksum_command local filename="$1" local expected_checksum="$(echo "$2" | tr [A-Z] [a-z])" # 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=`echo "$($checksum_command < "$filename")" | tr [A-Z] [a-z]` [ -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_${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() { aria2c --dry-run --no-conf=true ${ARIA2_OPTS} "$1" >&4 2>&1 } http_get_aria2c() { local out="${2:-$(mktemp "out.XXXXXX")}" if aria2c --allow-overwrite=true --no-conf=true -o "${out}" ${ARIA2_OPTS} "$1" >&4; then [ -n "$2" ] || cat "${out}" else false fi } http_head_curl() { curl -qsILf ${CURL_OPTS} "$1" >&4 2>&1 } http_get_curl() { curl -q -o "${2:--}" -sSLf ${CURL_OPTS} "$1" } http_head_wget() { wget -q --spider ${WGET_OPTS} "$1" >&4 2>&1 } http_get_wget() { wget -nv ${WGET_OPTS} -O "${2:--}" "$1" } fetch_tarball() { local package_name="$1" local package_url="$2" local mirror_url local checksum local extracted_dir 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 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="$(basename "$package_url")" echo "Downloading ${tarball_filename}..." >&2 http head "$mirror_url" && download_tarball "$mirror_url" "$package_filename" "$checksum" || download_tarball "$package_url" "$package_filename" "$checksum" fi { if tar $tar_args "$package_filename"; then if [ ! -d "$package_name" ]; then extracted_dir="$(find_extracted_directory)" mv "$extracted_dir" "$package_name" fi if [ -z "$KEEP_BUILD_PATH" ]; then rm -f "$package_filename" else true fi fi } >&4 2>&1 } 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" >&4 2>&1 || return 1 ln -s "$cached_package_filename" "$package_filename" >&4 2>&1 || return 1 } download_tarball() { local package_url="$1" [ -n "$package_url" ] || return 1 local package_filename="$2" local checksum="$3" echo "-> $package_url" >&2 if http get "$package_url" "$package_filename" >&4 2>&1; then verify_checksum "$package_filename" "$checksum" >&4 2>&1 || 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" } >&4 2>&1 || return 1 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 if [ -n "$RUBY_BUILD_CACHE_PATH" ]; then pushd "$RUBY_BUILD_CACHE_PATH" >&4 local clone_name="$(sanitize "$git_url")" if [ -e "${clone_name}" ]; then { cd "${clone_name}" git fetch --force "$git_url" "+${git_ref}:${git_ref}" } >&4 2>&1 else git clone --bare --branch "$git_ref" "$git_url" "${clone_name}" >&4 2>&1 fi git_url="$RUBY_BUILD_CACHE_PATH/${clone_name}" popd >&4 fi if [ -e "${package_name}" ]; then ( cd "${package_name}" git fetch --depth 1 origin "+${git_ref}" git 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 else echo "error: please install \`git\` and try again" >&2 exit 1 fi } fetch_svn() { local package_name="$1" local svn_url="$2" local svn_rev="$3" echo "Checking out ${svn_url}..." >&2 if type svn &>/dev/null; then svn co -r "$svn_rev" "$svn_url" "${package_name}" >&4 2>&1 elif type svnlite &>/dev/null; then svnlite co -r "$svn_rev" "$svn_url" "${package_name}" >&4 2>&1 else echo "error: please install Subversion and try again" >&2 exit 1 fi } build_package() { local package_name="$1" shift if [ "$#" -eq 0 ]; then local commands="standard" else local commands="$*" fi echo "Installing ${package_name}..." >&2 [ -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="$(capitalize "${package_name}_${command_name}")_OPTS_ARRAY" local array="$variable[@]" shift 2 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="$(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 use_homebrew_readline || use_freebsd_pkg ||true fi ( if [ "${CFLAGS+defined}" ] || [ "${!PACKAGE_CFLAGS+defined}" ]; then export CFLAGS="$CFLAGS ${!PACKAGE_CFLAGS}" fi if [ -z "$CC" ] && is_mac -ge 1010; then export CC=clang fi ${!PACKAGE_CONFIGURE:-./configure} --prefix="${!PACKAGE_PREFIX_PATH:-$PREFIX_PATH}" \ $CONFIGURE_OPTS ${!PACKAGE_CONFIGURE_OPTS} "${!PACKAGE_CONFIGURE_OPTS_ARRAY}" || return 1 ) >&4 2>&1 { "$MAKE" $MAKE_OPTS ${!PACKAGE_MAKE_OPTS} "${!PACKAGE_MAKE_OPTS_ARRAY}" } >&4 2>&1 } build_package_standard_install() { local package_name="$1" local 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 $MAKE_INSTALL_OPTS ${!PACKAGE_MAKE_INSTALL_OPTS} "${!PACKAGE_MAKE_INSTALL_OPTS_ARRAY}" } >&4 2>&1 } build_package_standard_install_with_bundled_gems() { { "$MAKE" update-gems "$MAKE" extract-gems } >&4 2>&1 build_package_standard_install "$@" } # Backward Compatibility for standard function build_package_standard() { build_package_standard_build "$@" build_package_standard_install "$@" } build_package_autoconf() { { autoconf } >&4 2>&1 } build_package_ruby() { local package_name="$1" { "$RUBY_BIN" setup.rb } >&4 2>&1 } build_package_ree_installer() { build_package_auto_tcltk local options="" is_mac && options="--no-tcmalloc" local option for option in $RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[@]}; do options="$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" { ./installer --auto "$PREFIX_PATH" --dont-install-useful-gems $options $CONFIGURE_OPTS } >&4 2>&1 } 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 RUBYOPT="-rrubygems $RUBYOPT" ./configure --prefix="$PREFIX_PATH" $RUBY_CONFIGURE_OPTS "${configure_opts[@]}" rake install fix_rbx_gem_binstubs "$PREFIX_PATH" fix_rbx_irb "$PREFIX_PATH" } >&4 2>&1 } build_package_mruby() { { ./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" } >&4 2>&1 } build_package_maglev() { build_package_copy { cd "${PREFIX_PATH}" ./install.sh cd "${PREFIX_PATH}/bin" echo "Creating symlink for ruby*" ln -fs maglev-ruby ruby echo "Creating symlink for irb*" ln -fs maglev-irb irb } >&4 2>&1 echo echo "Run 'maglev start' to start up the stone before using 'ruby' or 'irb'" } build_package_topaz() { build_package_copy { cd "${PREFIX_PATH}/bin" echo "Creating symlink for ruby*" ln -fs topaz ruby } >&4 2>&1 } topaz_architecture() { case "$(uname -s)" in "Darwin") echo "osx64";; "Linux") [[ "$(uname -m)" = "x86_64" ]] && echo "linux64" || echo "linux32";; *) echo "no nightly builds available" >&2 exit 1;; esac } build_package_jruby() { build_package_copy cd "${PREFIX_PATH}/bin" ln -fs jruby ruby chmod +x ruby install_jruby_launcher remove_windows_files fix_jruby_shebangs } install_jruby_launcher() { cd "${PREFIX_PATH}/bin" { ./ruby gem install jruby-launcher } >&4 2>&1 } fix_jruby_shebangs() { for file in "${PREFIX_PATH}/bin"/*; do if [ "$(head -c 20 "$file")" = "#!/usr/bin/env jruby" ]; then sed -i.bak "1 s:.*:#\!${PREFIX_PATH}\/bin\/jruby:" "$file" rm "$file".bak fi done } build_package_truffleruby() { build_package_copy cd "${PREFIX_PATH}" "${PREFIX_PATH}/lib/truffle/post_install_hook.sh" } remove_windows_files() { cd "$PREFIX_PATH" rm -f bin/*.exe bin/*.dll bin/*.bat bin/jruby.sh } build_package_copy() { # Make sure there are no leftover files in $PREFIX_PATH rm -rf "$PREFIX_PATH" 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 || "${prefix}/bin/gem" install rubysl-tracer -v '~> 2.0' --no-rdoc --no-ri &>/dev/null || true } require_java() { local required="$1" local java_version="$(java -version 2>&1)" local version_string="$(grep 'java version' <<<"$java_version" | head -1 | grep -o '[0-9.]\+' || true)" [ -n "$version_string" ] || version_string="$(grep 'openjdk version' <<<"$java_version" | head -1 | grep -o '[0-9.]\+' || true)" IFS="." 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 } # keep for backwards compatibility require_java7() { require_java 7 } require_gcc() { local gcc="$(locate_gcc || true)" if [ -z "$gcc" ]; then { echo colorize 1 "ERROR" echo ": This package must be compiled with GCC, but ruby-build couldn't" echo "find a suitable \`gcc\` executable on your system. Please install GCC" echo "and try again." echo if is_mac; then colorize 1 "DETAILS" echo ": Apple no longer includes the official GCC compiler with Xcode" echo "as of version 4.2. Instead, the \`gcc\` executable is a symlink to" echo "\`llvm-gcc\`, a modified version of GCC which outputs LLVM bytecode." echo echo "For most programs the \`llvm-gcc\` compiler works fine. However," echo "versions of Ruby older than 1.9.3-p125 are incompatible with" echo "\`llvm-gcc\`. To build older versions of Ruby you must have the official" echo "GCC compiler installed on your system." echo colorize 1 "TO FIX THE PROBLEM" if type brew &>/dev/null; then echo ": Install Homebrew's GCC package with this" echo -n "command: " colorize 4 "brew install gcc@4.9" else echo ": Install the official GCC compiler using these" echo -n "packages: " colorize 4 "https://github.com/kennethreitz/osx-gcc-installer/downloads" fi echo echo echo "You will need to install the official GCC compiler to build older" echo "versions of Ruby even if you have installed Apple's Command Line Tools" echo "for Xcode package. The Command Line Tools for Xcode package only" echo "includes \`llvm-gcc\`." fi } >&3 return 1 fi export CC="$gcc" if is_mac -ge 1010; then export MACOSX_DEPLOYMENT_TARGET=10.9 fi } locate_gcc() { local gcc gccs IFS=: gccs=($(gccs_in_path)) IFS="$OLDIFS" verify_gcc "$CC" || verify_gcc "$(command -v gcc || true)" || { for gcc in "${gccs[@]}"; do verify_gcc "$gcc" && break || true done } return 1 } gccs_in_path() { local gcc path paths local gccs=() IFS=: paths=($PATH) IFS="$OLDIFS" shopt -s nullglob for path in "${paths[@]}"; do for gcc in "$path"/gcc-*; do gccs["${#gccs[@]}"]="$gcc" done done shopt -u nullglob printf :%s "${gccs[@]}" } verify_gcc() { local gcc="$1" if [ -z "$gcc" ]; then return 1 fi local version="$("$gcc" --version 2>/dev/null || true)" if [ -z "$version" ]; then return 1 fi if echo "$version" | grep LLVM >/dev/null; then return 1 fi echo "$gcc" } require_llvm() { local llvm_version="$1" if is_mac -ge 1010; then if [[ "$RUBY_CONFIGURE_OPTS" != *--llvm-* ]]; then case "$llvm_version" in 3.2 ) package_option ruby configure --prebuilt-name="llvm-3.2-x86_64-apple-darwin13.tar.bz2" ;; 3.[56] ) local llvm_config="$(locate_llvm "$llvm_version")" if [ -n "$llvm_config" ]; then package_option ruby configure --llvm-config="$llvm_config" else local homebrew_package="llvm@$llvm_version" { echo colorize 1 "ERROR" echo ": Rubinius will not be able to compile using Apple's LLVM-based " echo "build tools on OS X. You will need to install LLVM $llvm_version first." echo colorize 1 "TO FIX THE PROBLEM" echo ": Install Homebrew's llvm package with this" echo -n "command: " colorize 4 "brew install $homebrew_package" echo } >&3 return 1 fi ;; esac fi fi } locate_llvm() { local llvm_version="$1" local package llvm_config shopt -s nullglob for package in `brew list 2>/dev/null | grep "^llvm"`; do llvm_config="$(echo "$(brew --prefix "$package")/bin/llvm-config"*)" if [ -n "$llvm_config" ] && [[ "$("$llvm_config" --version)" = "$llvm_version"* ]]; then echo "$llvm_config" break fi done shopt -u nullglob } needs_yaml() { [[ "$RUBY_CONFIGURE_OPTS" != *--with-libyaml-dir=* ]] && ! use_homebrew_yaml } use_homebrew_yaml() { local libdir="$(brew --prefix libyaml 2>/dev/null || true)" if [ -d "$libdir" ]; then echo "ruby-build: using libyaml from homebrew" package_option ruby configure --with-libyaml-dir="$libdir" else return 1 fi } use_freebsd_pkg() { # check if FreeBSD if [ "FreeBSD" = "$(uname -s)" ]; then # use openssl if installed from Ports Collection if [ -f /usr/local/include/openssl/ssl.h ]; then package_option ruby configure --with-openssl-dir="/usr/local" fi # check if 11-R or later release="$(uname -r)" if [ "${release%%.*}" -ge 11 ]; then # prefers readline to compile most of ruby versions if pkg info -e readline > /dev/null; then # use readline from Ports Collection package_option ruby configure --with-readline-dir="/usr/local" elif pkg info -e libedit > /dev/null; then # use libedit from Ports Collection package_option ruby configure --enable-libedit package_option ruby configure --with-libedit-dir="/usr/local" fi fi fi } use_homebrew_readline() { if [[ "$RUBY_CONFIGURE_OPTS" != *--with-readline-dir=* ]]; then local libdir="$(brew --prefix readline 2>/dev/null || true)" if [ -d "$libdir" ]; then echo "ruby-build: using readline from homebrew" package_option ruby configure --with-readline-dir="$libdir" else return 1 fi fi } has_broken_mac_openssl() { is_mac || return 1 local openssl_version="$(/usr/bin/openssl version 2>/dev/null || true)" [[ $openssl_version = "OpenSSL 0.9.8"?* || $openssl_version = "LibreSSL"* ]] && [[ "$RUBY_CONFIGURE_OPTS" != *--with-openssl-dir=* ]] } use_homebrew_openssl() { local ssldir="$(brew --prefix openssl@1.1 2>/dev/null || true)" if [ -d "$ssldir" ]; then echo "ruby-build: using openssl 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_mac_openssl() { # Install to a subdirectory since we don't want shims for bin/openssl. 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}" # Hint OpenSSL that we prefer a 64-bit build. export KERNEL_BITS="64" OPENSSL_CONFIGURE="${OPENSSL_CONFIGURE:-./config}" 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} # Default MAKE_OPTS are -j 2 which can confuse the build. Thankfully, make # gives precedence to the last -j option, so we can override that. package_option openssl make -j 1 build_package_standard "$@" # Extract root certs from the system keychain in .pem format and rehash. local pem_file="$OPENSSLDIR/cert.pem" security find-certificate -a -p /Library/Keychains/System.keychain > "$pem_file" security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >> "$pem_file" } # Post-install check that the openssl extension was built. build_package_verify_openssl() { "$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 $stderr.puts "The Ruby #{lib} extension was not compiled." 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 } # Ensure that directories listed in LDFLAGS exist build_package_ldflags_dirs() { local arg dir set - $LDFLAGS while [ $# -gt 0 ]; do dir="" case "$1" in -L ) dir="$2" ;; -L* ) dir="${1#-L}" ;; esac [ -z "$dir" ] || mkdir -p "$dir" shift 1 done } build_package_enable_shared() { package_option ruby configure --enable-shared } 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 case "$1" in ruby-* | jruby-* | rubinius-* | truffleruby-* ) patchfile="$(mktemp "${TMP}/ruby-patch.XXXXXX")" cat "${2:--}" >"$patchfile" local striplevel=0 grep -q '^--- a/' "$patchfile" && striplevel=1 patch -p$striplevel --force -i "$patchfile" ;; 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_definitions() { { for DEFINITION_DIR in "${RUBY_BUILD_DEFINITIONS[@]}"; do [ -d "$DEFINITION_DIR" ] && ls "$DEFINITION_DIR" done } | sort_versions | uniq } 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 RUBY_BUILD_INSTALL_PREFIX="$(abs_dirname "$0")/.." 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" ) version echo usage 0 ;; "definitions" ) list_definitions exit 0 ;; "k" | "keep" ) KEEP_BUILD_PATH=true ;; "v" | "verbose" ) VERBOSE=true ;; "p" | "patch" ) HAS_PATCH=true ;; "4" | "ipv4") IPV4=true ;; "6" | "ipv6") IPV6=true ;; "version" ) version exit 0 ;; esac done [ "${#ARGUMENTS[@]}" -eq 2 ] || usage 1 >&2 DEFINITION_PATH="${ARGUMENTS[0]}" if [ -z "$DEFINITION_PATH" ]; then usage 1 >&2 elif [ ! -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 PREFIX_PATH="${ARGUMENTS[1]}" if [ -z "$PREFIX_PATH" ]; then usage 1 >&2 elif [ "${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 # Apply following work around, if gcc is not installed. if [ -z "$(locate_gcc)" ]; then # Work around warnings building Ruby 2.0 on Clang 2.x: # pass -Wno-error=shorten-64-to-32 if the compiler accepts it. # # When we set CFLAGS, Ruby won't apply its default flags, though. Since clang # builds 1.9.x and 2.x only, where -O3 is default, we can safely set that flag. # Ensure it's the first flag since later flags take precedence. if "${CC:-cc}" -x c /dev/null -E -Wno-error=shorten-64-to-32 &>/dev/null; then RUBY_CFLAGS="-O3 -Wno-error=shorten-64-to-32 $RUBY_CFLAGS" fi fi if [ -z "$MAKE" ]; then if [ "FreeBSD" = "$(uname -s)" ]; then # Workaround for Ruby bug 16331: https://bugs.ruby-lang.org/issues/16331 # Due to this bug, build will fail with FreeBSD's make after #1368 # The bug is already fixed in upstream but GNU make is still required # when building older releases of Ruby. Use GNU make rather than switching # depending of Ruby version. 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" ]; 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 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" CWD="$(pwd)" if [ -z "$RUBY_BUILD_BUILD_PATH" ]; then BUILD_PATH="$(mktemp -d "${LOG_PATH%.log}.XXXXXX")" else BUILD_PATH="$RUBY_BUILD_BUILD_PATH" fi exec 4<> "$LOG_PATH" # open the log file at fd 4 if [ -n "$VERBOSE" ]; then tail -f "$LOG_PATH" & TAIL_PID=$! trap "kill $TAIL_PID" SIGINT SIGTERM EXIT fi export LDFLAGS="-L${PREFIX_PATH}/lib ${LDFLAGS}" export CPPFLAGS="-I${PREFIX_PATH}/include ${CPPFLAGS}" unset RUBYOPT unset RUBYLIB trap build_failed ERR mkdir -p "$BUILD_PATH" source "$DEFINITION_PATH" [ -z "${KEEP_BUILD_PATH}" ] && rm -fr "$BUILD_PATH" trap - ERR ruby-build-20200401/install.sh000077500000000000000000000005451364075357400160510ustar00rootroot00000000000000#!/bin/sh # Usage: PREFIX=/usr/local ./install.sh # # Installs ruby-build under $PREFIX. set -e cd "$(dirname "$0")" if [ -z "${PREFIX}" ]; then PREFIX="/usr/local" fi BIN_PATH="${PREFIX}/bin" SHARE_PATH="${PREFIX}/share/ruby-build" mkdir -p "$BIN_PATH" "$SHARE_PATH" install -p bin/* "$BIN_PATH" install -p -m 0644 share/ruby-build/* "$SHARE_PATH" ruby-build-20200401/script/000077500000000000000000000000001364075357400153445ustar00rootroot00000000000000ruby-build-20200401/script/mirror000077500000000000000000000044711364075357400166120ustar00rootroot00000000000000#!/usr/bin/env bash # Usage: script/mirror update # script/mirror verify # script/mirror stats set -e eval "$(grep RUBY_BUILD_MIRROR_URL= ./bin/ruby-build | head -1)" help_text() { sed -ne '/^#/!q;s/.\{1,2\}//;1d;p' < "$0" } test_mirrored() { curl -qsSfIL "$RUBY_BUILD_MIRROR_URL/$1" >/dev/null 2>&1 } compute_sha2() { local output="$(openssl dgst -sha256)" echo "${output##* }" | tr '[A-Z]' '[a-z]' } download_package() { curl -qsSfL -o "$2" "$1" } download_and_verify() { local checksum local url="$1" local file="$2" local expected="$3" download_package "$url" "$file" checksum="$(compute_sha2 < "$file")" if [ "$checksum" != "$expected" ]; then echo "Error: $url doesn't match its checksum $expected" >&2 return 1 fi } changed_files() { git diff --name-only --diff-filter=ACMR "$@" } potentially_new_packages() { local files="$(changed_files "$1" -- ./share/ruby-build)" [ -n "$files" ] && extract_urls $files } extract_urls() { $(type -p ggrep grep | head -1) -hoe 'http[^"]\+#[^"]\+' "$@" | sort | uniq } update() { local url local checksum local file for url in $(potentially_new_packages "$1"); do checksum="${url#*#}" url="${url%#*}" if test_mirrored "$checksum"; then echo "Already mirrored: $url" else echo "Mirroring: $url" file="${TMPDIR:-/tmp}/$checksum" download_and_verify "$url" "$file" "$checksum" ./script/s3-put "$file" "${AMAZON_S3_BUCKET?}" fi done } verify() { local url local checksum local file for url in $(potentially_new_packages "$1"); do checksum="${url#*#}" url="${url%#*}" echo "Verifying checksum for $url" file="${TMPDIR:-/tmp}/$checksum" download_and_verify "$url" "$file" "$checksum" done } stats() { local packages=( $(extract_urls ./share/ruby-build/*) ) local total="${#packages[@]}" local confirmed=0 local checksum for url in "${packages[@]}"; do checksum="${url#*#}" if test_mirrored "$checksum"; then confirmed="$((confirmed + 1))" else echo "failed: $url" >&2 fi echo -n "." done echo echo "$confirmed/$total mirrored" } cmd="$1" case "$cmd" in update | verify | stats ) shift 1 "$cmd" "$@" ;; -h | --help ) help_text exit 0 ;; * ) help_text >&2 exit 1 ;; esac ruby-build-20200401/script/release000077500000000000000000000027771364075357400167270ustar00rootroot00000000000000#!/usr/bin/env bash # Usage: script/release # # - checks out the master branch # - changes version in `bin/ruby-build` to current date # - commits and tags the change # - pushes master + tag to GitHub # - opens pull request to update the Homebrew formula # # TODO: handle making multiple releases on the same date set -e echo "Running hub to see if configured correctly" echo "This shows the latest release:" hub release -L1 git fetch -q --tags origin master git checkout -q master git merge --ff-only @{upstream} existing="$(git tag --points-at HEAD)" if [ -n "$existing" ]; then echo "Aborting: HEAD is already tagged as '${existing}'" >&2 exit 1 fi binfile="bin/ruby-build" new_version="$(date '+%Y%m%d')" version_tag="v${new_version}" previous_tag="$(git describe --tags HEAD --abbrev=0)" if git diff --quiet "${previous_tag}..HEAD" -- bin share; then echo "Aborting: No features to release since '${previous_tag}'" >&2 exit 1 fi sed -i.bak -E "s!^(RUBY_BUILD_VERSION=).+!\\1\"${new_version}\"!" "$binfile" rm -f "${binfile}.bak" git commit -m "ruby-build ${new_version}" -- "$binfile" notes_file="$(mktemp)" { echo "ruby-build $new_version" echo git log --no-merges --format='* %s%n%w(0,2,2)%+b' --reverse "${previous_tag}..HEAD^" -- bin share } >"$notes_file" trap "rm -f '$notes_file'" EXIT git tag "$version_tag" -F "$notes_file" --edit git push origin master "${version_tag}" git tag --list "$version_tag" --format='%(contents:subject)%0a%0a%(contents:body)' | \ hub release create -F- "$version_tag" ruby-build-20200401/script/s3-put000077500000000000000000000022771364075357400164350ustar00rootroot00000000000000#!/usr/bin/env bash # Usage: s3-put [] # # Uploads a file to the Amazon S3 service. # # Depends on AWS credentials being set via env: # - AMAZON_ACCESS_KEY_ID # - AMAZON_SECRET_ACCESS_KEY # # Outputs the URL of the newly uploaded file. set -e authorization() { local signature="$(string_to_sign | hmac_sha1 | base64)" echo "AWS ${AMAZON_ACCESS_KEY_ID?}:${signature}" } hmac_sha1() { openssl dgst -binary -sha1 -hmac "${AMAZON_SECRET_ACCESS_KEY?}" } base64() { openssl enc -base64 } bin_md5() { openssl dgst -binary -md5 } string_to_sign() { echo "$http_method" echo "$content_md5" echo "$content_type" echo "$date" echo "x-amz-acl:$acl" printf "/$bucket/$remote_path" } date_string() { LC_TIME=C date "+%a, %d %h %Y %T %z" } file="$1" bucket="$2" content_type="$3" http_method=PUT acl="public-read" remote_path="${file##*/}" content_md5="$(bin_md5 < "$file" | base64)" date="$(date_string)" url="https://$bucket.s3.amazonaws.com/$remote_path" curl -qsSf -T "$file" \ -H "Authorization: $(authorization)" \ -H "x-amz-acl: $acl" \ -H "Date: $date" \ -H "Content-MD5: $content_md5" \ -H "Content-Type: $content_type" \ "$url" echo "$url" ruby-build-20200401/script/test000077500000000000000000000004511364075357400162510ustar00rootroot00000000000000#!/usr/bin/env bash set -e STATUS=0 bats ${CI:+--tap} test || STATUS="$?" if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then ./script/mirror update "$TRAVIS_COMMIT_RANGE" elif [ "${TRAVIS_PULL_REQUEST:-false}" != "false" ]; then ./script/mirror verify "$TRAVIS_COMMIT_RANGE" fi exit "$STATUS" ruby-build-20200401/script/update-cruby000077500000000000000000000013701364075357400176770ustar00rootroot00000000000000#!/usr/bin/env bash set -e set -o pipefail if [ $# -ne 2 ]; then echo "usage: $0 VERSION RELEASE_DIRECTORY" exit 1 fi version="$1" release_directory="$2" file="share/ruby-build/${version}" basename="ruby-${version}.tar.bz2" major_minor_version=$(echo ${version} | cut -d '.' -f 1,2) url="https://cache.ruby-lang.org/pub/ruby/${major_minor_version}/${basename}" sha256=$(sha256sum "$release_directory/$basename" | cut -d ' ' -f 1) cat > "$file" < "$file" <> "$file" < "$file" <> "$file" <> "$file" < "$definition" run ruby-build "$definition" assert_failure assert_output_contains 'Usage: ruby-build' } @test "extra arguments for ruby-build" { # use empty inline definition so nothing gets built anyway local definition="${TMP}/build-definition" echo '' > "$definition" run ruby-build "$definition" "${TMP}/install" "" assert_failure assert_output_contains 'Usage: ruby-build' } ruby-build-20200401/test/build.bats000077500000000000000000000367761364075357400170170ustar00rootroot00000000000000#!/usr/bin/env bats load test_helper export RUBY_BUILD_CACHE_PATH="$TMP/cache" export MAKE=make export MAKE_OPTS="-j 2" export CC=cc export -n RUBY_CONFIGURE_OPTS setup() { mkdir -p "$INSTALL_ROOT" stub md5 false stub curl false } executable() { local file="$1" mkdir -p "${file%/*}" cat > "$file" chmod +x "$file" } cached_tarball() { mkdir -p "$RUBY_BUILD_CACHE_PATH" pushd "$RUBY_BUILD_CACHE_PATH" >/dev/null tarball "$@" popd >/dev/null } tarball() { local name="$1" local path="$PWD/$name" local configure="$path/configure" shift 1 executable "$configure" <> build.log OUT for file; do mkdir -p "$(dirname "${path}/${file}")" touch "${path}/${file}" done tar czf "${path}.tar.gz" -C "${path%/*}" "$name" } stub_make_install() { stub "$MAKE" \ " : echo \"$MAKE \$@\" >> build.log" \ "install : echo \"$MAKE \$@\" >> build.log && cat build.log >> '$INSTALL_ROOT/build.log'" } assert_build_log() { run cat "$INSTALL_ROOT/build.log" assert_output } @test "yaml is installed for ruby" { cached_tarball "yaml-0.1.6" cached_tarball "ruby-2.0.0" stub uname '-s : echo Linux' stub brew false stub_make_install stub_make_install install_fixture definitions/needs-yaml assert_success unstub uname unstub make assert_build_log <> build.log' TMPDIR="$TMP" install_fixture --patch definitions/needs-yaml <> build.log' TMPDIR="$TMP" install_fixture --patch definitions/needs-yaml <> build.log' TMPDIR="$TMP" install_fixture --patch definitions/needs-yaml <> build.log' stub_make_install export RUBY_CONFIGURE="${TMP}/custom-configure" run_inline_definition <> '$INSTALL_ROOT'/build.log mkdir -p build/host/bin touch build/host/bin/{mruby,mirb} chmod +x build/host/bin/{mruby,mirb} OUT mkdir -p "$package/include" touch "$package/include/mruby.h" mkdir -p "$RUBY_BUILD_CACHE_PATH" tar czf "$RUBY_BUILD_CACHE_PATH/${package##*/}.tar.gz" -C "${package%/*}" "${package##*/}" rm -rf "$package" stub gem false stub rake false mkdir -p "$INSTALL_ROOT/bin" touch "$INSTALL_ROOT/bin/mruby" chmod -w "$INSTALL_ROOT/bin/mruby" run_inline_definition <> build.log' \ '--version : echo 1' \ " exec rake install : { cat build.log; echo bundle \"\$@\"; } >> '$INSTALL_ROOT/build.log'" run_inline_definition <>' OUT cached_tarball "rubinius-2.0.0" bin/ruby stub bundle false stub rake \ '--version : echo 1' \ "install : mkdir -p '$INSTALL_ROOT'; cp -fR . '$INSTALL_ROOT'" run_inline_definition <>' OUT } @test "JRuby build" { executable "${RUBY_BUILD_CACHE_PATH}/jruby-1.7.9/bin/jruby" <> ../build.log OUT executable "${RUBY_BUILD_CACHE_PATH}/jruby-1.7.9/bin/gem" <&2" run_inline_definition <&2' run_inline_definition <&2; echo 'java version \"1.8.0_31\"' >&2" run_inline_definition <&2" run_inline_definition <&2" run_inline_definition <&2" run_inline_definition <&2; echo 4.2.1' '--version : echo warning >&2; echo 4.2.1' run_inline_definition < ./configure < "${TMP}/definitions/1.9.3-test" mkdir -p "${TMP}/other" echo false > "${TMP}/other/1.9.3-test" run bin/ruby-build "1.9.3-test" "${TMP}/install" assert_success "" } @test "installing nonexistent definition" { run ruby-build "nonexistent" "${TMP}/install" assert [ "$status" -eq 2 ] assert_output "ruby-build: definition not found: nonexistent" } @test "sorting Ruby versions" { export RUBY_BUILD_ROOT="$TMP" mkdir -p "${RUBY_BUILD_ROOT}/share/ruby-build" expected="1.8.7 1.8.7-p72 1.8.7-p375 1.9.3-dev 1.9.3-preview1 1.9.3-rc1 1.9.3-p0 1.9.3-p125 2.1.0-dev 2.1.0-rc1 2.1.0 2.1.1 2.2.0-dev jruby-1.6.5 jruby-1.6.5.1 jruby-1.7.0-preview1 jruby-1.7.0-rc1 jruby-1.7.0 jruby-1.7.1 jruby-1.7.9 jruby-1.7.10 jruby-9000-dev jruby-9000 truffleruby-1.0.0-rc2 truffleruby-19.0.0 truffleruby-19.3.0" for ver in $expected; do touch "${RUBY_BUILD_ROOT}/share/ruby-build/$ver" done run ruby-build --definitions assert_success "$expected" } @test "removing duplicate Ruby versions" { export RUBY_BUILD_ROOT="$TMP" export RUBY_BUILD_DEFINITIONS="${RUBY_BUILD_ROOT}/share/ruby-build" mkdir -p "$RUBY_BUILD_DEFINITIONS" touch "${RUBY_BUILD_DEFINITIONS}/1.9.3" touch "${RUBY_BUILD_DEFINITIONS}/2.2.0" run ruby-build --definitions assert_success assert_output < http://example.com/packages/package-1.0.0.tar.gz" assert_output_contains "error: failed to download package-1.0.0.tar.gz" } @test "no download tool" { export -n RUBY_BUILD_HTTP_CLIENT clean_path="$(remove_commands_from_path curl wget aria2c)" PATH="$clean_path" install_fixture definitions/without-checksum assert_failure assert_output_contains 'error: install `curl`, `wget`, or `aria2c` to download packages' } @test "using aria2c if available" { export RUBY_BUILD_ARIA2_OPTS= export -n RUBY_BUILD_HTTP_CLIENT stub aria2c "--allow-overwrite=true --no-conf=true -o * http://example.com/* : cp $FIXTURE_ROOT/\${5##*/} \$4" install_fixture definitions/without-checksum assert_success assert_output < http://example.com/packages/package-1.0.0.tar.gz Installing package-1.0.0... Installed package-1.0.0 to ${TMP}/install OUT unstub aria2c } @test "fetching from git repository" { stub git "clone --depth 1 --branch master http://example.com/packages/package.git package-dev : mkdir package-dev" run_inline_definition <dQ:&Kiul+$:Fc(ruby-build-20200401/test/hooks.bats000066400000000000000000000022301364075357400170120ustar00rootroot00000000000000#!/usr/bin/env bats load test_helper setup() { export RBENV_ROOT="${TMP}/rbenv" export HOOK_PATH="${TMP}/i has hooks" mkdir -p "$HOOK_PATH" } @test "rbenv-install hooks" { cat > "${HOOK_PATH}/install.bash" < "$definition" <<<"echo ruby-build" run rbenv-install "$definition" assert_success assert_output <<-OUT before: ${RBENV_ROOT}/versions/2.0.0 ruby-build after: 0 rehashed OUT } @test "rbenv-uninstall hooks" { cat > "${HOOK_PATH}/uninstall.bash" <&2 assert_success assert [ -x "${INSTALL_ROOT}/bin/package" ] unstub curl unstub shasum } @test "package URL with checksum but no shasum support bypasses mirror" { stub shasum false stub curl "-q -o * -*S* http://example.com/* : cp $FIXTURE_ROOT/\${5##*/} \$3" install_fixture definitions/with-checksum assert_success assert [ -x "${INSTALL_ROOT}/bin/package" ] unstub curl unstub shasum } @test "package URL with checksum hits mirror first" { local checksum="ba988b1bb4250dee0b9dd3d4d722f9c64b2bacfc805d1b6eba7426bda72dd3c5" local mirror_url="${RUBY_BUILD_MIRROR_URL}/$checksum" stub shasum true "echo $checksum" stub curl "-*I* $mirror_url : true" \ "-q -o * -*S* $mirror_url : cp $FIXTURE_ROOT/package-1.0.0.tar.gz \$3" install_fixture definitions/with-checksum assert_success assert [ -x "${INSTALL_ROOT}/bin/package" ] unstub curl unstub shasum } @test "package is fetched from original URL if mirror download fails" { local checksum="ba988b1bb4250dee0b9dd3d4d722f9c64b2bacfc805d1b6eba7426bda72dd3c5" local mirror_url="${RUBY_BUILD_MIRROR_URL}/$checksum" stub shasum true "echo $checksum" stub curl "-*I* $mirror_url : false" \ "-q -o * -*S* http://example.com/* : cp $FIXTURE_ROOT/\${5##*/} \$3" install_fixture definitions/with-checksum assert_success assert [ -x "${INSTALL_ROOT}/bin/package" ] unstub curl unstub shasum } @test "package is fetched from original URL if mirror download checksum is invalid" { local checksum="ba988b1bb4250dee0b9dd3d4d722f9c64b2bacfc805d1b6eba7426bda72dd3c5" local mirror_url="${RUBY_BUILD_MIRROR_URL}/$checksum" stub shasum true "echo invalid" "echo $checksum" stub curl "-*I* $mirror_url : true" \ "-q -o * -*S* $mirror_url : cp $FIXTURE_ROOT/package-1.0.0.tar.gz \$3" \ "-q -o * -*S* http://example.com/* : cp $FIXTURE_ROOT/\${5##*/} \$3" install_fixture definitions/with-checksum echo "$output" >&2 assert_success assert [ -x "${INSTALL_ROOT}/bin/package" ] unstub curl unstub shasum } @test "default mirror URL" { export RUBY_BUILD_MIRROR_URL= local checksum="ba988b1bb4250dee0b9dd3d4d722f9c64b2bacfc805d1b6eba7426bda72dd3c5" stub shasum true "echo $checksum" stub curl "-*I* : true" \ "-q -o * -*S* https://?*/$checksum : cp $FIXTURE_ROOT/package-1.0.0.tar.gz \$3" \ install_fixture definitions/with-checksum assert_success assert [ -x "${INSTALL_ROOT}/bin/package" ] unstub curl unstub shasum } @test "package URL with ruby-lang CDN with default mirror URL will bypasses mirror" { export RUBY_BUILD_MIRROR_URL= local checksum="ba988b1bb4250dee0b9dd3d4d722f9c64b2bacfc805d1b6eba7426bda72dd3c5" stub shasum true "echo $checksum" stub curl "-q -o * -*S* https://cache.ruby-lang.org/* : cp $FIXTURE_ROOT/\${5##*/} \$3" run_inline_definition <&2 && exit 2' \ "--definitions : echo 1.8.7 1.9.3-p0 1.9.3-p194 2.1.2 | tr ' ' $'\\n'" run rbenv-install 1.9.3 assert_failure assert_output <&2 && exit 2' \ "--definitions : true" run rbenv-install 1.9.3 assert_failure assert_output <&${!_STUB_DEBUG} fi [ -e "${!_STUB_PLAN}" ] || exit 1 [ -n "${!_STUB_RUN}" ] || eval "${_STUB_RUN}"="${TMPDIR}/${program}-stub-run" # Initialize or load the stub run information. eval "${_STUB_INDEX}"=1 eval "${_STUB_RESULT}"=0 [ ! -e "${!_STUB_RUN}" ] || source "${!_STUB_RUN}" # Loop over each line in the plan. index=0 while IFS= read -r line; do index=$(($index + 1)) if [ -z "${!_STUB_END}" ] && [ $index -eq "${!_STUB_INDEX}" ]; then # We found the plan line we're interested in. # Start off by assuming success. result=0 # Split the line into an array of arguments to # match and a command to run to produce output. command=" $line" if [ "$command" != "${command/ : }" ]; then patterns="${command%% : *}" command="${command#* : }" fi # Naively split patterns by whitespace for now. # In the future, use a sed script to split while # respecting quoting. set -f patterns=($patterns) set +f arguments=("$@") # Match the expected argument patterns to actual # arguments. for (( i=0; i<${#patterns[@]}; i++ )); do pattern="${patterns[$i]}" argument="${arguments[$i]}" case "$argument" in $pattern ) ;; * ) result=1 ;; esac done # If the arguments matched, evaluate the command # in a subshell. Otherwise, log the failure. if [ $result -eq 0 ] ; then set +e ( eval "$command" ) status="$?" set -e else eval "${_STUB_RESULT}"=1 fi fi done < "${!_STUB_PLAN}" if [ -n "${!_STUB_END}" ]; then # Clean up the run file. rm -f "${!_STUB_RUN}" # If the number of lines in the plan is larger than # the requested index, we failed. if [ $index -ge "${!_STUB_INDEX}" ]; then eval "${_STUB_RESULT}"=1 fi # Return the result. exit "${!_STUB_RESULT}" else # If the requested index is larger than the number # of lines in the plan file, we failed. if [ "${!_STUB_INDEX}" -gt $index ]; then eval "${_STUB_RESULT}"=1 fi # Write out the run information. { echo "${_STUB_INDEX}=$((${!_STUB_INDEX} + 1))" echo "${_STUB_RESULT}=${!_STUB_RESULT}" } > "${!_STUB_RUN}" exit "$status" fi ruby-build-20200401/test/test_helper.bash000066400000000000000000000062601364075357400202000ustar00rootroot00000000000000export TMP="$BATS_TEST_DIRNAME/tmp" export RUBY_BUILD_CURL_OPTS= export RUBY_BUILD_HTTP_CLIENT="curl" if [ "$FIXTURE_ROOT" != "$BATS_TEST_DIRNAME/fixtures" ]; then export FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures" export INSTALL_ROOT="$TMP/install" PATH="/usr/bin:/bin:/usr/sbin:/sbin" if [ "FreeBSD" = "$(uname -s)" ]; then PATH="/usr/local/bin:$PATH" fi PATH="$BATS_TEST_DIRNAME/../bin:$PATH" PATH="$TMP/bin:$PATH" export PATH fi remove_commands_from_path() { local path cmd local paths=( $(command -v "$@" | sed 's!/[^/]*$!!' | sort -u) ) local NEWPATH=":$PATH:" for path in "${paths[@]}"; do local tmp_path="$(mktemp -d "$TMP/path.XXXXX")" ln -fs "$path"/* "$tmp_path/" for cmd; do rm -f "$tmp_path/$cmd"; done NEWPATH="${NEWPATH/:$path:/:$tmp_path:}" done echo "${NEWPATH#:}" } teardown() { rm -fr "${TMP:?}"/* } stub() { local program="$1" local prefix="$(echo "$program" | tr a-z- A-Z_)" shift export "${prefix}_STUB_PLAN"="${TMP}/${program}-stub-plan" export "${prefix}_STUB_RUN"="${TMP}/${program}-stub-run" export "${prefix}_STUB_END"= mkdir -p "${TMP}/bin" ln -sf "${BATS_TEST_DIRNAME}/stubs/stub" "${TMP}/bin/${program}" touch "${TMP}/${program}-stub-plan" for arg in "$@"; do printf "%s\n" "$arg" >> "${TMP}/${program}-stub-plan"; done } unstub() { local program="$1" local prefix="$(echo "$program" | tr a-z- A-Z_)" local path="${TMP}/bin/${program}" export "${prefix}_STUB_END"=1 local STATUS=0 "$path" || STATUS="$?" rm -f "$path" rm -f "${TMP}/${program}-stub-plan" "${TMP}/${program}-stub-run" return "$STATUS" } run_inline_definition() { local definition="${TMP}/build-definition" cat > "$definition" run ruby-build "$definition" "${1:-$INSTALL_ROOT}" } install_fixture() { local args while [ "${1#-}" != "$1" ]; do args="$args $1" shift 1 done local name="$1" local destination="$2" [ -n "$destination" ] || destination="$INSTALL_ROOT" run ruby-build $args "$FIXTURE_ROOT/$name" "$destination" } assert() { if ! "$@"; then flunk "failed: $@" fi } refute() { if "$@"; then flunk "expected to fail: $@" fi } flunk() { { if [ "$#" -eq 0 ]; then cat - else echo "$@" fi } | sed "s:${TMP}:\${TMP}:g" >&2 return 1 } assert_success() { if [ "$status" -ne 0 ]; then { echo "command failed with exit status $status" echo "output: $output" } | flunk elif [ "$#" -gt 0 ]; then assert_output "$1" fi } assert_failure() { if [ "$status" -eq 0 ]; then flunk "expected failed exit status" elif [ "$#" -gt 0 ]; then assert_output "$1" fi } assert_equal() { if [ "$1" != "$2" ]; then { echo "expected: $1" echo "actual: $2" } | flunk fi } assert_output() { local expected if [ $# -eq 0 ]; then expected="$(cat -)" else expected="$1" fi assert_equal "$expected" "$output" } assert_output_contains() { local expected="$1" if [ -z "$expected" ]; then echo "assert_output_contains needs an argument" >&2 return 1 fi echo "$output" | $(type -p ggrep grep | head -1) -F "$expected" >/dev/null || { { echo "expected output to contain $expected" echo "actual: $output" } | flunk } } ruby-build-20200401/test/tmp/000077500000000000000000000000001364075357400156175ustar00rootroot00000000000000ruby-build-20200401/test/tmp/.gitignore000066400000000000000000000000021364075357400175770ustar00rootroot00000000000000* ruby-build-20200401/test/version.bats000066400000000000000000000020761364075357400173640ustar00rootroot00000000000000#!/usr/bin/env bats load test_helper bats_bin="${BATS_TEST_DIRNAME}/../bin/ruby-build" static_version="$(grep VERSION "$bats_bin" | head -1 | cut -d'"' -f 2)" @test "ruby-build static version" { stub git 'echo "ASPLODE" >&2; exit 1' run ruby-build --version assert_success "ruby-build ${static_version}" unstub git } @test "ruby-build git version" { stub git \ 'remote -v : echo origin https://github.com/rbenv/ruby-build.git' \ "describe --tags HEAD : echo v1984-12-gSHA" run ruby-build --version assert_success "ruby-build 1984-12-gSHA" unstub git } @test "git describe fails" { stub git \ 'remote -v : echo origin https://github.com/rbenv/ruby-build.git' \ "describe --tags HEAD : echo ASPLODE >&2; exit 1" run ruby-build --version assert_success "ruby-build ${static_version}" unstub git } @test "git remote doesn't match" { stub git \ 'remote -v : echo origin https://github.com/Homebrew/homebrew.git' \ "describe --tags HEAD : echo v1984-12-gSHA" run ruby-build --version assert_success "ruby-build ${static_version}" }