mirror of
https://github.com/Homebrew/brew.git
synced 2026-10-29 01:54:43 +08:00
- Run managed commands as the prefix owner without a console login. - Share account switching with `as-console-user`. - Allow package deployment without Xcode or Command Line Tools. - Bootstrap missing Git without invoking Apple's installer stubs. - Test package deployment and bottle use with a non-admin account. - Document MDM provisioning, central policy and vulnerability updates.
179 lines
5.8 KiB
Bash
Executable File
179 lines
5.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# $1 Full path to the installer (unused)
|
|
# $2 Location of the Homebrew installation we may need to move into place
|
|
# $3 Target install location (unused)
|
|
# $4 System root directory (unused)
|
|
set -euo pipefail
|
|
|
|
# Use system tools without triggering developer tool installation prompts.
|
|
export PATH="/usr/bin:/bin:/usr/sbin:/sbin"
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)"
|
|
if [[ -f "${script_dir}/macos_user.sh" ]]
|
|
then
|
|
# `pkgbuild` stages this helper beside the package scripts.
|
|
# shellcheck disable=SC1091
|
|
source "${script_dir}/macos_user.sh"
|
|
else
|
|
# This fallback keeps direct local execution from the repository working.
|
|
# shellcheck disable=SC1091
|
|
source "${script_dir}/../../Library/Homebrew/utils/macos_user.sh"
|
|
fi
|
|
|
|
# disable analytics while installing
|
|
export HOMEBREW_NO_ANALYTICS_THIS_RUN=1
|
|
export HOMEBREW_NO_ANALYTICS_MESSAGE_OUTPUT=1
|
|
|
|
# verify the installation exists
|
|
# default to /opt/homebrew to make development/testing easier
|
|
homebrew_directory="${2:-/opt/homebrew}"
|
|
if [[ ! -d "${homebrew_directory:?}" ]]
|
|
then
|
|
echo "No directory at ${homebrew_directory}!" >&2
|
|
exit 1
|
|
fi
|
|
|
|
cd "${homebrew_directory}"
|
|
|
|
refuse_symlinked_directories() {
|
|
for dir in Caskroom Cellar Frameworks bin etc include lib opt sbin share var var/homebrew var/homebrew/linked
|
|
do
|
|
if [[ -L "${dir}" ]]
|
|
then
|
|
echo "Refusing to operate on symlinked ${dir} in ${homebrew_directory}." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
enter_managed_directory() {
|
|
local directory="$1"
|
|
local expected_path="$2"
|
|
local display_path="$3"
|
|
|
|
if [[ -L "${directory}" ]]
|
|
then
|
|
echo "Refusing to operate on symlinked ${display_path} in ${homebrew_directory}." >&2
|
|
exit 1
|
|
fi
|
|
|
|
cd -P "${directory}"
|
|
if [[ "$(pwd -P)" != "${expected_path}" ]]
|
|
then
|
|
echo "Refusing to operate on ${display_path} outside ${homebrew_directory}." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
prefix_directory="$(pwd -P)"
|
|
|
|
# optionally define an install user at /var/tmp/.homebrew_pkg_user.plist
|
|
# otherwise, get valid logged in user
|
|
homebrew_pkg_user="$(homebrew-package-user)" ||
|
|
{
|
|
echo "No valid user for Homebrew installation. Log in before install or specify an install user."
|
|
exit 1
|
|
}
|
|
|
|
if [[ "$(id -u "${homebrew_pkg_user}")" -eq 0 ]]
|
|
then
|
|
echo "The Homebrew installation user must not be root."
|
|
exit 1
|
|
fi
|
|
|
|
homebrew_pkg_group="admin"
|
|
if [[ " $(id -Gn "${homebrew_pkg_user}") " != *" admin "* ]]
|
|
then
|
|
homebrew_pkg_group="$(id -gn "${homebrew_pkg_user}")"
|
|
fi
|
|
homebrew_pkg_mode="ug=rwx"
|
|
if [[ "${homebrew_pkg_group}" == staff ]]
|
|
then
|
|
# Keep in sync with brew.sh and Homebrew/install's install.sh.
|
|
umask go-w
|
|
homebrew_pkg_mode="u=rwx,go-w"
|
|
chmod -R go-w .
|
|
fi
|
|
|
|
# create missing directories
|
|
refuse_symlinked_directories
|
|
mkdir -vp Caskroom Cellar Frameworks etc include lib opt sbin share var
|
|
(
|
|
enter_managed_directory var "${prefix_directory}/var" var
|
|
mkdir -vp homebrew
|
|
enter_managed_directory homebrew "${prefix_directory}/var/homebrew" var/homebrew
|
|
mkdir -vp linked
|
|
)
|
|
|
|
if [[ -z "${HOMEBREW_NO_SUDO:-}" ]] && command -v sudo &>/dev/null
|
|
then
|
|
user_command=(sudo -u "${homebrew_pkg_user}")
|
|
elif [[ "$(id -u)" == 0 ]]
|
|
then
|
|
user_command=(homebrew-login "${homebrew_pkg_user}")
|
|
else
|
|
echo "Switching to the Homebrew installation user without sudo requires root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${homebrew_pkg_group}" == staff ]]
|
|
then
|
|
# Account-switching tools may reset the umask; retain both masks afterwards.
|
|
# shellcheck disable=SC2016
|
|
user_command+=(/bin/bash -c 'umask "$(printf "%03o" "$((8#$1 | 8#$(umask)))")"; shift; exec "$@"' -- "$(umask)")
|
|
fi
|
|
|
|
# set permissions
|
|
refuse_symlinked_directories
|
|
chmod -h "${homebrew_pkg_mode}" Caskroom Cellar Frameworks bin etc include lib opt sbin share var
|
|
(
|
|
enter_managed_directory var "${prefix_directory}/var" var
|
|
enter_managed_directory homebrew "${prefix_directory}/var/homebrew" var/homebrew
|
|
chmod "${homebrew_pkg_mode}" .
|
|
enter_managed_directory linked "${prefix_directory}/var/homebrew/linked" var/homebrew/linked
|
|
chmod "${homebrew_pkg_mode}" .
|
|
)
|
|
chown -R "${homebrew_pkg_user}:${homebrew_pkg_group}" .
|
|
|
|
rm -rf "${homebrew_directory}/.git/hooks" "${homebrew_directory}/.gitconfig" "${homebrew_directory}/.config/git"
|
|
# The package already contains a stable checkout; reset it when Git is available.
|
|
if developer_dir="$(xcode-select --print-path 2>/dev/null)" &&
|
|
[[ -n "${developer_dir}" && "${developer_dir}" != / && -x "${developer_dir}/usr/bin/git" ]]
|
|
then
|
|
git_as_user() {
|
|
"${user_command[@]}" /usr/bin/env \
|
|
HOME="${homebrew_directory}" GIT_CONFIG_GLOBAL=/dev/null PATH="${PATH}" \
|
|
"${developer_dir}/usr/bin/git" -c core.hooksPath=/dev/null "$@"
|
|
}
|
|
|
|
latest_tag="$(git_as_user -C "${homebrew_directory}" tag --list --sort="-version:refname" | head -n1)"
|
|
git_as_user -C "${homebrew_directory}" checkout --force -B stable
|
|
git_as_user -C "${homebrew_directory}" reset --hard "${latest_tag}"
|
|
git_as_user -C "${homebrew_directory}" clean -f -d
|
|
fi
|
|
|
|
# move API cache to ~/Library/Caches/Homebrew
|
|
user_home_dir="$(homebrew-user-home "${homebrew_pkg_user}")" ||
|
|
{
|
|
echo "No home directory for Homebrew installation user: ${homebrew_pkg_user}"
|
|
exit 1
|
|
}
|
|
user_cache_dir="${user_home_dir}/Library/Caches/Homebrew"
|
|
user_api_cache_dir="${user_cache_dir}/api"
|
|
# Seed the cache as the install user: as root, `cp` follows a symlink planted at the
|
|
# destination, and the `chown -R` this removes would reach anything hard-linked into the tree.
|
|
"${user_command[@]}" mkdir -vp "${user_api_cache_dir}"
|
|
"${user_command[@]}" cp -vpR "${homebrew_directory}/cache_api/." "${user_api_cache_dir}"
|
|
if [[ "${homebrew_pkg_group}" == staff ]]
|
|
then
|
|
"${user_command[@]}" chmod -R go-w "${user_cache_dir}"
|
|
fi
|
|
rm -vrf "${homebrew_directory}/cache_api"
|
|
|
|
# add Homebrew to the default PATH
|
|
if [[ -d "/etc/paths.d" ]]
|
|
then
|
|
echo "${homebrew_directory}/bin" >/etc/paths.d/homebrew
|
|
chown root:wheel /etc/paths.d/homebrew
|
|
fi
|