feat(homebrew): 优化交互式终端中的 Homebrew 进度显示

- 在交互式终端中保留 Homebrew 6 的原生实时下载进度条和动态状态
- 使用 -t 检查判断终端类型,决定是否启用原生进度条
- 在 macOS 上使用 script(1) 创建伪终端以记录输出到日志
- 重定向到文件或 CI 时自动切换为稳定逐行输出模式
- 通过 HOMEBREW_COLOR 环境变量控制配色方案
- 在 Darwin 系统上检查 script 工具可用性以决定处理方式
This commit is contained in:
2026-07-24 00:59:02 +08:00
parent d090edd5c6
commit 972e7a142d
2 changed files with 21 additions and 3 deletions
+3
View File
@@ -22,6 +22,7 @@
- 同一用户只能运行一个主脚本实例,避免并发升级争用 Homebrew 锁和 `/Applications`
- 升级与失败重试全部结束后,执行 `brew cleanup --prune=all` 清理全部缓存和旧版本。
- 支持 `--width`、环境变量宽度和终端动态宽度。
- 交互式终端中保留 Homebrew 6 的原生实时下载进度条和动态状态。
- 启动器支持通过 macOS Keychain 保存并读取 sudo 密码,用于 `sudo -A -v` 预刷新 sudo 凭据。
## 依赖
@@ -196,6 +197,8 @@ BREWUP_CONNECT_TIMEOUT_SECONDS=20 BREWUP_LOW_SPEED_TIME_SECONDS=45 brewup
为了兼顾性能,Formula 和 Cask 的批量阶段都只执行一次,只有仍然过期的失败项进入单项重试。单项升级保持串行,因为并行运行多个 Homebrew 写操作会争用 Homebrew 锁和 `/Applications`。用于错误分类的临时日志会在命令结束或收到信号后删除。
在交互式终端中,主脚本会让 Homebrew 直接连接 TTY,以便 Homebrew 6 实时重绘并行下载进度。需要记录错误以供重试判断时,macOS 自带的 `script(1)` 会创建伪终端并同步保存日志。如果将 `brewup` 输出重定向到文件或 CI,则自动切换为稳定的逐行输出,不绘制动态进度条。
## Cask 与清理策略
默认不使用 `--force`。确实需要覆盖已有 Cask 文件时:
+18 -3
View File
@@ -573,8 +573,14 @@ colorize_brew_output() {
run_brew_colored() {
local pipeline_status=()
# 禁用 Homebrew 自带的不完整配色,统一按语义着色。这里不能在
# 交互式终端直接运行 brew,否则版本变化行会绕过着色器。
# Homebrew 6 的并行下载队列只有在 stdout 是 TTY 时才会绘制
# 实时进度。交互式终端直接运行 brew保留它的原生进度条与
# 动态下载状态;重定向到文件或 CI 时再使用按行语义着色。
if [[ -t 1 ]]; then
env -u HOMEBREW_COLOR brew "$@"
return $?
fi
if env -u HOMEBREW_COLOR brew "$@" 2>&1 | colorize_brew_output; then
return 0
fi
@@ -698,7 +704,16 @@ run_brew_with_retries() {
fi
: > "$ACTIVE_LOG_FILE"
if env -u HOMEBREW_COLOR brew "$@" 2>&1 | tee "$ACTIVE_LOG_FILE" | colorize_brew_output; then
if [[ -t 1 && "$(uname -s 2>/dev/null || true)" == "Darwin" && -x /usr/bin/script ]]; then
# tee 会把 brew 的 stdout 变成管道,导致 Homebrew 关闭实时进度。
# macOS script(1) 为 brew 分配伪终端,同时把完整输出记录到
# 日志,供后续错误分类与重试决策使用。-F 确保记录实时刷新。
if /usr/bin/script -qF "$ACTIVE_LOG_FILE" env -u HOMEBREW_COLOR brew "$@"; then
status=0
else
status=$?
fi
elif env -u HOMEBREW_COLOR brew "$@" 2>&1 | tee "$ACTIVE_LOG_FILE" | colorize_brew_output; then
status=0
else
pipeline_status=("${PIPESTATUS[@]}")