brew/bin/brew
Carlo Cabrera 6f63be411b
bin/brew: refine generation of HOMEBREW_* env vars
We inherit some variables from the user's environment but prefix them
with `HOMEBREW_`. This is the case for (1) variables documented in the
manpage and also for some (2) variables used internally by `brew`.

We currently treat both types identically, but we should not. In
particular, we allow users to override type (1), but we don't want to do
this for type (2).

This was partially fixed in f4103e5d61526cfbf7f31540ba45ec171adc452e,
but that fix did not go far enough. Some variables that the user should
not be allowed to override can still be overridden.

This change completes the partial fix and refactors the code so that
we're less likely to mistakenly conflate the two types of variables in
the future.
2023-02-15 13:27:02 +08:00

172 lines
4.9 KiB
Bash
Executable File

#!/bin/bash
set -u
# Fail fast with concise message when not using bash
# Single brackets is needed here for POSIX compatibility
# shellcheck disable=SC2292
if [ -z "${BASH_VERSION:-}" ]
then
echo "Error: Bash is required to run brew." >&2
exit 1
fi
set +o posix # as we are using bash now
# Fail fast with concise message when cwd does not exist
if ! [[ -d "${PWD}" ]]
then
echo "Error: The current working directory doesn't exist, cannot proceed." >&2
exit 1
fi
# Fail fast with concise message when requesting unfiltered environment.
# This is basically odisabled so can be removed at any major release afterwards
# and definitely if this is still here in 2023.
if [[ -n "${HOMEBREW_NO_ENV_FILTERING:-}" ]]
then
echo "Error: HOMEBREW_NO_ENV_FILTERING was deprecated for over a year and has now been removed (because it breaks many things)!" >&2
exit 1
fi
quiet_cd() {
cd "$@" &>/dev/null || return
}
symlink_target_directory() {
local target target_dirname
target="$(readlink "$1")"
target_dirname="$(dirname "${target}")"
local directory="$2"
quiet_cd "${directory}" && quiet_cd "${target_dirname}" && pwd -P
}
# Enable and use default Bash builtins rather than user-defined functions
builtin enable compgen unset
for cmd in $(builtin compgen -A builtin)
do
builtin unset -f "${cmd}"
builtin enable "${cmd}"
done
unset cmd
BREW_FILE_DIRECTORY="$(quiet_cd "${0%/*}/" && pwd -P)"
HOMEBREW_BREW_FILE="${BREW_FILE_DIRECTORY%/}/${0##*/}"
HOMEBREW_PREFIX="${HOMEBREW_BREW_FILE%/*/*}"
# Default to / prefix if unset or the bin/brew file.
if [[ -z "${HOMEBREW_PREFIX}" || "${HOMEBREW_PREFIX}" = "${HOMEBREW_BREW_FILE}" ]]
then
HOMEBREW_PREFIX="/"
fi
HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}"
# Resolve the bin/brew symlink to find Homebrew's repository
if [[ -L "${HOMEBREW_BREW_FILE}" ]]
then
BREW_FILE_DIRECTORY="$(symlink_target_directory "${HOMEBREW_BREW_FILE}" "${BREW_FILE_DIRECTORY}")"
HOMEBREW_REPOSITORY="${BREW_FILE_DIRECTORY%/*}"
fi
# Try to find a /usr/local HOMEBREW_PREFIX where possible (for bottles)
if [[ -L "/usr/local/bin/brew" && ! -L "${HOMEBREW_PREFIX}/Cellar" ]]
then
USR_LOCAL_BREW_FILE_DIRECTORY="$(symlink_target_directory "/usr/local/bin/brew" "/usr/local/bin")"
USR_LOCAL_HOMEBREW_REPOSITORY="${USR_LOCAL_BREW_FILE_DIRECTORY%/*}"
if [[ "${HOMEBREW_REPOSITORY}" = "${USR_LOCAL_HOMEBREW_REPOSITORY}" ]]
then
HOMEBREW_PREFIX="/usr/local"
fi
fi
# If the location of HOMEBREW_LIBRARY changes
# keg_relocate.rb, formula_cellar_checks.rb, and test/global_spec.rb need to change.
HOMEBREW_LIBRARY="${HOMEBREW_REPOSITORY}/Library"
# Copy and export all HOMEBREW_* variables previously mentioned in
# manpage or used elsewhere by Homebrew.
# These variables are allowed to be set by the user as, e.g., `HOMEBREW_BROWSER`.
MANPAGE_VARS=(
BAT_CONFIG_PATH
BAT_THEME
BROWSER
DISPLAY
EDITOR
NO_COLOR
)
for VAR in "${MANPAGE_VARS[@]}"
do
# Skip if variable value is empty.
[[ -z "${!VAR:-}" ]] && continue
VAR_NEW="HOMEBREW_${VAR}"
# Skip if existing HOMEBREW_* variable is set.
[[ -n "${!VAR_NEW:-}" ]] && continue
export "${VAR_NEW}"="${!VAR}"
done
# We don't want to take the user's value for, e.g., `HOMEBREW_PATH` here!
USED_BY_HOMEBREW_VARS=(
CODESPACES
DBUS_SESSION_BUS_ADDRESS
PATH
TMUX
XDG_RUNTIME_DIR
)
for VAR in "${USED_BY_HOMEBREW_VARS[@]}"
do
# Skip if variable value is empty.
[[ -z "${!VAR:-}" ]] && continue
# We unconditionally override `HOMEBREW_*` here.
VAR_NEW="HOMEBREW_${VAR}"
export "${VAR_NEW}"="${!VAR}"
done
unset VAR VAR_NEW MANPAGE_VARS USED_BY_HOMEBREW_VARS
export HOMEBREW_BREW_FILE
export HOMEBREW_PREFIX
export HOMEBREW_REPOSITORY
export HOMEBREW_LIBRARY
# set from user environment
# shellcheck disable=SC2154
# Use VISUAL if HOMEBREW_EDITOR and EDITOR are unset.
if [[ -z "${HOMEBREW_EDITOR:-}" && -n "${VISUAL:-}" ]]
then
export HOMEBREW_EDITOR="${VISUAL}"
fi
# set from user environment
# shellcheck disable=SC2154
# Set CI variable for Azure Pipelines and Jenkins
# (Set by default on GitHub Actions, Circle and Travis CI)
if [[ -z "${CI:-}" ]] && [[ -n "${TF_BUILD:-}" || -n "${JENKINS_HOME:-}" ]]
then
export CI="1"
fi
# filter the user environment
PATH="/usr/bin:/bin:/usr/sbin:/sbin"
FILTERED_ENV=()
ENV_VAR_NAMES=(
HOME SHELL PATH TERM TERMINFO TERMINFO_DIRS COLUMNS DISPLAY LOGNAME USER CI SSH_AUTH_SOCK SUDO_ASKPASS
http_proxy https_proxy ftp_proxy no_proxy all_proxy HTTPS_PROXY FTP_PROXY ALL_PROXY
GITHUB_ACTIONS GITHUB_WORKSPACE GITHUB_ACTIONS_HOMEBREW_SELF_HOSTED
GITHUB_REPOSITORY GITHUB_RUN_ID GITHUB_RUN_ATTEMPT GITHUB_SHA GITHUB_HEAD_REF GITHUB_BASE_REF GITHUB_REF GITHUB_OUTPUT
)
# Filter all but the specific variables.
for VAR in "${ENV_VAR_NAMES[@]}" "${!HOMEBREW_@}"
do
# Skip if variable value is empty.
[[ -z "${!VAR:-}" ]] && continue
FILTERED_ENV+=("${VAR}=${!VAR}")
done
unset VAR ENV_VAR_NAMES
exec /usr/bin/env -i "${FILTERED_ENV[@]}" /bin/bash "${HOMEBREW_LIBRARY}/Homebrew/brew.sh" "$@"