♻️ refactor(core): 优化 Homebrew 智能升级管理脚本
* 优化 Shell 环境设置,采用 set -euo pipefail 提升脚本鲁棒性 * 改进路径处理逻辑,动态按需向 PATH 注入 Homebrew 常用路径 * 增强失败隔离机制,实现 Cask 批量失败后仅对过期项精准重试 * 优化临时文件管理,改用临时目录并在退出时自动清理相关资源 * 完善网络容错能力,在 bootstrap 阶段增加 curl 重试与超时限制 * 更新文档说明,同步最新的升级策略、并发控制及错误处理逻辑 * 引入终端动态宽度支持,优化非交互式环境下的输出展示效果
This commit is contained in:
@@ -1,12 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Homebrew 智能升级脚本(Cask 失败隔离与重试版)
|
||||
# Homebrew 智能升级脚本(失败隔离、选择性重试与性能优化版)
|
||||
|
||||
# ================== 脚本环境设置 ==================
|
||||
|
||||
# set -e:当命令返回非零退出状态(表示失败)时,脚本会立即退出。
|
||||
set -e
|
||||
# set -o pipefail:在管道命令中,如果任何一个子命令失败,整个管道即为失败。
|
||||
set -o pipefail
|
||||
set -euo pipefail
|
||||
|
||||
prepend_path_once() {
|
||||
local dir="$1"
|
||||
@@ -21,13 +16,13 @@ prepend_path_once "/usr/local/sbin"
|
||||
prepend_path_once "/opt/homebrew/sbin"
|
||||
export PATH
|
||||
|
||||
# --- 颜色定义 (自动检测终端是否支持) ---
|
||||
if [ -t 1 ]; then
|
||||
if [[ -t 1 ]]; then
|
||||
GREEN='\033[1;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[1;34m'
|
||||
CYAN='\033[1;36m'
|
||||
NC='\033[0m'
|
||||
export HOMEBREW_COLOR=1
|
||||
else
|
||||
GREEN=''
|
||||
YELLOW=''
|
||||
@@ -36,35 +31,165 @@ else
|
||||
NC=''
|
||||
fi
|
||||
|
||||
# --- 终端宽度和打印函数 ---
|
||||
TERMINAL_WIDTH="130"
|
||||
TERMINAL_WIDTH=""
|
||||
ACTIVE_LOG_FILE=""
|
||||
LOCK_ACQUIRED=0
|
||||
LOCK_DIR="${HB_LOCK_DIR:-${TMPDIR:-/tmp}/brewup-$(id -u).lock}"
|
||||
FAILED_FORMULAE=()
|
||||
FAILED_CASKS=()
|
||||
|
||||
terminal_width() {
|
||||
printf "%s" "$TERMINAL_WIDTH"
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: brew-upgrade-manager.sh [--width N]
|
||||
|
||||
Options:
|
||||
--width N, --width=N Set output width (40-500).
|
||||
-h, --help Show this help.
|
||||
EOF
|
||||
}
|
||||
|
||||
separator() { local width; width=$(terminal_width); printf '=%.0s' $(seq 1 "$width"); printf "\n"; }
|
||||
print_header() { echo -e "${BLUE}$1${NC}"; }
|
||||
parse_args() {
|
||||
while (($# > 0)); do
|
||||
case "$1" in
|
||||
--width)
|
||||
[[ $# -ge 2 ]] || { echo "Error: --width requires a value." >&2; exit 2; }
|
||||
TERMINAL_WIDTH="$2"
|
||||
shift 2
|
||||
;;
|
||||
--width=*)
|
||||
TERMINAL_WIDTH="${1#*=}"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unknown argument: $1" >&2
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
retry_delay_seconds() {
|
||||
local delay="${HB_RETRY_DELAY_SECONDS:-5}"
|
||||
[[ "$delay" =~ ^[0-9]+$ ]] || delay=5
|
||||
printf '%s' "$delay"
|
||||
resolve_terminal_width() {
|
||||
if [[ -z "$TERMINAL_WIDTH" ]]; then
|
||||
TERMINAL_WIDTH="${HB_TERMINAL_WIDTH:-}"
|
||||
fi
|
||||
if [[ -z "$TERMINAL_WIDTH" ]] && [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
|
||||
TERMINAL_WIDTH="$(tput cols 2>/dev/null || true)"
|
||||
fi
|
||||
[[ -n "$TERMINAL_WIDTH" ]] || TERMINAL_WIDTH=130
|
||||
|
||||
if [[ ! "$TERMINAL_WIDTH" =~ ^[0-9]+$ ]] || ((TERMINAL_WIDTH < 40 || TERMINAL_WIDTH > 500)); then
|
||||
echo "Error: terminal width must be an integer between 40 and 500." >&2
|
||||
exit 2
|
||||
fi
|
||||
export COLUMNS="$TERMINAL_WIDTH"
|
||||
}
|
||||
|
||||
separator() {
|
||||
local i
|
||||
for ((i = 0; i < TERMINAL_WIDTH; i++)); do
|
||||
printf '='
|
||||
done
|
||||
printf '\n'
|
||||
}
|
||||
|
||||
print_header() {
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
}
|
||||
|
||||
is_enabled() {
|
||||
case "${1:-}" in
|
||||
1|true|TRUE|yes|YES|on|ON) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2329 # Invoked by EXIT trap.
|
||||
cleanup_runtime() {
|
||||
if [[ -n "${ACTIVE_LOG_FILE:-}" && -f "$ACTIVE_LOG_FILE" ]]; then
|
||||
rm -f "$ACTIVE_LOG_FILE"
|
||||
fi
|
||||
if ((LOCK_ACQUIRED)); then
|
||||
rm -f "$LOCK_DIR/pid"
|
||||
rmdir "$LOCK_DIR" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2329 # Invoked by INT trap.
|
||||
on_interrupt() {
|
||||
exit 130
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2329 # Invoked by TERM trap.
|
||||
on_terminate() {
|
||||
exit 143
|
||||
}
|
||||
|
||||
trap cleanup_runtime EXIT
|
||||
trap on_interrupt INT
|
||||
trap on_terminate TERM
|
||||
|
||||
acquire_lock() {
|
||||
local existing_pid=""
|
||||
|
||||
if mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||
LOCK_ACQUIRED=1
|
||||
printf '%s\n' "$$" > "$LOCK_DIR/pid"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -r "$LOCK_DIR/pid" ]]; then
|
||||
IFS= read -r existing_pid < "$LOCK_DIR/pid" || true
|
||||
fi
|
||||
if [[ "$existing_pid" =~ ^[0-9]+$ ]] && kill -0 "$existing_pid" 2>/dev/null; then
|
||||
echo "Error: another brewup process is already running (PID ${existing_pid})." >&2
|
||||
exit 75
|
||||
fi
|
||||
|
||||
rm -f "$LOCK_DIR/pid" 2>/dev/null || true
|
||||
rmdir "$LOCK_DIR" 2>/dev/null || {
|
||||
echo "Error: unable to remove stale lock directory: $LOCK_DIR" >&2
|
||||
exit 75
|
||||
}
|
||||
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||
echo "Error: another brewup process acquired the lock." >&2
|
||||
exit 75
|
||||
fi
|
||||
LOCK_ACQUIRED=1
|
||||
printf '%s\n' "$$" > "$LOCK_DIR/pid"
|
||||
}
|
||||
|
||||
retry_attempts() {
|
||||
local attempts="${HB_RETRY_ATTEMPTS:-3}"
|
||||
[[ "$attempts" =~ ^[1-9][0-9]*$ ]] || attempts=3
|
||||
if [[ ! "$attempts" =~ ^[1-9][0-9]*$ ]] || ((attempts > 10)); then
|
||||
attempts=3
|
||||
fi
|
||||
printf '%s' "$attempts"
|
||||
}
|
||||
|
||||
retry_delay_seconds() {
|
||||
local delay="${HB_RETRY_DELAY_SECONDS:-5}"
|
||||
if [[ ! "$delay" =~ ^[0-9]+$ ]] || ((delay > 300)); then
|
||||
delay=5
|
||||
fi
|
||||
printf '%s' "$delay"
|
||||
}
|
||||
|
||||
is_non_retryable_brew_error() {
|
||||
local log_file="$1"
|
||||
grep -Eiq \
|
||||
'Running Homebrew as root|Permission denied|Operation not permitted|No space left on device|checksum mismatch|SHA-?256 mismatch|certificate verify failed|SSL certificate problem|curl: \((3|23|26|60)\)|unknown (option|argument)|invalid (option|argument)' \
|
||||
"$log_file"
|
||||
}
|
||||
|
||||
is_retryable_brew_error() {
|
||||
local log_file="$1"
|
||||
|
||||
# 网络、下载和服务端短暂错误适合重试;权限、root、签名和配置错误
|
||||
# 通常是确定性失败,重试只会浪费时间并重复修改应用。
|
||||
grep -Eiq \
|
||||
'curl: \([0-9]+\)|Transferred a partial file|Could not resolve host|timed out|timeout|connection (reset|refused|closed)|network|HTTP (5[0-9]{2}|429)|temporarily unavailable|failed to download|download.*failed' \
|
||||
'curl: \((5|6|7|18|28|35|52|55|56|92)\)|Transferred a partial file|Could not resolve host|timed out|timeout|connection (reset|refused|closed)|HTTP[^0-9]*(429|5[0-9]{2})|returned error: (429|5[0-9]{2})|temporarily unavailable|failed to download|download.*failed|RPC failed|early EOF|remote end hung up|unexpected disconnect' \
|
||||
"$log_file"
|
||||
}
|
||||
|
||||
@@ -72,135 +197,253 @@ run_brew_with_retries() {
|
||||
local label="$1"
|
||||
shift
|
||||
|
||||
local attempts delay attempt status log_file
|
||||
local attempts delay attempt status next_delay
|
||||
local pipeline_status=()
|
||||
attempts="$(retry_attempts)"
|
||||
delay="$(retry_delay_seconds)"
|
||||
log_file="$(mktemp "${TMPDIR:-/tmp}/brewup-retry.XXXXXX.log")"
|
||||
ACTIVE_LOG_FILE="$(mktemp "${TMPDIR:-/tmp}/brewup-retry.XXXXXX.log")"
|
||||
|
||||
for ((attempt = 1; attempt <= attempts; attempt++)); do
|
||||
if ((attempt > 1)); then
|
||||
echo -e "${YELLOW}Retrying ${label} (${attempt}/${attempts}) after ${delay}s...${NC}"
|
||||
sleep "$delay"
|
||||
delay=$((delay * 2))
|
||||
next_delay=$((delay * 2))
|
||||
((next_delay > 300)) && next_delay=300
|
||||
delay="$next_delay"
|
||||
fi
|
||||
|
||||
# stdout 直接输出,避免正常升级时把大量进度信息落盘;只复制通常包含
|
||||
# 错误详情的 stderr,用于失败分类,同时保持实时终端输出。
|
||||
: > "$log_file"
|
||||
if brew "$@" 2> >(tee "$log_file" >&2); then
|
||||
rm -f "$log_file"
|
||||
return 0
|
||||
: > "$ACTIVE_LOG_FILE"
|
||||
if brew "$@" 2>&1 | tee "$ACTIVE_LOG_FILE"; then
|
||||
status=0
|
||||
else
|
||||
status=$?
|
||||
pipeline_status=("${PIPESTATUS[@]}")
|
||||
status="${pipeline_status[0]}"
|
||||
if ((${pipeline_status[1]:-0} != 0)); then
|
||||
echo "Error: failed to write retry log." >&2
|
||||
status="${pipeline_status[1]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ((attempt == attempts)) || ! is_retryable_brew_error "$log_file"; then
|
||||
rm -f "$log_file"
|
||||
if ((status == 0)); then
|
||||
rm -f "$ACTIVE_LOG_FILE"
|
||||
ACTIVE_LOG_FILE=""
|
||||
return 0
|
||||
fi
|
||||
|
||||
if is_non_retryable_brew_error "$ACTIVE_LOG_FILE"; then
|
||||
rm -f "$ACTIVE_LOG_FILE"
|
||||
ACTIVE_LOG_FILE=""
|
||||
return "$status"
|
||||
fi
|
||||
if ((attempt == attempts)) || ! is_retryable_brew_error "$ACTIVE_LOG_FILE"; then
|
||||
rm -f "$ACTIVE_LOG_FILE"
|
||||
ACTIVE_LOG_FILE=""
|
||||
return "$status"
|
||||
fi
|
||||
echo -e "${YELLOW}${label} failed with a retryable error.${NC}"
|
||||
done
|
||||
}
|
||||
|
||||
get_outdated_formulae() {
|
||||
brew outdated --formula 2>/dev/null
|
||||
}
|
||||
|
||||
get_outdated_casks() {
|
||||
brew outdated --cask --greedy 2>/dev/null
|
||||
}
|
||||
|
||||
run_formula_upgrade() {
|
||||
local bulk_status=0 outdated_formulae remaining_formulae formula
|
||||
local failed_formulae=()
|
||||
|
||||
brew upgrade --formula || bulk_status=$?
|
||||
if ((bulk_status == 0)); then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Warning: Formula upgrade returned ${bulk_status}; checking remaining Formulae...${NC}"
|
||||
if ! outdated_formulae="$(get_outdated_formulae)"; then
|
||||
echo -e "${YELLOW}Warning: unable to verify outdated Formulae.${NC}"
|
||||
return "$bulk_status"
|
||||
fi
|
||||
if [[ -z "$outdated_formulae" ]]; then
|
||||
echo -e "${YELLOW}No outdated Formulae remain; treating the bulk error as recovered.${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '%s\n' "$outdated_formulae"
|
||||
while IFS= read -r formula; do
|
||||
[[ -n "$formula" ]] || continue
|
||||
echo -e "${CYAN}Retrying Formula: ${formula}${NC}"
|
||||
if run_brew_with_retries "Formula ${formula}" upgrade --formula "$formula"; then
|
||||
:
|
||||
else
|
||||
failed_formulae+=("$formula")
|
||||
fi
|
||||
done <<< "$outdated_formulae"
|
||||
|
||||
if ! remaining_formulae="$(get_outdated_formulae)"; then
|
||||
echo -e "${YELLOW}Warning: unable to verify Formulae after individual retries.${NC}"
|
||||
FAILED_FORMULAE=("${failed_formulae[@]}")
|
||||
return 1
|
||||
fi
|
||||
if [[ -z "$remaining_formulae" ]]; then
|
||||
echo -e "${GREEN}All outdated Formulae were upgraded after isolated retries.${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
while IFS= read -r formula; do
|
||||
[[ -n "$formula" ]] && FAILED_FORMULAE+=("$formula")
|
||||
done <<< "$remaining_formulae"
|
||||
echo -e "${YELLOW}Formulae still outdated after retries:${NC}"
|
||||
printf '%s\n' "$remaining_formulae"
|
||||
return 1
|
||||
}
|
||||
|
||||
run_cask_upgrade() {
|
||||
local status=0 outdated_casks remaining_casks cask
|
||||
local bulk_status=0 outdated_casks remaining_casks cask
|
||||
local bulk_args=(upgrade --cask --greedy)
|
||||
local failed_casks=()
|
||||
|
||||
# 批量阶段只执行一次,让 Homebrew 并发获取下载;失败后只处理仍然过期
|
||||
# 的 Cask,避免重跑整个批次和重复检查已经升级成功的应用。
|
||||
brew upgrade --cask --greedy --force || status=$?
|
||||
if [[ "$status" -eq 0 ]]; then
|
||||
if is_enabled "${HB_CASK_FORCE:-0}"; then
|
||||
bulk_args+=(--force)
|
||||
echo -e "${YELLOW}HB_CASK_FORCE is enabled; existing Cask files may be overwritten.${NC}"
|
||||
fi
|
||||
|
||||
brew "${bulk_args[@]}" || bulk_status=$?
|
||||
if ((bulk_status == 0)); then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Warning: Cask upgrade reported a non-zero exit code (${status}). Verifying whether outdated casks remain...${NC}"
|
||||
|
||||
if ! outdated_casks="$(brew outdated --cask --greedy 2>/dev/null)"; then
|
||||
echo -e "${YELLOW}Warning: Unable to verify outdated casks after the failed upgrade command.${NC}"
|
||||
return "$status"
|
||||
echo -e "${YELLOW}Warning: Cask upgrade returned ${bulk_status}; checking remaining Casks...${NC}"
|
||||
if ! outdated_casks="$(get_outdated_casks)"; then
|
||||
echo -e "${YELLOW}Warning: unable to verify outdated Casks.${NC}"
|
||||
return "$bulk_status"
|
||||
fi
|
||||
|
||||
if [[ -z "$outdated_casks" ]]; then
|
||||
echo -e "${YELLOW}Warning: No outdated casks remain. Treating the previous Cask error as transient and continuing.${NC}"
|
||||
echo -e "${YELLOW}No outdated Casks remain; treating the bulk error as recovered.${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}The following casks still appear to be outdated; retrying individually:${NC}"
|
||||
printf '%s\n' "$outdated_casks"
|
||||
|
||||
while IFS= read -r cask; do
|
||||
[[ -n "$cask" ]] || continue
|
||||
echo -e "${CYAN}Retrying Cask: ${cask} (without --force)${NC}"
|
||||
if ! run_brew_with_retries "Cask ${cask}" upgrade --cask --greedy "$cask"; then
|
||||
if run_brew_with_retries "Cask ${cask}" upgrade --cask --greedy "$cask"; then
|
||||
:
|
||||
else
|
||||
failed_casks+=("$cask")
|
||||
fi
|
||||
done <<< "$outdated_casks"
|
||||
|
||||
if ! remaining_casks="$(brew outdated --cask --greedy 2>/dev/null)"; then
|
||||
echo -e "${YELLOW}Warning: Unable to verify outdated Casks after individual retries.${NC}"
|
||||
return "$status"
|
||||
if ! remaining_casks="$(get_outdated_casks)"; then
|
||||
echo -e "${YELLOW}Warning: unable to verify Casks after individual retries.${NC}"
|
||||
FAILED_CASKS=("${failed_casks[@]}")
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$remaining_casks" ]]; then
|
||||
echo -e "${GREEN}All outdated Casks were upgraded after retrying individually.${NC}"
|
||||
echo -e "${GREEN}All outdated Casks were upgraded after isolated retries.${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}The following Casks remain outdated after retries:${NC}"
|
||||
while IFS= read -r cask; do
|
||||
[[ -n "$cask" ]] && FAILED_CASKS+=("$cask")
|
||||
done <<< "$remaining_casks"
|
||||
echo -e "${YELLOW}Casks still outdated after retries:${NC}"
|
||||
printf '%s\n' "$remaining_casks"
|
||||
if ((${#failed_casks[@]} > 0)); then
|
||||
echo -e "${YELLOW}These Casks failed during individual retries: ${failed_casks[*]}${NC}"
|
||||
fi
|
||||
return "$status"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ================== 流程开始 ==================
|
||||
separator
|
||||
run_cleanup() {
|
||||
local cleanup_days="${HB_CLEANUP_DAYS:-}"
|
||||
|
||||
if is_enabled "${HB_SKIP_CLEANUP:-0}"; then
|
||||
echo -e "${YELLOW}Cleanup skipped because HB_SKIP_CLEANUP is enabled.${NC}"
|
||||
return 0
|
||||
fi
|
||||
if is_enabled "${HB_CLEANUP_ALL:-0}"; then
|
||||
brew cleanup --prune=all
|
||||
return
|
||||
fi
|
||||
if [[ -n "$cleanup_days" ]]; then
|
||||
if [[ ! "$cleanup_days" =~ ^[0-9]+$ ]] || ((cleanup_days > 3650)); then
|
||||
echo "Error: HB_CLEANUP_DAYS must be an integer between 0 and 3650." >&2
|
||||
return 2
|
||||
fi
|
||||
brew cleanup --prune="$cleanup_days"
|
||||
return
|
||||
fi
|
||||
brew cleanup
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local overall_status="$1"
|
||||
|
||||
separator
|
||||
if ((overall_status == 0)); then
|
||||
echo -e "${GREEN}All operations completed successfully.${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Homebrew upgrade completed with unresolved failures.${NC}"
|
||||
if ((${#FAILED_FORMULAE[@]} > 0)); then
|
||||
printf 'Failed Formulae: %s\n' "${FAILED_FORMULAE[*]}"
|
||||
fi
|
||||
if ((${#FAILED_CASKS[@]} > 0)); then
|
||||
printf 'Failed Casks: %s\n' "${FAILED_CASKS[*]}"
|
||||
fi
|
||||
fi
|
||||
separator
|
||||
}
|
||||
|
||||
parse_args "$@"
|
||||
resolve_terminal_width
|
||||
|
||||
command -v brew >/dev/null 2>&1 || { echo "Error: Homebrew is not installed or not in PATH." >&2; exit 127; }
|
||||
command -v tee >/dev/null 2>&1 || { echo "Error: tee is required." >&2; exit 127; }
|
||||
acquire_lock
|
||||
|
||||
separator
|
||||
print_header "Step 1: Updating Homebrew repositories (brew update -v)"
|
||||
run_brew_with_retries "Homebrew repository update" update -v
|
||||
separator
|
||||
printf "\n"
|
||||
printf '\n'
|
||||
|
||||
separator
|
||||
print_header "Step 2: Performing health check (brew doctor)"
|
||||
if ! brew doctor; then
|
||||
echo -e "${YELLOW}Warning: 'brew doctor' detected issues. Manual review and resolution are recommended.${NC}"
|
||||
if is_enabled "${HB_SKIP_DOCTOR:-0}"; then
|
||||
echo -e "${YELLOW}brew doctor skipped because HB_SKIP_DOCTOR is enabled.${NC}"
|
||||
elif ! brew doctor; then
|
||||
echo -e "${YELLOW}Warning: 'brew doctor' detected issues. Manual review is recommended.${NC}"
|
||||
else
|
||||
echo "Homebrew environment is in good health."
|
||||
fi
|
||||
separator
|
||||
printf "\n"
|
||||
printf '\n'
|
||||
|
||||
separator
|
||||
print_header "Step 3: Executing comprehensive upgrades (Formulae & Casks)"
|
||||
echo -e "${NC}"
|
||||
print_header "Step 3: Upgrading Formulae and Casks with failure isolation"
|
||||
overall_status=0
|
||||
|
||||
# 1. 升级命令行工具 (Formulae)
|
||||
echo -e "\n${CYAN}>>> [1/2] Upgrading CLI Formulae (brew upgrade --formula)...${NC}"
|
||||
run_brew_with_retries "Formula upgrade" upgrade --formula
|
||||
echo -e "\n${CYAN}>>> [1/2] Upgrading CLI Formulae...${NC}"
|
||||
if ! run_formula_upgrade; then
|
||||
overall_status=1
|
||||
fi
|
||||
|
||||
# 2. 升级图形界面软件 (Casks)
|
||||
echo -e "\n${CYAN}>>> [2/2] Upgrading GUI Casks (bulk --force, then isolated retries)...${NC}"
|
||||
|
||||
# 强制注入环境变量,确保终端输出依然保留 ANSI 颜色格式
|
||||
export HOMEBREW_COLOR=1
|
||||
|
||||
# --- 终端宽度处理 ---
|
||||
# 固定宽度,避免动态识别终端列数导致 prompt 重绘异常。
|
||||
export COLUMNS
|
||||
COLUMNS="$(terminal_width)"
|
||||
|
||||
run_cask_upgrade
|
||||
echo -e "\n${CYAN}>>> [2/2] Upgrading GUI Casks...${NC}"
|
||||
if ! run_cask_upgrade; then
|
||||
overall_status=1
|
||||
fi
|
||||
separator
|
||||
printf '\n'
|
||||
|
||||
separator
|
||||
printf "\n"
|
||||
|
||||
print_header "Step 4: Cleaning up old files and caches"
|
||||
if ((overall_status != 0)) && ! is_enabled "${HB_CLEANUP_ON_FAILURE:-0}"; then
|
||||
echo -e "${YELLOW}Cleanup skipped because upgrades failed; cached downloads are preserved for the next retry.${NC}"
|
||||
elif ! run_cleanup; then
|
||||
overall_status=1
|
||||
fi
|
||||
separator
|
||||
print_header "Step 4: Cleaning up old files and caches (brew cleanup --prune=all)"
|
||||
brew cleanup --prune=all
|
||||
separator
|
||||
printf "\n"
|
||||
printf '\n'
|
||||
|
||||
echo -e "${GREEN}All operations completed!${NC}"
|
||||
printf "\n"
|
||||
print_summary "$overall_status"
|
||||
exit "$overall_status"
|
||||
|
||||
Reference in New Issue
Block a user