Files
script/homebrew/brew-upgrade-manager-bootstrap.sh
T
orion 15d18f6123 fix(homebrew): 修复 Homebrew 伪终端输入和输出处理问题
- 在 colorize_line 函数中处理光标控制序列,避免它们破坏版本着色
- 添加 run_brew_in_pseudoterminal 函数,从控制终端读取输入而不是关闭的管道
- 将主脚本通过 curl 管道启动时的输入重定向到 /dev/tty
- 修复启动器中 sudo 密码读取时的输入源问题
- 更新文档说明启动器如何处理 curl 管道输入和确认提示
2026-07-24 08:54:53 +08:00

139 lines
4.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 目标:下载远程升级脚本、执行、销毁临时文件
set -euo pipefail
if [[ -t 1 ]]; then
RED='\033[31m'
YELLOW='\033[33m'
CYAN='\033[36m'
NC='\033[0m'
else
RED=''
YELLOW=''
CYAN=''
NC=''
fi
print_info() {
printf '%b%s%b\n' "$CYAN" "$*" "$NC"
}
print_error() {
printf '%bError:%b %s\n' "$RED" "$NC" "$*" >&2
}
REMOTE="https://git.orionc.me/orion/script/raw/branch/main/homebrew/brew-upgrade-manager.sh"
TEMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/brew-upgrade-manager.XXXXXX")"
TEMP="$TEMP_DIR/brew-upgrade-manager.sh"
ASKPASS_TEMP="$TEMP_DIR/brewup-askpass.sh"
KEYCHAIN_SERVICE="${BREWUP_KEYCHAIN_SERVICE:-brewup-sudo-password}"
CURRENT_USER="${USER:-$(id -un)}"
cleanup() {
rm -f "$TEMP" "$ASKPASS_TEMP"
rmdir "$TEMP_DIR" 2>/dev/null || true
}
on_interrupt() {
exit 130
}
on_terminate() {
exit 143
}
trap cleanup EXIT
trap on_interrupt INT
trap on_terminate TERM
PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
export PATH
download_retries="${BREWUP_DOWNLOAD_RETRIES:-3}"
download_retry_delay="${BREWUP_DOWNLOAD_RETRY_DELAY_SECONDS:-2}"
connect_timeout="${BREWUP_CONNECT_TIMEOUT_SECONDS:-15}"
speed_time="${BREWUP_LOW_SPEED_TIME_SECONDS:-30}"
[[ "$download_retries" =~ ^[1-9][0-9]*$ ]] || download_retries=3
[[ "$download_retry_delay" =~ ^[0-9]+$ ]] || download_retry_delay=2
[[ "$connect_timeout" =~ ^[1-9][0-9]*$ ]] || connect_timeout=15
[[ "$speed_time" =~ ^[1-9][0-9]*$ ]] || speed_time=30
curl_retry_all_errors=()
if curl --help all 2>/dev/null | grep -q -- '--retry-all-errors'; then
curl_retry_all_errors+=(--retry-all-errors)
fi
print_info "正在下载远程脚本..."
curl -f -sSL \
--connect-timeout "$connect_timeout" \
--speed-limit 1024 \
--speed-time "$speed_time" \
--retry "$download_retries" \
--retry-delay "$download_retry_delay" \
"${curl_retry_all_errors[@]}" \
"$REMOTE" -o "$TEMP"
[[ -s "$TEMP" ]] || { print_error "远程脚本为空,已停止执行。"; exit 1; }
if [[ -n "${BREWUP_SHA256:-}" ]]; then
print_info "正在校验脚本 SHA256..."
actual_sha256="$(shasum -a 256 "$TEMP")"
actual_sha256="${actual_sha256%% *}"
if [[ "$actual_sha256" != "$BREWUP_SHA256" ]]; then
print_error "脚本 SHA256 不匹配,已停止执行。"
printf '%bExpected:%b %s\n' "$YELLOW" "$NC" "$BREWUP_SHA256" >&2
printf '%bActual:%b %s\n' "$RED" "$NC" "$actual_sha256" >&2
exit 1
fi
fi
bash -n "$TEMP"
if [[ "${BREWUP_DEBUG:-0}" == "1" ]]; then
print_info "Downloaded script first line:"
head -n 1 "$TEMP"
fi
setup_sudo_askpass() {
cat > "$ASKPASS_TEMP" <<'EOF'
#!/usr/bin/env bash
exec /usr/bin/security find-generic-password \
-a "${BREWUP_KEYCHAIN_ACCOUNT:-${USER:-$(id -un)}}" \
-s "${BREWUP_KEYCHAIN_SERVICE:-brewup-sudo-password}" -w
EOF
chmod 700 "$ASKPASS_TEMP"
export SUDO_ASKPASS="$ASKPASS_TEMP"
export BREWUP_KEYCHAIN_SERVICE="$KEYCHAIN_SERVICE"
export BREWUP_KEYCHAIN_ACCOUNT="$CURRENT_USER"
if ! /usr/bin/security find-generic-password -a "$CURRENT_USER" -s "$KEYCHAIN_SERVICE" -w >/dev/null 2>&1; then
printf '%b首次使用:请输入一次 sudo 密码,将保存到 macOS Keychain%b' "$YELLOW" "$NC"
if [[ -r /dev/tty ]]; then
IFS= read -r -s BREWUP_SUDO_PASSWORD < /dev/tty
else
IFS= read -r -s BREWUP_SUDO_PASSWORD
fi
printf '\n'
/usr/bin/security add-generic-password -U -a "$CURRENT_USER" -s "$KEYCHAIN_SERVICE" -w "$BREWUP_SUDO_PASSWORD" >/dev/null
unset BREWUP_SUDO_PASSWORD
fi
print_info "正在通过 Keychain 准备 sudo 凭据..."
if ! sudo -A -v; then
print_error "Keychain 中的 sudo 密码不可用,请删除后重新保存:"
printf ' %bsecurity delete-generic-password -a %q -s %q%b\n' \
"$CYAN" "$CURRENT_USER" "$KEYCHAIN_SERVICE" "$NC" >&2
exit 1
fi
}
setup_sudo_askpass
export COLUMNS="${COLUMNS:-130}"
if [[ -r /dev/tty ]]; then
# 启动器是通过 curl 管道执行时,不让主脚本继承已关闭的管道输入。
# 这样 Homebrew 的确认提示和 script(1) 的伪终端都能从当前终端正常读取输入。
bash "$TEMP" "$@" < /dev/tty
else
bash "$TEMP" "$@"
fi