ff54bffc53
* 优化 Shell 环境设置,采用 set -euo pipefail 提升脚本鲁棒性 * 改进路径处理逻辑,动态按需向 PATH 注入 Homebrew 常用路径 * 增强失败隔离机制,实现 Cask 批量失败后仅对过期项精准重试 * 优化临时文件管理,改用临时目录并在退出时自动清理相关资源 * 完善网络容错能力,在 bootstrap 阶段增加 curl 重试与超时限制 * 更新文档说明,同步最新的升级策略、并发控制及错误处理逻辑 * 引入终端动态宽度支持,优化非交互式环境下的输出展示效果
108 lines
3.5 KiB
Bash
Executable File
108 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 目标:下载远程升级脚本、执行、销毁临时文件
|
||
set -euo pipefail
|
||
|
||
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
|
||
|
||
echo "正在下载远程脚本..."
|
||
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" ]] || { echo "远程脚本为空,已停止执行。" >&2; exit 1; }
|
||
|
||
if [[ -n "${BREWUP_SHA256:-}" ]]; then
|
||
echo "正在校验脚本 SHA256..."
|
||
actual_sha256="$(shasum -a 256 "$TEMP")"
|
||
actual_sha256="${actual_sha256%% *}"
|
||
if [[ "$actual_sha256" != "$BREWUP_SHA256" ]]; then
|
||
echo "脚本 SHA256 不匹配,已停止执行。" >&2
|
||
echo "Expected: $BREWUP_SHA256" >&2
|
||
echo "Actual: $actual_sha256" >&2
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
bash -n "$TEMP"
|
||
|
||
if [[ "${BREWUP_DEBUG:-0}" == "1" ]]; then
|
||
echo "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 "首次使用:请输入一次 sudo 密码,将保存到 macOS Keychain:"
|
||
IFS= read -r -s BREWUP_SUDO_PASSWORD
|
||
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
|
||
|
||
echo "正在通过 Keychain 准备 sudo 凭据..."
|
||
if ! sudo -A -v; then
|
||
echo "Keychain 中的 sudo 密码不可用,请删除后重新保存:" >&2
|
||
echo " security delete-generic-password -a \"$CURRENT_USER\" -s \"$KEYCHAIN_SERVICE\"" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
setup_sudo_askpass
|
||
|
||
export COLUMNS="${COLUMNS:-130}"
|
||
bash "$TEMP" "$@"
|