From 87cb590f4cc3691e87d3f8c981e60c818da022fe Mon Sep 17 00:00:00 2001 From: neo Date: Mon, 1 Nov 2021 16:35:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=9C=80=E6=96=B0?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/tests.yml | 42 +-- install.sh | 605 ++++++++++++++++++++++-------------- uninstall.sh | 353 ++++++++++++--------- 3 files changed, 597 insertions(+), 403 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8f6357e..510e1c1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: GitHub Actions CI +name: CI on: push: branches: @@ -30,7 +30,6 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - name: Set up Git repository uses: actions/checkout@main @@ -40,7 +39,6 @@ jobs: sudo rm -rf /Applications/Xcode.app \ /Library/Developer/CommandLineTools sudo xcode-select --reset - - name: Install WSL if: runner.os == 'windows' # https://github.com/Vampire/setup-wsl/releases/tag/v1.1.0 @@ -53,19 +51,19 @@ jobs: - name: Set up Homebrew PATH if: runner.os != 'windows' run: | - if [ "${{ runner.os }}" = "macOS" ]; then - echo "/usr/local/bin:/usr/bin:/bin" >> ${GITHUB_PATH} + if [[ "${{ runner.os }}" = "macOS" ]] + then + echo "/usr/local/bin:/usr/bin:/bin" >> "${GITHUB_PATH}" else - echo "/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin" >> ${GITHUB_PATH} + echo "/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin" >> "${GITHUB_PATH}" fi - - name: Uninstall GitHub Actions Homebrew run: | - if which brew &>/dev/null; then + if which brew &>/dev/null + then /bin/bash uninstall.sh -n >/dev/null /bin/bash uninstall.sh -f >/dev/null fi - - name: Set up WSL environment if: runner.os == 'windows' shell: "wsl-bash -u root {0}" @@ -74,7 +72,6 @@ jobs: chmod 644 /etc/sudoers.d/runner echo -e "#!/bin/bash\nexec /home/linuxbrew/.linuxbrew/bin/brew \"\$@\"" | tee /usr/local/bin/brew chmod 755 /usr/local/bin/brew - - run: /bin/bash -c "$(cat install.sh)" - run: brew config @@ -83,39 +80,32 @@ jobs: - run: /bin/bash uninstall.sh -f >/dev/null - - name: Install Homebrew with mirror remotes + - name: Install Homebrew with non-default remotes # Use the default remotes but with Git Protocol run: | HOMEBREW_BREW_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/brew" - if [ "${{ runner.os }}" = "macOS" ]; then - HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/homebrew-core" - else - HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/linuxbrew-core" - fi - export HOMEBREW_BREW_GIT_REMOTE="${HOMEBREW_BREW_DEFAULT_GIT_REMOTE/%https/git}" - export HOMEBREW_CORE_GIT_REMOTE="${HOMEBREW_CORE_DEFAULT_GIT_REMOTE/%https/git}" + HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/homebrew-core" + export HOMEBREW_BREW_GIT_REMOTE="${HOMEBREW_BREW_DEFAULT_GIT_REMOTE/#https/git}" + export HOMEBREW_CORE_GIT_REMOTE="${HOMEBREW_CORE_DEFAULT_GIT_REMOTE/#https/git}" /bin/bash -c "$(cat install.sh)" - - run: brew config - run: | /bin/bash uninstall.sh -f >/dev/null unset HOMEBREW_{BREW,CORE}{,_DEFAULT}_GIT_REMOTE - - run: /bin/bash -c "$(cat install.sh)" - name: Uninstall and reinstall with sudo NOPASSWD if: runner.os == 'linux' run: | - echo "$USER ALL=(ALL) NOPASSWD:ALL" | sudo tee "/etc/sudoers.d/$USER" + echo "${USER} ALL=(ALL) NOPASSWD:ALL" | sudo tee "/etc/sudoers.d/${USER}" /bin/bash uninstall.sh -f >/dev/null /bin/bash -c "$(cat install.sh)" - - - run: brew install shellcheck - - - run: shellcheck *.sh + - name: Check code styles if: runner.os != 'windows' - + run: | + brew install shellcheck shfmt diffutils + brew style *.sh - run: /bin/bash uninstall.sh -n >/dev/null - run: /bin/bash uninstall.sh -f >/dev/null diff --git a/install.sh b/install.sh index 6b3b097..ca26613 100755 --- a/install.sh +++ b/install.sh @@ -6,31 +6,37 @@ abort() { exit 1 } -if [ -z "${BASH_VERSION:-}" ]; then +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 +if [[ ! -t 0 || -n "${CI-}" ]] +then NONINTERACTIVE=1 fi # First check OS. OS="$(uname)" -if [[ "$OS" == "Linux" ]]; then +if [[ "${OS}" == "Linux" ]] +then HOMEBREW_ON_LINUX=1 -elif [[ "$OS" != "Darwin" ]]; then +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 +if [[ -z "${HOMEBREW_ON_LINUX-}" ]] +then UNAME_MACHINE="$(/usr/bin/uname -m)" - if [[ "$UNAME_MACHINE" == "arm64" ]]; then + if [[ "${UNAME_MACHINE}" == "arm64" ]] + then # On ARM macOS, this script installs to /opt/homebrew only HOMEBREW_PREFIX="/opt/homebrew" HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}" @@ -44,7 +50,7 @@ if [[ -z "${HOMEBREW_ON_LINUX-}" ]]; then #HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/homebrew-core" HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git" - STAT="stat -f" + STAT_FLAG="-f" PERMISSION_FORMAT="%A" CHOWN="/usr/sbin/chown" CHGRP="/usr/bin/chgrp" @@ -57,11 +63,8 @@ else # and ~/.linuxbrew (which is unsupported) if run interactively. HOMEBREW_PREFIX_DEFAULT="/home/linuxbrew/.linuxbrew" HOMEBREW_CACHE="${HOME}/.cache/Homebrew" - #changed - #HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/linuxbrew-core" - HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://mirrors.ustc.edu.cn/linuxbrew-core.git" - STAT="stat --printf" + STAT_FLAG="--printf" PERMISSION_FORMAT="%a" CHOWN="/bin/chown" CHGRP="/bin/chgrp" @@ -71,36 +74,42 @@ fi #changed #HOMEBREW_BREW_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/brew" HOMEBREW_BREW_DEFAULT_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git" +#changed +#HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://github.com/Homebrew/linuxbrew-core" +HOMEBREW_CORE_DEFAULT_GIT_REMOTE="https://mirrors.ustc.edu.cn/linuxbrew-core.git" # 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 +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 +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" +MACOS_NEWEST_UNSUPPORTED="13.0" # TODO: bump version when new macOS is released -MACOS_OLDEST_SUPPORTED="10.14" +MACOS_OLDEST_SUPPORTED="10.15" # For Homebrew on Linux -REQUIRED_RUBY_VERSION=2.6 # https://github.com/Homebrew/brew/pull/6556 +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 REQUIRED_CURL_VERSION=7.41.0 # HOMEBREW_MINIMUM_CURL_VERSION in brew.sh in Homebrew/brew -REQUIRED_GIT_VERSION=2.7.0 # HOMEBREW_MINIMUM_GIT_VERSION in brew.sh in Homebrew/brew +REQUIRED_GIT_VERSION=2.7.0 # HOMEBREW_MINIMUM_GIT_VERSION in brew.sh in Homebrew/brew # no analytics during installation export HOMEBREW_NO_ANALYTICS_THIS_RUN=1 export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1 # string formatters -if [[ -t 1 ]]; then +if [[ -t 1 ]] +then tty_escape() { printf "\033[%sm" "$1"; } else tty_escape() { :; } @@ -112,25 +121,34 @@ tty_red="$(tty_mkbold 31)" tty_bold="$(tty_mkbold 39)" tty_reset="$(tty_escape 0)" +unset HAVE_SUDO_ACCESS # unset this from the environment + have_sudo_access() { - if [[ ! -x "/usr/bin/sudo" ]]; then + if [[ ! -x "/usr/bin/sudo" ]] + then return 1 fi local -a args - if [[ -n "${SUDO_ASKPASS-}" ]]; then + if [[ -n "${SUDO_ASKPASS-}" ]] + then args=("-A") - elif [[ -n "${NONINTERACTIVE-}" ]]; then + elif [[ -n "${NONINTERACTIVE-}" ]] + then args=("-n") fi - if [[ -z "${HAVE_SUDO_ACCESS-}" ]]; then - if [[ -n "${args[*]-}" ]]; then + 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 + if [[ -n "${NONINTERACTIVE-}" ]] + then + # Don't add quotes around ${SUDO} here ${SUDO} -l mkdir &>/dev/null else ${SUDO} -v && ${SUDO} -l mkdir &>/dev/null @@ -138,18 +156,20 @@ have_sudo_access() { 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)!" + 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" + return "${HAVE_SUDO_ACCESS}" } shell_join() { local arg printf "%s" "$1" shift - for arg in "$@"; do + for arg in "$@" + do printf " " printf "%s" "${arg// /\ }" done @@ -168,15 +188,18 @@ warn() { } execute() { - if ! "$@"; then + 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 + if have_sudo_access + then + if [[ -n "${SUDO_ASKPASS-}" ]] + then args=("-A" "${args[@]}") fi ohai "/usr/bin/sudo" "${args[@]}" @@ -189,15 +212,16 @@ execute_sudo() { getc() { local save_state - save_state=$(/bin/stty -g) + save_state="$(/bin/stty -g)" /bin/stty raw -echo - IFS= read -r -n 1 -d '' "$@" - /bin/stty "$save_state" + IFS='' read -r -n 1 -d '' "$@" + /bin/stty "${save_state}" } ring_bell() { # Use the shell's audible bell. - if [[ -t 1 ]]; then + if [[ -t 1 ]] + then printf "\a" fi } @@ -208,13 +232,17 @@ wait_for_user() { echo "请按回车键(RETURN)继续安装,按其他任意按键取消安装" getc c # we test for \r and \n because some stuff does \r instead - if ! [[ "$c" == $'\r' || "$c" == $'\n' ]]; then + if ! [[ "${c}" == $'\r' || "${c}" == $'\n' ]] + then exit 1 fi } major_minor() { - echo "${1%%.*}.$(x="${1#*.}"; echo "${x%%.*}")" + echo "${1%%.*}.$( + x="${1#*.}" + echo "${x%%.*}" + )" } version_gt() { @@ -228,11 +256,13 @@ version_lt() { } should_install_command_line_tools() { - if [[ -n "${HOMEBREW_ON_LINUX-}" ]]; then + if [[ -n "${HOMEBREW_ON_LINUX-}" ]] + then return 1 fi - if version_gt "$macos_version" "10.13"; then + if version_gt "${macos_version}" "10.13" + then ! [[ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]] else ! [[ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]] || @@ -241,7 +271,7 @@ should_install_command_line_tools() { } get_permission() { - $STAT "${PERMISSION_FORMAT}" "$1" + stat "${STAT_FLAG}" "${PERMISSION_FORMAT}" "$1" } user_only_chmod() { @@ -253,7 +283,7 @@ exists_but_not_writable() { } get_owner() { - $STAT "%u" "$1" + stat "${STAT_FLAG}" "%u" "$1" } file_not_owned() { @@ -261,93 +291,107 @@ file_not_owned() { } get_group() { - $STAT "%g" "$1" + stat "${STAT_FLAG}" "%g" "$1" } file_not_grpowned() { - [[ " $(id -G "$USER") " != *" $(get_group "$1") "* ]] + [[ " $(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 ]] + 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 + Gem::Version.new('${REQUIRED_RUBY_VERSION}').to_s.split('.').first(2)" 2>/dev/null } test_curl() { - if [[ ! -x $1 ]]; then + if [[ ! -x "$1" ]] + then return 1 fi local curl_version_output curl_name_and_version - curl_version_output=$("$1" --version 2>/dev/null) + curl_version_output="$("$1" --version 2>/dev/null)" curl_name_and_version="${curl_version_output%% (*}" - version_ge "$(major_minor "${curl_name_and_version##* }")" "$(major_minor "$REQUIRED_CURL_VERSION")" + version_ge "$(major_minor "${curl_name_and_version##* }")" "$(major_minor "${REQUIRED_CURL_VERSION}")" } test_git() { - if [[ ! -x $1 ]]; then + if [[ ! -x "$1" ]] + then return 1 fi local git_version_output - git_version_output=$("$1" --version 2>/dev/null) - version_ge "$(major_minor "${git_version_output##* }")" "$(major_minor "$REQUIRED_GIT_VERSION")" + git_version_output="$("$1" --version 2>/dev/null)" + version_ge "$(major_minor "${git_version_output##* }")" "$(major_minor "${REQUIRED_GIT_VERSION}")" +} + +# Search given executable in PATH (remove dependency for `which` command) +which() { + # Alias to Bash built-in command `type -P` + type -P "$@" } # Search PATH for the specified program that satisfies Homebrew requirements +# function which is set above +# shellcheck disable=SC2230 find_tool() { - if [[ $# -ne 1 ]]; then - return + if [[ $# -ne 1 ]] + then + return 1 fi local executable - IFS=$'\n' # Do word splitting on new lines only - for executable in $(which -a "$1" 2>/dev/null); do - if "test_$1" "$executable"; then - echo "$executable" + while read -r executable + do + if "test_$1" "${executable}" + then + echo "${executable}" break fi - done - IFS=$' \t\n' # Restore IFS to its default value + done < <(which -a "$1") } no_usable_ruby() { - [[ -z $(find_tool ruby) ]] + [[ -z "$(find_tool ruby)" ]] } 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" + 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 - )" + 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 +if [[ -z "${USER-}" ]] +then USER="$(chomp "$(id -un)")" export USER fi # Invalidate sudo timestamp before exiting (if it wasn't active before). -if [[ -x /usr/bin/sudo ]] && ! /usr/bin/sudo -n -v 2>/dev/null; then +if [[ -x /usr/bin/sudo ]] && ! /usr/bin/sudo -n -v 2>/dev/null +then trap '/usr/bin/sudo -k' EXIT fi @@ -356,48 +400,60 @@ fi cd "/usr" || exit 1 ####################################################################### script -if ! command -v git >/dev/null; then - abort "$(cat </dev/null +then + abort "$( + cat </dev/null; then - abort "$(cat </dev/null +then + abort "$( + cat </dev/null; then + if ! /usr/bin/sudo -n -v &>/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-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" + if have_sudo_access + then + HOMEBREW_PREFIX="${HOMEBREW_PREFIX_DEFAULT}" else - HOMEBREW_PREFIX="$HOME/.linuxbrew" + HOMEBREW_PREFIX="${HOME}/.linuxbrew" fi trap - SIGINT fi @@ -433,58 +500,73 @@ else fi HOMEBREW_CORE="${HOMEBREW_REPOSITORY}/Library/Taps/homebrew/homebrew-core" -if [[ "${EUID:-${UID}}" == "0" ]]; then +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 + ! 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 <> ${shell_profile} eval "\$(${HOMEBREW_PREFIX}/bin/brew shellenv)" EOS echo " 如有疑问,可以访问 ${tty_underline}https://brew.idayer.com/guide/m1/${tty_reset}" fi -if [[ -n "${non_default_repos}" ]]; then - s="" - if [[ "${#additional_shellenv_commands[@]}" -gt 1 ]]; then - s="s" +if [[ -n "${non_default_repos}" ]] +then + plural="" + if [[ "${#additional_shellenv_commands[@]}" -gt 1 ]] + then + plural="s" fi - echo "- Run these commands in your terminal to add the non-default Git remote${s} for ${non_default_repos}:" + echo "- Run these commands in your terminal to add the non-default Git remote${plural} for ${non_default_repos}:" printf " echo '%s' >> ${shell_profile}\n" "${additional_shellenv_commands[@]}" printf " %s\n" "${additional_shellenv_commands[@]}" fi @@ -885,16 +1027,21 @@ echo "- 更多文档: " echo " ${tty_underline}https://docs.brew.sh${tty_reset}" echo " ${tty_underline}https://brew.idayer.com${tty_reset}" -if [[ -n "${HOMEBREW_ON_LINUX-}" ]]; then +if [[ -n "${HOMEBREW_ON_LINUX-}" ]] +then echo "- Install the Homebrew dependencies if you have sudo access:" - if [[ $(command -v apt-get) ]]; then + if [[ -x "$(command -v apt-get)" ]] + then echo " sudo apt-get install build-essential" - elif [[ $(command -v yum) ]]; then + elif [[ -x "$(command -v yum)" ]] + then echo " sudo yum groupinstall 'Development Tools'" - elif [[ $(command -v pacman) ]]; then + elif [[ -x "$(command -v pacman)" ]] + then echo " sudo pacman -S base-devel" - elif [[ $(command -v apk) ]]; then + elif [[ -x "$(command -v apk)" ]] + then echo " sudo apk add build-base" fi diff --git a/uninstall.sh b/uninstall.sh index 5989dbb..52bc602 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -9,25 +9,27 @@ abort() { strip_s() { local s - for s in "$@"; do - s=${s## } + for s in "$@" + do + s="${s## }" echo "${s%% }" done } dir_children() { local p - for p in "$@"; do - [[ -d $p ]] || continue - find "$p" -mindepth 1 -maxdepth 1 + for p in "$@" + do + [[ -d "${p}" ]] || continue + find "${p}" -mindepth 1 -maxdepth 1 done } # Set up temp dir -tmpdir=/tmp/uninstall.$$ -mkdir -p "$tmpdir" || abort "Unable to create temp dir '$tmpdir'" +tmpdir="/tmp/uninstall.$$" +mkdir -p "${tmpdir}" || abort "Unable to create temp dir '${tmpdir}'" trap ' - rm -fr "$tmpdir" + rm -fr "${tmpdir}" # Invalidate sudo timestamp before exiting /usr/bin/sudo -k ' EXIT @@ -41,15 +43,16 @@ opt_skip_cache_and_logs="" # global status to indicate whether there is anything wrong. failed=false -un=$(uname) -case "$un" in +un="$(uname)" +case "${un}" in Linux) ostype=linux homebrew_prefix_default=/home/linuxbrew/.linuxbrew - ;; + ;; Darwin) ostype=macos - if [[ "$(uname -m)" == "arm64" ]]; then + if [[ "$(uname -m)" == "arm64" ]] + then homebrew_prefix_default=/opt/homebrew else homebrew_prefix_default=/usr/local @@ -57,32 +60,36 @@ case "$un" in realpath() { cd "$(dirname "$1")" && echo "$(pwd -P)/$(basename "$1")" } - ;; + ;; *) - abort "Unsupported system type '$un'" - ;; + abort "Unsupported system type '${un}'" + ;; esac # string formatters -if [[ -t 1 ]]; then +if [[ -t 1 ]] +then tty_escape() { printf "\033[%sm" "$1"; } else tty_escape() { :; } fi tty_mkbold() { tty_escape "1;${1:-39}"; } -tty_blue=$(tty_mkbold 34) -tty_red=$(tty_mkbold 31) -tty_bold=$(tty_mkbold 39) -tty_reset=$(tty_escape 0) +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 + if [[ -n "${SUDO_ASKPASS-}" ]] + then args=("-A") fi - if [[ -z "${HAVE_SUDO_ACCESS-}" ]]; then - if [[ -n "${args[*]-}" ]]; then + if [[ -z "${HAVE_SUDO_ACCESS-}" ]] + then + if [[ -n "${args[*]-}" ]] + then /usr/bin/sudo "${args[@]}" -l mkdir &>/dev/null else /usr/bin/sudo -l mkdir &>/dev/null @@ -90,18 +97,20 @@ have_sudo_access() { 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 to be an Administrator)!" + if [[ -z "${HOMEBREW_ON_LINUX-}" ]] && [[ "${HAVE_SUDO_ACCESS}" -ne 0 ]] + then + abort "Need sudo access on macOS (e.g. the user ${USER} to be an Administrator)!" fi - return "$HAVE_SUDO_ACCESS" + return "${HAVE_SUDO_ACCESS}" } shell_join() { local arg printf "%s" "$1" shift - for arg in "$@"; do + for arg in "$@" + do printf " " printf "%s" "${arg// /\ }" done @@ -111,13 +120,16 @@ resolved_pathname() { realpath "$1"; } pretty_print_pathnames() { local p - for p in "$@"; do - if [[ -h $p ]]; then - printf '%s -> %s\n' "$p" "$(resolved_pathname "$p")" - elif [[ -d $p ]]; then - echo "$p/" + for p in "$@" + do + if [[ -L "${p}" ]] + then + printf '%s -> %s\n' "${p}" "$(resolved_pathname "${p}")" + elif [[ -d "${p}" ]] + then + echo "${p}/" else - echo "$p" + echo "${p}" fi done } @@ -135,17 +147,20 @@ warn() { } execute() { - if ! "$@"; then + if ! "$@" + then abort "$(printf "Failed during: %s" "$(shell_join "$@")")" fi } execute_sudo() { local -a args=("$@") - if [[ -n "${SUDO_ASKPASS-}" ]]; then + if [[ -n "${SUDO_ASKPASS-}" ]] + then args=("-A" "${args[@]}") fi - if have_sudo_access; then + if have_sudo_access + then ohai "/usr/bin/sudo" "${args[@]}" system "/usr/bin/sudo" "${args[@]}" else @@ -155,7 +170,8 @@ execute_sudo() { } system() { - if ! "$@"; then + if ! "$@" + then warn "Failed during: $(shell_join "$@")" failed=true fi @@ -180,132 +196,159 @@ EOS exit "${1:-0}" } -while [[ $# -gt 0 ]]; do +while [[ $# -gt 0 ]] +do case "$1" in - -p*) homebrew_prefix_candidates+=("${1#-p}");; - --path=*) homebrew_prefix_candidates+=("${1#--path=}");; - --skip-cache-and-logs) opt_skip_cache_and_logs=1;; - -f|--force) opt_force=1;; - -q|--quiet) opt_quiet=1;; - -d|-n|--dry-run) opt_dry_run=1;; - -h|--help) usage;; - *) warn "Unrecognized option: '$1'"; usage 1;; + -p*) homebrew_prefix_candidates+=("${1#-p}") ;; + --path=*) homebrew_prefix_candidates+=("${1#--path=}") ;; + --skip-cache-and-logs) opt_skip_cache_and_logs=1 ;; + -f | --force) opt_force=1 ;; + -q | --quiet) opt_quiet=1 ;; + -d | -n | --dry-run) opt_dry_run=1 ;; + -h | --help) usage ;; + *) + warn "Unrecognized option: '$1'" + usage 1 + ;; esac shift done -if [[ ${#homebrew_prefix_candidates[@]} -eq 0 ]]; then # Attempt to locate Homebrew unless `--path` is passed - prefix=$(brew --prefix) - [[ -n $prefix ]] && homebrew_prefix_candidates+=("$prefix") - prefix=$(command -v brew) || prefix="" - [[ -n $prefix ]] && homebrew_prefix_candidates+=("$(dirname "$(dirname "$(strip_s "$prefix")")")") - homebrew_prefix_candidates+=("$homebrew_prefix_default") # Homebrew default path - homebrew_prefix_candidates+=("$HOME/.linuxbrew") # Linuxbrew default path +# Attempt to locate Homebrew unless `--path` is passed +if [[ "${#homebrew_prefix_candidates[@]}" -eq 0 ]] +then + prefix="$(brew --prefix)" + [[ -n "${prefix}" ]] && homebrew_prefix_candidates+=("${prefix}") + prefix="$(command -v brew)" || prefix="" + [[ -n "${prefix}" ]] && homebrew_prefix_candidates+=("$(dirname "$(dirname "$(strip_s "${prefix}")")")") + homebrew_prefix_candidates+=("${homebrew_prefix_default}") # Homebrew default path + homebrew_prefix_candidates+=("${HOME}/.linuxbrew") # Linuxbrew default path fi -HOMEBREW_PREFIX=$(for p in "${homebrew_prefix_candidates[@]}"; do - [[ -d $p ]] || continue - [[ $p == "$homebrew_prefix_default" && -d $p/Homebrew/.git ]] && echo "$p" && break - [[ -d $p/.git || -x $p/bin/brew ]] && echo "$p" && break -done) -[[ -n $HOMEBREW_PREFIX ]] || abort "Failed to locate Homebrew!" +HOMEBREW_PREFIX="$( + for p in "${homebrew_prefix_candidates[@]}" + do + [[ -d "${p}" ]] || continue + [[ ${p} == "${homebrew_prefix_default}" && -d "${p}/Homebrew/.git" ]] && echo "${p}" && break + [[ -d "${p}/.git" || -x "${p}/bin/brew" ]] && echo "${p}" && break + done +)" +[[ -n "${HOMEBREW_PREFIX}" ]] || abort "Failed to locate Homebrew!" -if [[ -d $HOMEBREW_PREFIX/.git ]]; then - HOMEBREW_REPOSITORY=$(dirname "$(realpath "$HOMEBREW_PREFIX/.git")") -elif [[ -x $HOMEBREW_PREFIX/bin/brew ]]; then - HOMEBREW_REPOSITORY=$(dirname "$(dirname "$(realpath "$HOMEBREW_PREFIX/bin/brew")")") +if [[ -d "${HOMEBREW_PREFIX}/.git" ]] +then + HOMEBREW_REPOSITORY="$(dirname "$(realpath "${HOMEBREW_PREFIX}/.git")")" +elif [[ -x "${HOMEBREW_PREFIX}/bin/brew" ]] +then + HOMEBREW_REPOSITORY="$(dirname "$(dirname "$(realpath "${HOMEBREW_PREFIX}/bin/brew")")")" else abort "Failed to locate Homebrew!" fi -if [[ -d $HOMEBREW_PREFIX/Cellar ]]; then - HOMEBREW_CELLAR=$HOMEBREW_PREFIX/Cellar +if [[ -d "${HOMEBREW_PREFIX}/Cellar" ]] +then + HOMEBREW_CELLAR="${HOMEBREW_PREFIX}/Cellar" else - HOMEBREW_CELLAR=$HOMEBREW_REPOSITORY/Cellar + HOMEBREW_CELLAR="${HOMEBREW_REPOSITORY}/Cellar" fi -if [[ -s $HOMEBREW_REPOSITORY/.gitignore ]]; then - gitignore=$(<"$HOMEBREW_REPOSITORY/.gitignore") +if [[ -s "${HOMEBREW_REPOSITORY}/.gitignore" ]] +then + gitignore="$(<"${HOMEBREW_REPOSITORY}/.gitignore")" else gitignore=$(curl -fsSL https://cdn.jsdelivr.net/gh/Homebrew/brew/.gitignore) fi -[[ -n $gitignore ]] || abort "Failed to fetch Homebrew .gitignore!" +[[ -n "${gitignore}" ]] || abort "Failed to fetch Homebrew .gitignore!" { - while read -r l; do - [[ $l == \!* ]] || continue - l=${l#\!} - l=${l#/} - [[ $l == @(bin|share|share/doc) ]] && echo "REJECT: $l" >&2 && continue - echo "$HOMEBREW_REPOSITORY/$l" - done <<<"$gitignore" + while read -r l + do + [[ "${l}" == \!* ]] || continue + l="${l#\!}" + l="${l#/}" + [[ "${l}" == @(bin|share|share/doc) ]] && echo "REJECT: ${l}" >&2 && continue + echo "${HOMEBREW_REPOSITORY}/${l}" + done <<<"${gitignore}" - if [[ $HOMEBREW_PREFIX != "$HOMEBREW_REPOSITORY" ]]; then - echo "$HOMEBREW_REPOSITORY" - for p in \ - bin/brew \ - etc/bash_completion.d/brew \ - share/doc/homebrew \ - share/man/man1/brew.1 \ - share/man/man1/brew-cask.1 \ - share/zsh/site-functions/_brew \ - share/zsh/site-functions/_brew_cask \ - var/homebrew \ - ; do - echo "$HOMEBREW_PREFIX/$p" + if [[ "${HOMEBREW_PREFIX}" != "${HOMEBREW_REPOSITORY}" ]] + then + echo "${HOMEBREW_REPOSITORY}" + directories=( + bin/brew + etc/bash_completion.d/brew + share/doc/homebrew + share/man/man1/brew.1 + share/man/man1/brew-cask.1 + share/man/man1/README.md + share/zsh/site-functions/_brew + share/zsh/site-functions/_brew_cask + share/fish/vendor_completions.d/brew.fish + var/homebrew + ) + for p in "${directories[@]}" + do + echo "${HOMEBREW_PREFIX}/${p}" done else - echo "$HOMEBREW_REPOSITORY/.git" + echo "${HOMEBREW_REPOSITORY}/.git" fi - echo "$HOMEBREW_CELLAR" - echo "$HOMEBREW_PREFIX/Caskroom" + echo "${HOMEBREW_CELLAR}" + echo "${HOMEBREW_PREFIX}/Caskroom" - [[ -n $opt_skip_cache_and_logs ]] || cat <<-EOS - $HOME/Library/Caches/Homebrew - $HOME/Library/Logs/Homebrew - /Library/Caches/Homebrew - $HOME/.cache/Homebrew - ${HOMEBREW_CACHE:-} - ${HOMEBREW_LOGS:-} - EOS + [[ -n ${opt_skip_cache_and_logs} ]] || cat <<-EOS +${HOME}/Library/Caches/Homebrew +${HOME}/Library/Logs/Homebrew +/Library/Caches/Homebrew +${HOME}/.cache/Homebrew +${HOMEBREW_CACHE:-} +${HOMEBREW_LOGS:-} +EOS - if [[ $ostype == macos ]]; then - dir_children "/Applications" "$HOME/Applications" | while read -r p2; do - [[ $(resolved_pathname "$p2") == $HOMEBREW_CELLAR/* ]] && echo "$p2" + if [[ "${ostype}" == macos ]] + then + dir_children "/Applications" "${HOME}/Applications" | while read -r p2; do + [[ $(resolved_pathname "${p2}") == "${HOMEBREW_CELLAR}"/* ]] && echo "${p2}" done fi } | while read -r l; do - [[ -e $l ]] && echo "$l" -done | sort -u > "$tmpdir/homebrew_files" + [[ -e "${l}" ]] && echo "${l}" +done | sort -u >"${tmpdir}/homebrew_files" homebrew_files=() -while read -r l; do - homebrew_files+=("$l") -done < "$tmpdir/homebrew_files" +while read -r l +do + homebrew_files+=("${l}") +done <"${tmpdir}/homebrew_files" -if [[ -z $opt_quiet ]]; then - dry_str=${opt_dry_run:+would} +if [[ -z "${opt_quiet}" ]] +then + dry_str="${opt_dry_run:+would}" warn "This script ${dry_str:-will} remove:" pretty_print_pathnames "${homebrew_files[@]}" fi -if [[ -t 0 && -z $opt_force && -z $opt_dry_run ]]; then +if [[ -t 0 && -z "${opt_force}" && -z "${opt_dry_run}" ]] +then read -rp "Are you sure you want to uninstall Homebrew? This will remove your installed packages! [y/N] " - [[ $REPLY == [yY]* ]] || abort + [[ "${REPLY}" == [yY]* ]] || abort fi -[[ -n $opt_quiet ]] || ohai "Removing Homebrew installation..." +[[ -n "${opt_quiet}" ]] || ohai "Removing Homebrew installation..." paths=() -for p in Frameworks bin etc include lib opt sbin share var; do - p=$HOMEBREW_PREFIX/$p - [[ -e $p ]] && paths+=("$p") +for p in Frameworks bin etc include lib opt sbin share var +do + p="${HOMEBREW_PREFIX}/${p}" + [[ -e "${p}" ]] && paths+=("${p}") done -if [[ ${#paths[@]} -gt 0 ]]; then - if [[ $ostype == macos ]]; then +if [[ "${#paths[@]}" -gt 0 ]] +then + if [[ "${ostype}" == macos ]] + then args=(-E "${paths[@]}" -regex '.*/info/([^.][^/]*\.info|dir)') else args=("${paths[@]}" -regextype posix-extended -regex '.*/info/([^.][^/]*\.info|dir)') fi - if [[ -n $opt_dry_run ]]; then + if [[ -n "${opt_dry_run}" ]] + then args+=(-print) echo "Would delete:" else @@ -315,22 +358,26 @@ if [[ ${#paths[@]} -gt 0 ]]; then fi system /usr/bin/find "${args[@]}" args=("${paths[@]}" -type l -lname '*/Cellar/*') - if [[ -n $opt_dry_run ]]; then + if [[ -n "${opt_dry_run}" ]] + then args+=(-print) else args+=(-exec unlink '{}' ';') fi - [[ -n $opt_dry_run ]] && echo "Would delete:" + [[ -n "${opt_dry_run}" ]] && echo "Would delete:" system /usr/bin/find "${args[@]}" fi -for file in "${homebrew_files[@]}"; do - if [[ -n $opt_dry_run ]]; then +for file in "${homebrew_files[@]}" +do + if [[ -n "${opt_dry_run}" ]] + then echo "Would delete ${file}" else - if ! err=$(rm -fr "$file" 2>&1); then + if ! err="$(rm -fr "${file}" 2>&1)" + then warn "Failed to delete ${file}" - echo "$err" + echo "${err}" fi fi done @@ -340,17 +387,20 @@ sudo() { system /usr/bin/sudo "$@" } -[[ -n $opt_quiet ]] || ohai "Removing empty directories..." +[[ -n "${opt_quiet}" ]] || ohai "Removing empty directories..." paths=() -for p in bin etc include lib opt sbin share var \ - Caskroom Cellar Homebrew Frameworks; do - p=$HOMEBREW_PREFIX/$p - [[ -e $p ]] && paths+=("$p") +for p in bin etc include lib opt sbin share var Caskroom Cellar Homebrew Frameworks +do + p="${HOMEBREW_PREFIX}/${p}" + [[ -e "${p}" ]] && paths+=("${p}") done -if [[ ${#paths[@]} -gt 0 ]]; then - if [[ $ostype == macos ]]; then +if [[ "${#paths[@]}" -gt 0 ]] +then + if [[ "${ostype}" == macos ]] + then args=("${paths[@]}" -name .DS_Store) - if [[ -n $opt_dry_run ]]; then + if [[ -n "${opt_dry_run}" ]] + then args+=(-print) echo "Would delete:" else @@ -359,7 +409,8 @@ if [[ ${#paths[@]} -gt 0 ]]; then execute_sudo /usr/bin/find "${args[@]}" fi args=("${paths[@]}" -depth -type d -empty) - if [[ -n $opt_dry_run ]]; then + if [[ -n "${opt_dry_run}" ]] + then args+=(-print) echo "Would remove directories:" else @@ -368,16 +419,20 @@ if [[ ${#paths[@]} -gt 0 ]]; then execute_sudo /usr/bin/find "${args[@]}" fi -[[ -n $opt_dry_run ]] && exit -if [[ $HOMEBREW_PREFIX != "$homebrew_prefix_default" && -e $HOMEBREW_PREFIX ]]; then - execute_sudo rmdir "$HOMEBREW_PREFIX" +[[ -n "${opt_dry_run}" ]] && exit +if [[ "${HOMEBREW_PREFIX}" != "${homebrew_prefix_default}" && -e "${HOMEBREW_PREFIX}" ]] +then + execute_sudo rmdir "${HOMEBREW_PREFIX}" fi -if [[ $HOMEBREW_PREFIX != "$HOMEBREW_REPOSITORY" && -e $HOMEBREW_REPOSITORY ]]; then - execute_sudo rmdir "$HOMEBREW_REPOSITORY" +if [[ "${HOMEBREW_PREFIX}" != "${HOMEBREW_REPOSITORY}" && -e "${HOMEBREW_REPOSITORY}" ]] +then + execute_sudo rmdir "${HOMEBREW_REPOSITORY}" fi -if [[ -z $opt_quiet ]]; then - if [[ $failed == true ]]; then +if [[ -z "${opt_quiet}" ]] +then + if [[ "${failed}" == true ]] + then warn "Homebrew partially uninstalled (but there were steps that failed)!" echo "To finish uninstalling rerun this script with \`sudo\`." else @@ -385,15 +440,17 @@ if [[ -z $opt_quiet ]]; then fi fi -dir_children "$HOMEBREW_REPOSITORY" "$HOMEBREW_PREFIX" \ - | sort -u > "$tmpdir/residual_files" +dir_children "${HOMEBREW_REPOSITORY}" "${HOMEBREW_PREFIX}" | + sort -u >"${tmpdir}/residual_files" -if [[ -s $tmpdir/residual_files && -z $opt_quiet ]]; then +if [[ -s "${tmpdir}/residual_files" && -z "${opt_quiet}" ]] +then echo "The following possible Homebrew files were not deleted:" - while read -r f; do - pretty_print_pathnames "$f" - done <"$tmpdir/residual_files" + while read -r f + do + pretty_print_pathnames "${f}" + done <"${tmpdir}/residual_files" echo -e "You may wish to remove them yourself.\n" fi -[[ $failed != true ]] +[[ "${failed}" != true ]]