diff --git a/homebrew/brew-upgrade-manager.sh b/homebrew/brew-upgrade-manager.sh index 51cf905..200d694 100644 --- a/homebrew/brew-upgrade-manager.sh +++ b/homebrew/brew-upgrade-manager.sh @@ -129,6 +129,16 @@ print_info() { printf '%b%s%b\n' "$CYAN" "$*" "$NC" } +print_colored_list() { + local label="$1" color="$2" items="$3" item + + printf '%b%s%b\n' "$color" "$label" "$NC" + while IFS= read -r item; do + [[ -n "$item" ]] || continue + printf ' %b%s%b\n' "$color" "$item" "$NC" + done <<< "$items" +} + is_enabled() { case "${1:-}" in 1|true|TRUE|yes|YES|on|ON) return 0 ;; @@ -279,19 +289,58 @@ run_brew_with_retries() { } get_outdated_formulae() { - brew outdated --formula 2>/dev/null + env -u HOMEBREW_COLOR brew outdated --formula 2>/dev/null } get_outdated_casks() { - brew outdated --cask --greedy 2>/dev/null + env -u HOMEBREW_COLOR brew outdated --cask --greedy 2>/dev/null +} + +run_brew_doctor() { + local output status=0 line + + if output="$(env -u HOMEBREW_COLOR brew doctor 2>&1)"; then + status=0 + else + status=$? + fi + while IFS= read -r line; do + case "$line" in + Warning:*|*deprecated*|*disabled*|*pre-release*|*"find replacements"*|*"do not provide support"*|*"Tier 2 configuration"*) + printf '%b%s%b\n' "$YELLOW" "$line" "$NC" + ;; + ' '*|' https://'*) + printf '%b%s%b\n' "$CYAN" "$line" "$NC" + ;; + *) + printf '%s\n' "$line" + ;; + esac + done <<< "$output" + return "$status" } run_formula_upgrade() { - local bulk_status=0 outdated_formulae remaining_formulae formula + local bulk_status=0 initial_formulae="" initial_formulae_known=1 + local outdated_formulae remaining_formulae formula local failed_formulae=() + if ! initial_formulae="$(get_outdated_formulae)"; then + initial_formulae_known=0 + print_warning "unable to list Formulae requiring updates before upgrade." + elif [[ -n "$initial_formulae" ]]; then + print_colored_list "Formulae requiring updates:" "$YELLOW" "$initial_formulae" + else + print_success "No Formulae require updates." + fi + brew upgrade --formula || bulk_status=$? if ((bulk_status == 0)); then + if ((initial_formulae_known)) && [[ -n "$initial_formulae" ]]; then + print_colored_list "Updated Formulae:" "$GREEN" "$initial_formulae" + else + print_success "Formula upgrade completed." + fi return 0 fi @@ -301,11 +350,14 @@ run_formula_upgrade() { return "$bulk_status" fi if [[ -z "$outdated_formulae" ]]; then - print_notice "No outdated Formulae remain; treating the bulk error as recovered." + if [[ -n "$initial_formulae" ]]; then + print_colored_list "Updated Formulae:" "$GREEN" "$initial_formulae" + else + print_success "No outdated Formulae remain; the bulk error was recovered." + fi return 0 fi - printf '%s\n' "$outdated_formulae" while IFS= read -r formula; do [[ -n "$formula" ]] || continue print_info "Retrying Formula: ${formula}" @@ -322,20 +374,24 @@ run_formula_upgrade() { return 1 fi if [[ -z "$remaining_formulae" ]]; then - print_success "All outdated Formulae were upgraded after isolated retries." + if [[ -n "$initial_formulae" ]]; then + print_colored_list "Updated Formulae after isolated retries:" "$GREEN" "$initial_formulae" + else + print_success "All outdated Formulae were upgraded after isolated retries." + fi return 0 fi while IFS= read -r formula; do [[ -n "$formula" ]] && FAILED_FORMULAE+=("$formula") done <<< "$remaining_formulae" - print_warning "Formulae still outdated after retries:" - printf '%s\n' "$remaining_formulae" + print_colored_list "Outdated Formulae remaining after retries:" "$RED" "$remaining_formulae" return 1 } run_cask_upgrade() { - local bulk_status=0 outdated_casks remaining_casks cask + local bulk_status=0 initial_casks="" initial_casks_known=1 + local outdated_casks remaining_casks cask local bulk_args=(upgrade --cask --greedy) local failed_casks=() @@ -344,8 +400,22 @@ run_cask_upgrade() { print_warning "HB_CASK_FORCE is enabled; existing Cask files may be overwritten." fi + if ! initial_casks="$(get_outdated_casks)"; then + initial_casks_known=0 + print_warning "unable to list Casks requiring updates before upgrade." + elif [[ -n "$initial_casks" ]]; then + print_colored_list "Casks requiring updates:" "$YELLOW" "$initial_casks" + else + print_success "No Casks require updates." + fi + brew "${bulk_args[@]}" || bulk_status=$? if ((bulk_status == 0)); then + if ((initial_casks_known)) && [[ -n "$initial_casks" ]]; then + print_colored_list "Updated Casks:" "$GREEN" "$initial_casks" + else + print_success "Cask upgrade completed." + fi return 0 fi @@ -355,11 +425,14 @@ run_cask_upgrade() { return "$bulk_status" fi if [[ -z "$outdated_casks" ]]; then - print_notice "No outdated Casks remain; treating the bulk error as recovered." + if [[ -n "$initial_casks" ]]; then + print_colored_list "Updated Casks:" "$GREEN" "$initial_casks" + else + print_success "No outdated Casks remain; the bulk error was recovered." + fi return 0 fi - printf '%s\n' "$outdated_casks" while IFS= read -r cask; do [[ -n "$cask" ]] || continue print_info "Retrying Cask: ${cask} (without --force)" @@ -376,15 +449,18 @@ run_cask_upgrade() { return 1 fi if [[ -z "$remaining_casks" ]]; then - print_success "All outdated Casks were upgraded after isolated retries." + if [[ -n "$initial_casks" ]]; then + print_colored_list "Updated Casks after isolated retries:" "$GREEN" "$initial_casks" + else + print_success "All outdated Casks were upgraded after isolated retries." + fi return 0 fi while IFS= read -r cask; do [[ -n "$cask" ]] && FAILED_CASKS+=("$cask") done <<< "$remaining_casks" - print_warning "Casks still outdated after retries:" - printf '%s\n' "$remaining_casks" + print_colored_list "Outdated Casks remaining after retries:" "$RED" "$remaining_casks" return 1 } @@ -405,9 +481,23 @@ format_bytes() { printf '%d.%d %s' "$((tenths / 10))" "$((tenths % 10))" "${units[unit]}" } +is_cache_download_artifact() { + [[ "$1" == downloads/* ]] +} + +cache_artifact_display_name() { + local name="${1#downloads/}" + + # Homebrew 下载文件通常以 SHA-256-- 开头;终端只显示有意义的原文件名。 + [[ "$name" == *--* ]] && name="${name#*--}" + printf '%s' "$name" +} + prune_cache_before_today() { - local cache_dir cutoff_stamp cutoff_date file file_size relative_path + local cache_dir cutoff_stamp cutoff_date file file_size relative_path display_name hidden_count local removed_count=0 removed_bytes=0 kept_count=0 kept_bytes=0 cleanup_failed=0 + local removed_artifact_count=0 removed_artifact_bytes=0 + local kept_artifact_count=0 kept_artifact_bytes=0 cache_dir="$(brew --cache)" if [[ ! -d "$cache_dir" || "$cache_dir" == "/" || "$cache_dir" == "$HOME" ]]; then @@ -429,7 +519,7 @@ prune_cache_before_today() { return 1 fi - printf '%bRemoved cache files:%b\n' "$YELLOW" "$NC" + printf '%bRemoved download artifacts:%b\n' "$YELLOW" "$NC" while IFS= read -r -d '' file; do if ! file_size="$(stat -f '%z' -- "$file" 2>/dev/null)"; then file_size=0 @@ -438,18 +528,25 @@ prune_cache_before_today() { if rm -f -- "$file"; then removed_count=$((removed_count + 1)) removed_bytes=$((removed_bytes + file_size)) - printf ' %b%10s%b %q\n' "$CYAN" "$(format_bytes "$file_size")" "$NC" "$relative_path" + if is_cache_download_artifact "$relative_path"; then + removed_artifact_count=$((removed_artifact_count + 1)) + removed_artifact_bytes=$((removed_artifact_bytes + file_size)) + display_name="$(cache_artifact_display_name "$relative_path")" + printf ' %b%10s%b %q\n' "$CYAN" "$(format_bytes "$file_size")" "$NC" "$display_name" + fi else print_warning "failed to remove cache file: $file" >&2 cleanup_failed=1 fi done < "$ACTIVE_CLEANUP_MANIFEST" - if ((removed_count == 0)); then - printf ' (none)\n' - fi - printf '%bRemoved%b %b%d%b Homebrew cache file(s) dated before %b%s%b (%b%s total%b).\n' \ - "$YELLOW" "$NC" "$CYAN" "$removed_count" "$NC" "$BLUE" "$cutoff_date" "$NC" \ - "$CYAN" "$(format_bytes "$removed_bytes")" "$NC" + ((removed_artifact_count > 0)) || printf ' (none)\n' + hidden_count=$((removed_count - removed_artifact_count)) + printf '%bRemoved:%b %b%d files / %s%b before %b%s%b.\n' \ + "$YELLOW" "$NC" "$CYAN" "$removed_count" "$(format_bytes "$removed_bytes")" "$NC" \ + "$BLUE" "$cutoff_date" "$NC" + printf ' Downloads shown: %b%d / %s%b; internal files hidden: %b%d%b.\n' \ + "$CYAN" "$removed_artifact_count" "$(format_bytes "$removed_artifact_bytes")" "$NC" \ + "$CYAN" "$hidden_count" "$NC" if ! find "$cache_dir" -mindepth 1 \( -type f -o -type l \) \ -newer "$ACTIVE_CLEANUP_MARKER" -print0 > "$ACTIVE_CLEANUP_MANIFEST"; then @@ -457,7 +554,7 @@ prune_cache_before_today() { return 1 fi - printf '%bRetained cache files dated today or later:%b\n' "$GREEN" "$NC" + printf '%bRetained download artifacts from today:%b\n' "$GREEN" "$NC" while IFS= read -r -d '' file; do if ! file_size="$(stat -f '%z' -- "$file" 2>/dev/null)"; then file_size=0 @@ -465,14 +562,21 @@ prune_cache_before_today() { relative_path="${file#"$cache_dir"/}" kept_count=$((kept_count + 1)) kept_bytes=$((kept_bytes + file_size)) - printf ' %b%10s%b %q\n' "$CYAN" "$(format_bytes "$file_size")" "$NC" "$relative_path" + if is_cache_download_artifact "$relative_path"; then + kept_artifact_count=$((kept_artifact_count + 1)) + kept_artifact_bytes=$((kept_artifact_bytes + file_size)) + display_name="$(cache_artifact_display_name "$relative_path")" + printf ' %b%10s%b %q\n' "$CYAN" "$(format_bytes "$file_size")" "$NC" "$display_name" + fi done < "$ACTIVE_CLEANUP_MANIFEST" - if ((kept_count == 0)); then - printf ' (none)\n' - fi - printf '%bRetained%b %b%d%b Homebrew cache file(s) dated %b%s%b or later (%b%s total%b).\n' \ - "$GREEN" "$NC" "$CYAN" "$kept_count" "$NC" "$BLUE" "$cutoff_date" "$NC" \ - "$CYAN" "$(format_bytes "$kept_bytes")" "$NC" + ((kept_artifact_count > 0)) || printf ' (none)\n' + hidden_count=$((kept_count - kept_artifact_count)) + printf '%bRetained:%b %b%d files / %s%b dated %b%s%b or later.\n' \ + "$GREEN" "$NC" "$CYAN" "$kept_count" "$(format_bytes "$kept_bytes")" "$NC" \ + "$BLUE" "$cutoff_date" "$NC" + printf ' Downloads shown: %b%d / %s%b; internal files hidden: %b%d%b.\n' \ + "$CYAN" "$kept_artifact_count" "$(format_bytes "$kept_artifact_bytes")" "$NC" \ + "$CYAN" "$hidden_count" "$NC" rm -f "$ACTIVE_CLEANUP_MARKER" ACTIVE_CLEANUP_MARKER="" @@ -543,7 +647,7 @@ separator print_header "Step 2: Performing health check (brew doctor)" if is_enabled "${HB_SKIP_DOCTOR:-0}"; then print_notice "brew doctor skipped because HB_SKIP_DOCTOR is enabled." -elif ! brew doctor; then +elif ! run_brew_doctor; then print_warning "'brew doctor' detected issues. Manual review is recommended." else print_success "Homebrew environment is in good health." @@ -570,7 +674,7 @@ separator printf '\n' separator -print_header "Step 4: Cleaning cache dated before today (keeping today's downloads)" +print_header "Step 4: Cleaning old cache (showing download artifacts only)" if ! run_cleanup; then overall_status=1 fi