diff --git a/apps/rebreak-native/deploy.sh b/apps/rebreak-native/deploy.sh index 70a6a35..7b6b518 100755 --- a/apps/rebreak-native/deploy.sh +++ b/apps/rebreak-native/deploy.sh @@ -93,9 +93,76 @@ run() { fi } +# Runtime-Cache für Progress-Bar (lernt Dauer pro Step über Runs hinweg) +RUNTIME_CACHE="$SCRIPT_DIR/tmp/.deploy-runtimes" +mkdir -p "$(dirname "$RUNTIME_CACHE")" +runtime_lookup() { + local label="$1" + [[ -f "$RUNTIME_CACHE" ]] || return 1 + grep -aE "^$(printf '%s' "$label" | sed 's/[][\.*^$/]/\\&/g')\|" "$RUNTIME_CACHE" 2>/dev/null \ + | tail -1 | cut -d'|' -f2 +} +runtime_save() { + local label="$1" duration="$2" + # Keep only last entry per label + if [[ -f "$RUNTIME_CACHE" ]]; then + grep -avE "^$(printf '%s' "$label" | sed 's/[][\.*^$/]/\\&/g')\|" "$RUNTIME_CACHE" > "$RUNTIME_CACHE.tmp" || true + mv "$RUNTIME_CACHE.tmp" "$RUNTIME_CACHE" + fi + echo "$label|$duration" >> "$RUNTIME_CACHE" +} + +# Render brew-style progress bar: ████████░░░░░░░░ 42% (1m23s / ~3m18s) +render_progress() { + local elapsed="$1" expected="$2" label="$3" subtitle="$4" + local width=30 pct filled empty bar elapsed_h expected_h + if (( expected > 0 )); then + pct=$(( elapsed * 100 / expected )) + (( pct > 99 )) && pct=99 # never show 100% while still running + filled=$(( elapsed * width / expected )) + (( filled > width )) && filled=$width + else + pct=0; filled=0 + fi + empty=$(( width - filled )) + bar=$(printf '%*s' "$filled" '' | tr ' ' '█')$(printf '%*s' "$empty" '' | tr ' ' '░') + elapsed_h=$(format_duration "$elapsed") + if (( expected > 0 )); then + expected_h=$(format_duration "$expected") + if [[ -n "$subtitle" ]]; then + printf '\r\033[K%s==>%s %s\n %s %s%3d%%%s (%s / ~%s) %s%s↳ %s%s\033[1A' \ + "$BLUE" "$RESET" "$label" "$bar" "$YELLOW" "$pct" "$RESET" "$elapsed_h" "$expected_h" "$BLUE" "$BOLD" "$subtitle" "$RESET" >&2 + else + printf '\r\033[K%s==>%s %s\n %s %s%3d%%%s (%s / ~%s)\033[1A' \ + "$BLUE" "$RESET" "$label" "$bar" "$YELLOW" "$pct" "$RESET" "$elapsed_h" "$expected_h" >&2 + fi + else + # No baseline yet — spinner mode + local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' + local frame="${spin:RUN_QUIET_I%10:1}" + if [[ -n "$subtitle" ]]; then + printf '\r\033[K%s %s==>%s %s %s(%s)%s ↳ %s' \ + "$frame" "$BLUE" "$RESET" "$label" "$YELLOW" "$elapsed_h" "$RESET" "$subtitle" >&2 + else + printf '\r\033[K%s %s==>%s %s %s(%s)%s' \ + "$frame" "$BLUE" "$RESET" "$label" "$YELLOW" "$elapsed_h" "$RESET" >&2 + fi + fi +} + +format_duration() { + local s="$1" + if (( s < 60 )); then + printf '%ds' "$s" + else + printf '%dm%02ds' $((s / 60)) $((s % 60)) + fi +} + # run_quiet "Label" -# Runs cmd silently with a spinner + elapsed time. On error dumps last 40 log -# lines and exits. With --verbose / non-TTY: streams full output normally. +# Runs cmd silently with a brew-style progress bar (time-based, learns durations +# across runs). On error dumps last 40 log lines and exits. With --verbose / non-TTY: +# streams full output normally. run_quiet() { local label="$1"; shift local logfile="$1"; shift @@ -109,40 +176,44 @@ run_quiet() { return ${PIPESTATUS[0]} fi local start=$SECONDS - local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' - local i=0 pid elapsed frame subtitle + local expected pid elapsed subtitle + expected=$(runtime_lookup "$label" || echo 0) + expected=${expected:-0} + RUN_QUIET_I=0 ( "$@" >"$logfile" 2>&1 ) & pid=$! + # If we have a baseline, render 2-line bar (label + bar); else 1-line spinner. + if (( expected > 0 )); then + printf '\n\033[1A' >&2 # Reserve second line, then move up + fi while kill -0 "$pid" 2>/dev/null; do elapsed=$((SECONDS - start)) - frame="${spin:i%10:1}" - i=$((i + 1)) - # Pull latest meaningful build action from log (last 20 lines, filtered) + RUN_QUIET_I=$((RUN_QUIET_I + 1)) subtitle="" if [[ -f "$logfile" ]]; then subtitle=$(tail -20 "$logfile" 2>/dev/null \ | grep -aE '^(Compiling|CompileSwift|CompileC|Linking|Ld|Touch|CodeSign|ProcessProductPackaging|ExtractAppIntentsMetadata|Validate|Archive|GenerateAssetSymbols|CopySwiftLibs|PhaseScriptExecution|> Task|BUILD|\[CP|\[Pods)' \ | tail -1 \ | sed -E 's|.*/||; s|\(.*||' \ - | cut -c1-60) - fi - if [[ -n "$subtitle" ]]; then - printf '\r\033[K%s %s==>%s %s %s(%ds)%s ↳ %s' \ - "$frame" "$BLUE" "$RESET" "$label" "$YELLOW" "$elapsed" "$RESET" "$subtitle" >&2 - else - printf '\r\033[K%s %s==>%s %s %s(%ds)%s' \ - "$frame" "$BLUE" "$RESET" "$label" "$YELLOW" "$elapsed" "$RESET" >&2 + | cut -c1-50) fi + render_progress "$elapsed" "$expected" "$label" "$subtitle" sleep 0.2 done wait "$pid" local rc=$? elapsed=$((SECONDS - start)) - printf '\r\033[K' >&2 # Clear spinner line - if [[ $rc -eq 0 ]]; then - ok "$label ${YELLOW}(${elapsed}s)${RESET}" + # Clear both lines if we used 2-line mode, else 1 line + if (( expected > 0 )); then + printf '\r\033[K\n\033[K\033[1A' >&2 else - error "$label fehlgeschlagen nach ${elapsed}s (exit $rc)" + printf '\r\033[K' >&2 + fi + if [[ $rc -eq 0 ]]; then + ok "$label ${YELLOW}($(format_duration "$elapsed"))${RESET}" + runtime_save "$label" "$elapsed" + else + error "$label fehlgeschlagen nach $(format_duration "$elapsed") (exit $rc)" echo "" >&2 echo "${BOLD}── Letzte Log-Zeilen (${logfile}) ──${RESET}" >&2 tail -40 "$logfile" >&2