# ============================================================================= # ui.sh — Wspólny interfejs użytkownika dla buildera PaganOS # ============================================================================= # Zapewnia: # • spinner + czas trwania podczas budowy pakietu (tryb TTY) # • logi per-pakiet w $UI_LOG_DIR (zawsze) # • licznik postępu [N/TOTAL] i listę nieudanych pakietów # • czytelne podsumowanie na końcu budowy # W trybie non-TTY (CI, pipe) zachowuje proste linie + pełny log per pakiet. # ============================================================================= [[ -n "${UI_LOADED:-}" ]] && return 0 UI_LOADED=1 # ---- kolory (jeśli nie zdefiniowane przez skrypt źródłowy) ---- : "${RED:=\033[0;31m}" "${GREEN:=\033[0;32m}" "${YELLOW:=\033[1;33m}" : "${BLUE:=\033[0;34m}" "${MAGENTA:=\033[0;35m}" "${CYAN:=\033[0;36m}" : "${BOLD:=\033[1m}" "${DIM:=\033[2m}" "${NC:=\033[0m}" # ---- konfiguracja ---- UI_TTY=0; [[ -t 1 ]] && UI_TTY=1 UI_START_EPOCH=$(date +%s) UI_PKG_N=0 UI_PKG_TOTAL=0 UI_LOG_DIR="${UI_LOG_DIR:-/var/log/pagan-pkgs}" UI_TAIL_LINES="${UI_TAIL_LINES:-15}" UI_FAILED=() SPIN=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏') ui_init() { mkdir -p "$UI_LOG_DIR" 2>/dev/null || true } ui_fmt_duration() { local s="${1:-0}" h m h=$((s / 3600)); m=$(((s % 3600) / 60)); s=$((s % 60)) printf '%02d:%02d:%02d' "$h" "$m" "$s" } # Nadpisuje bieżącą linię statusu (tylko TTY) _ui_status() { [[ $UI_TTY -ne 1 ]] && return 0 printf '\r\033[K%s' "$*" } _ui_clear_status() { [[ $UI_TTY -ne 1 ]] && return 0 printf '\r\033[K' } # Resetuje licznik postępu dla nowego rozdziału ui_set_total() { UI_PKG_TOTAL="${1:-0}" UI_PKG_N=0 } # Pokazuje ostatnie N linii logu pakietu (po błędzie) _ui_tail() { local log="$1" n="${2:-15}" [[ -f "$log" ]] || return 0 echo -e " ${DIM}└─ Ostatnie linie z: ${log}${NC}" tail -n "$n" "$log" | sed 's/^/ /' } # Uruchamia komendę budowy z capture outputu do logu per-pakiet. # Zwraca kod wyjścia; po sukcesie drukuje ✓, po błędzie ✗ + tail logu. ui_build_eval() { local label="$1" log="$2" cmd="$3" local start_epoch rc el i start_epoch=$(date +%s) local counter if [[ $UI_PKG_TOTAL -gt 0 ]]; then counter="[${UI_PKG_N}/${UI_PKG_TOTAL}]" else counter="[#${UI_PKG_N}]" fi if [[ $UI_TTY -eq 1 ]]; then ( eval "$cmd" ) > "$log" 2>&1 & local pid=$! i=0 while kill -0 "$pid" 2>/dev/null; do el=$(( $(date +%s) - start_epoch )) _ui_status " ${SPIN[i % ${#SPIN[@]}]} ${counter} ${label} [$(ui_fmt_duration "$el")]" i=$((i + 1)) sleep 0.2 done rc=0; wait "$pid" || rc=$? _ui_clear_status else echo " ▶ ${counter} ${label}" ( eval "$cmd" ) > "$log" 2>&1 rc=$? fi el=$(( $(date +%s) - start_epoch )) if [[ $rc -eq 0 ]]; then echo -e " ${GREEN}✓${NC} ${counter} ${label} [$(ui_fmt_duration "$el")]" else echo -e " ${RED}✗${NC} ${counter} ${label} [$(ui_fmt_duration "$el")]" UI_FAILED+=("$label") _ui_tail "$log" "$UI_TAIL_LINES" fi return "$rc" } # Linia pominięcia pakietu (resume) ui_skip() { local label="$1" local counter if [[ $UI_PKG_TOTAL -gt 0 ]]; then counter="[${UI_PKG_N}/${UI_PKG_TOTAL}]" else counter="[#${UI_PKG_N}]" fi echo -e " ${DIM}⏭${NC} ${counter} ${label} ${DIM}(już zbudowany)${NC}" } # Podsumowanie końcowe ui_summary() { local total_sec elapsed total_sec=$(( $(date +%s) - UI_START_EPOCH )) elapsed=$(ui_fmt_duration "$total_sec") echo "" echo -e "${BOLD}════════════════════════════════════════════════════════════════════${NC}" echo -e "${BOLD} PODSUMOWANIE BUDOWY (czas: ${elapsed})${NC}" echo -e "${BOLD}════════════════════════════════════════════════════════════════════${NC}" echo -e " ${GREEN}✓ Zbudowano:${NC} ${PKG_BUILT}" echo -e " ${RED}✗ Błędy:${NC} ${PKG_FAILED}" echo -e " ${DIM}⏭ Pominięto:${NC} ${PKG_SKIPPED}" echo -e " ${CYAN}Log główny:${NC} ${LOG_FILE}" echo -e " ${CYAN}Raport:${NC} ${SUMMARY_FILE}" echo -e " ${CYAN}Logi pakietów:${NC} ${UI_LOG_DIR}" if [[ ${#UI_FAILED[@]} -gt 0 ]]; then echo "" echo -e " ${RED}Nieudane pakiety:${NC}" local p for p in "${UI_FAILED[@]}"; do echo -e " ${RED}✗${NC} $p" done fi echo -e "${BOLD}════════════════════════════════════════════════════════════════════${NC}" }