#!/bin/bash set -u abort() { printf "%s\n" "$@" exit 1 } if [ -z "${BASH_VERSION:-}" ]; then abort "Bash is required to interpret this script." fi # Check if script is run non-interactively (e.g. CI) # If it is run non-interactively we should not prompt for passwords. if [[ ! -t 0 || -n "${CI-}" ]]; then NONINTERACTIVE=1 fi # First check OS. OS="$(uname)" if [[ "$OS" == "Linux" ]]; then HOMEBREW_ON_LINUX=1 elif [[ "$OS" != "Darwin" ]]; then abort "Homebrew is only supported on macOS and Linux." fi # Required installation paths. To install elsewhere (which is unsupported) # you can untar https://github.com/Homebrew/brew/tarball/master # anywhere you like. if [[ -z "${HOMEBREW_ON_LINUX-}" ]]; then UNAME_MACHINE="$(/usr/bin/uname -m)" if [[ "$UNAME_MACHINE" == "arm64" ]]; then # On ARM macOS, this script installs to /opt/homebrew only HOMEBREW_PREFIX="/opt/homebrew" HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}" else # On Intel macOS, this script installs to /usr/local only HOMEBREW_PREFIX="/usr/local" HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew" fi HOMEBREW_CACHE="${HOME}/Library/Caches/Homebrew" HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/homebrew-core" STAT="stat -f" CHOWN="/usr/sbin/chown" CHGRP="/usr/bin/chgrp" GROUP="admin" TOUCH="/usr/bin/touch" else UNAME_MACHINE="$(uname -m)" # On Linux, it installs to /home/linuxbrew/.linuxbrew if you have sudo access # and ~/.linuxbrew (which is unsupported) if run interactively. HOMEBREW_PREFIX_DEFAULT="/home/linuxbrew/.linuxbrew" HOMEBREW_CACHE="${HOME}/.cache/Homebrew" HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/linuxbrew-core" STAT="stat --printf" CHOWN="/bin/chown" CHGRP="/bin/chgrp" GROUP="$(id -gn)" TOUCH="/bin/touch" fi HOMEBREW_BREW_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/brew" # Use remote URLs of Homebrew repositories from environment if set. HOMEBREW_BREW_GIT_REMOTE="${HOMEBREW_BREW_GIT_REMOTE:-"${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}"}" HOMEBREW_CORE_GIT_REMOTE="${HOMEBREW_CORE_GIT_REMOTE:-"${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}"}" # The URLs with and without the '.git' suffix are the same Git remote. Do not prompt. if [[ "$HOMEBREW_BREW_GIT_REMOTE" == "${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}.git" ]]; then HOMEBREW_BREW_GIT_REMOTE="${HOMEBREW_BREW_DEFAULT_GIT_REMOTE}" fi if [[ "$HOMEBREW_CORE_GIT_REMOTE" == "${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}.git" ]]; then HOMEBREW_CORE_GIT_REMOTE="${HOMEBREW_CORE_DEFAULT_GIT_REMOTE}" fi export HOMEBREW_{BREW,CORE}_GIT_REMOTE # TODO: bump version when new macOS is released or announced MACOS_NEWEST_UNSUPPORTED="12.0" # TODO: bump version when new macOS is released MACOS_OLDEST_SUPPORTED="10.14" # For Homebrew on Linux REQUIRED_RUBY_VERSION=2.6 # https://github.com/Homebrew/brew/pull/6556 REQUIRED_GLIBC_VERSION=2.13 # https://docs.brew.sh/Homebrew-on-Linux#requirements # no analytics during installation export HOMEBREW_NO_ANALYTICS_THIS_RUN=1 export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1 # string formatters if [[ -t 1 ]]; then tty_escape() { printf "\033[%sm" "$1"; } else tty_escape() { :; } fi tty_mkbold() { tty_escape "1;$1"; } tty_underline="$(tty_escape "4;39")" tty_blue="$(tty_mkbold 34)" tty_red="$(tty_mkbold 31)" tty_bold="$(tty_mkbold 39)" tty_reset="$(tty_escape 0)" have_sudo_access() { local -a args if [[ -n "${SUDO_ASKPASS-}" ]]; then args=("-A") elif [[ -n "${NONINTERACTIVE-}" ]]; then args=("-n") fi if [[ -z "${HAVE_SUDO_ACCESS-}" ]]; then if [[ -n "${args[*]-}" ]]; then SUDO="/usr/bin/sudo ${args[*]}" else SUDO="/usr/bin/sudo" fi if [[ -n "${NONINTERACTIVE-}" ]]; then ${SUDO} -l mkdir &>/dev/null else ${SUDO} -v && ${SUDO} -l mkdir &>/dev/null fi HAVE_SUDO_ACCESS="$?" fi if [[ -z "${HOMEBREW_ON_LINUX-}" ]] && [[ "$HAVE_SUDO_ACCESS" -ne 0 ]]; then abort "Need sudo access on macOS (e.g. the user $USER needs to be an Administrator)!" fi return "$HAVE_SUDO_ACCESS" } shell_join() { local arg printf "%s" "$1" shift for arg in "$@"; do printf " " printf "%s" "${arg// /\ }" done } chomp() { printf "%s" "${1/"$'\n'"/}" } ohai() { printf "${tty_blue}==>${tty_bold} %s${tty_reset}\n" "$(shell_join "$@")" } warn() { printf "${tty_red}Warning${tty_reset}: %s\n" "$(chomp "$1")" } execute() { if ! "$@"; then abort "$(printf "Failed during: %s" "$(shell_join "$@")")" fi } execute_sudo() { local -a args=("$@") if have_sudo_access; then if [[ -n "${SUDO_ASKPASS-}" ]]; then args=("-A" "${args[@]}") fi ohai "/usr/bin/sudo" "${args[@]}" execute "/usr/bin/sudo" "${args[@]}" else ohai "${args[@]}" execute "${args[@]}" fi } getc() { local save_state save_state=$(/bin/stty -g) /bin/stty raw -echo IFS= read -r -n 1 -d '' "$@" /bin/stty "$save_state" } ring_bell() { # Use the shell's audible bell. if [[ -t 1 ]]; then printf "\a" fi } wait_for_user() { local c echo echo "Press RETURN to continue or any other key to abort" getc c # we test for \r and \n because some stuff does \r instead if ! [[ "$c" == $'\r' || "$c" == $'\n' ]]; then exit 1 fi } major_minor() { echo "${1%%.*}.$(x="${1#*.}"; echo "${x%%.*}")" } version_gt() { [[ "${1%.*}" -gt "${2%.*}" ]] || [[ "${1%.*}" -eq "${2%.*}" && "${1#*.}" -gt "${2#*.}" ]] } version_ge() { [[ "${1%.*}" -gt "${2%.*}" ]] || [[ "${1%.*}" -eq "${2%.*}" && "${1#*.}" -ge "${2#*.}" ]] } version_lt() { [[ "${1%.*}" -lt "${2%.*}" ]] || [[ "${1%.*}" -eq "${2%.*}" && "${1#*.}" -lt "${2#*.}" ]] } should_install_command_line_tools() { if [[ -n "${HOMEBREW_ON_LINUX-}" ]]; then return 1 fi if version_gt "$macos_version" "10.13"; then ! [[ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]] else ! [[ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]] || ! [[ -e "/usr/include/iconv.h" ]] fi } get_permission() { $STAT "%A" "$1" } user_only_chmod() { [[ -d "$1" ]] && [[ "$(get_permission "$1")" != "755" ]] } exists_but_not_writable() { [[ -e "$1" ]] && ! [[ -r "$1" && -w "$1" && -x "$1" ]] } get_owner() { $STAT "%u" "$1" } file_not_owned() { [[ "$(get_owner "$1")" != "$(id -u)" ]] } get_group() { $STAT "%g" "$1" } file_not_grpowned() { [[ " $(id -G "$USER") " != *" $(get_group "$1") "* ]] } # Please sync with 'test_ruby()' in 'Library/Homebrew/utils/ruby.sh' from Homebrew/brew repository. test_ruby() { if [[ ! -x $1 ]] then return 1 fi "$1" --enable-frozen-string-literal --disable=gems,did_you_mean,rubyopt -rrubygems -e \ "abort if Gem::Version.new(RUBY_VERSION.to_s.dup).to_s.split('.').first(2) != \ Gem::Version.new('$REQUIRED_RUBY_VERSION').to_s.split('.').first(2)" 2>/dev/null } no_usable_ruby() { local ruby_exec IFS=$'\n' # Do word splitting on new lines only for ruby_exec in $(which -a ruby 2>/dev/null); do if test_ruby "$ruby_exec"; then IFS=$' \t\n' # Restore IFS to its default value return 1 fi done IFS=$' \t\n' # Restore IFS to its default value return 0 } outdated_glibc() { local glibc_version glibc_version=$(ldd --version | head -n1 | grep -o '[0-9.]*$' | grep -o '^[0-9]\+\.[0-9]\+') version_lt "$glibc_version" "$REQUIRED_GLIBC_VERSION" } if [[ -n "${HOMEBREW_ON_LINUX-}" ]] && no_usable_ruby && outdated_glibc then abort "$(cat <<-EOFABORT Homebrew requires Ruby $REQUIRED_RUBY_VERSION which was not found on your system. Homebrew portable Ruby requires Glibc version $REQUIRED_GLIBC_VERSION or newer, and your Glibc version is too old. See ${tty_underline}https://docs.brew.sh/Homebrew-on-Linux#requirements${tty_reset} Install Ruby $REQUIRED_RUBY_VERSION and add its location to your PATH. EOFABORT )" fi # USER isn't always set so provide a fall back for the installer and subprocesses. if [[ -z "${USER-}" ]]; then USER="$(chomp "$(id -un)")" export USER fi # Invalidate sudo timestamp before exiting (if it wasn't active before). if ! /usr/bin/sudo -n -v 2>/dev/null; then trap '/usr/bin/sudo -k' EXIT fi # Things can fail later if `pwd` doesn't exist. # Also sudo prints a warning message for no good reason cd "/usr" || exit 1 ####################################################################### script if ! command -v git >/dev/null; then abort "$(cat </dev/null; then abort "$(cat </dev/null; then ohai "Select the Homebrew installation directory" echo "- ${tty_bold}Enter your password${tty_reset} to install to ${tty_underline}${HOMEBREW_PREFIX_DEFAULT}${tty_reset} (${tty_bold}recommended${tty_reset})" echo "- ${tty_bold}Press Control-D${tty_reset} to install to ${tty_underline}$HOME/.linuxbrew${tty_reset}" echo "- ${tty_bold}Press Control-C${tty_reset} to cancel installation" fi if have_sudo_access; then HOMEBREW_PREFIX="$HOMEBREW_PREFIX_DEFAULT" else HOMEBREW_PREFIX="$HOME/.linuxbrew" fi trap - SIGINT fi HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew" fi HOMEBREW_CORE="${HOMEBREW_REPOSITORY}/Library/Taps/homebrew/homebrew-core" if [[ "${EUID:-${UID}}" == "0" ]]; then # Allow Azure Pipelines/GitHub Actions/Docker/Concourse/Kubernetes to do everything as root (as it's normal there) if ! [[ -f /proc/1/cgroup ]] || ! grep -E "azpl_job|actions_job|docker|garden|kubepods" -q /proc/1/cgroup; then abort "Don't run this as root!" fi fi if [[ -d "${HOMEBREW_PREFIX}" && ! -x "${HOMEBREW_PREFIX}" ]]; then abort "$(cat </dev/null || return # we do it in four steps to avoid merge errors when reinstalling execute "git" "init" "-q" # "git remote add" will fail if the remote is defined in the global config execute "git" "config" "remote.origin.url" "${HOMEBREW_BREW_GIT_REMOTE}" execute "git" "config" "remote.origin.fetch" "+refs/heads/*:refs/remotes/origin/*" # ensure we don't munge line endings on checkout execute "git" "config" "core.autocrlf" "false" execute "git" "fetch" "--force" "origin" execute "git" "fetch" "--force" "--tags" "origin" execute "git" "reset" "--hard" "origin/master" if [[ "${HOMEBREW_REPOSITORY}" != "${HOMEBREW_PREFIX}" ]]; then execute "ln" "-sf" "${HOMEBREW_REPOSITORY}/bin/brew" "${HOMEBREW_PREFIX}/bin/brew" fi if [[ ! -d "${HOMEBREW_CORE}" ]]; then ohai "Tapping homebrew/core" ( execute "/bin/mkdir" "-p" "${HOMEBREW_CORE}" cd "${HOMEBREW_CORE}" >/dev/null || return execute "git" "init" "-q" execute "git" "config" "remote.origin.url" "${HOMEBREW_CORE_GIT_REMOTE}" execute "git" "config" "remote.origin.fetch" "+refs/heads/*:refs/remotes/origin/*" execute "git" "config" "core.autocrlf" "false" execute "git" "fetch" "--force" "origin" "refs/heads/master:refs/remotes/origin/master" execute "git" "remote" "set-head" "origin" "--auto" >/dev/null execute "git" "reset" "--hard" "origin/master" cd "${HOMEBREW_REPOSITORY}" >/dev/null || return ) || exit 1 fi execute "${HOMEBREW_PREFIX}/bin/brew" "update" "--force" "--quiet" ) || exit 1 if [[ ":${PATH}:" != *":${HOMEBREW_PREFIX}/bin:"* ]]; then warn "${HOMEBREW_PREFIX}/bin is not in your PATH." fi ohai "Installation successful!" echo ring_bell # Use an extra newline and bold to avoid this being missed. ohai "Homebrew has enabled anonymous aggregate formulae and cask analytics." echo "$(cat </dev/null || return execute "git" "config" "--replace-all" "homebrew.analyticsmessage" "true" execute "git" "config" "--replace-all" "homebrew.caskanalyticsmessage" "true" ) || exit 1 ohai "Next steps:" case "$SHELL" in */bash*) if [[ -r "$HOME/.bash_profile" ]]; then shell_profile="$HOME/.bash_profile" else shell_profile="$HOME/.profile" fi ;; */zsh*) shell_profile="$HOME/.zprofile" ;; *) shell_profile="$HOME/.profile" ;; esac if [[ "$UNAME_MACHINE" == "arm64" ]] || [[ -n "${HOMEBREW_ON_LINUX-}" ]]; then cat <> ${shell_profile} eval "\$(${HOMEBREW_PREFIX}/bin/brew shellenv)" EOS fi if [[ -n "${non_default_repos}" ]]; then s="" if [[ "${#additional_shellenv_commands[@]}" -gt 1 ]]; then s="s" fi echo "- Add the non-default Git remote${s} for ${non_default_repos} in ${tty_underline}${shell_profile}${tty_reset}:" printf " echo '%s' >> ${shell_profile}\n" "${additional_shellenv_commands[@]}" printf " %s\n" "${additional_shellenv_commands[@]}" fi echo "- Run \`brew help\` to get started" echo "- Further documentation: " echo " ${tty_underline}https://docs.brew.sh${tty_reset}" if [[ -n "${HOMEBREW_ON_LINUX-}" ]]; then echo "- Install the Homebrew dependencies if you have sudo access:" if [[ $(command -v apt-get) ]]; then echo " sudo apt-get install build-essential" elif [[ $(command -v yum) ]]; then echo " sudo yum groupinstall 'Development Tools'" elif [[ $(command -v pacman) ]]; then echo " sudo pacman -S base-devel" elif [[ $(command -v apk) ]]; then echo " sudo apk add build-base" fi cat <