Feat: build script UI/UX

This commit is contained in:
2026-03-17 12:49:01 +01:00
parent 3d9d2ad759
commit d72b36b8f1

View File

@@ -22,8 +22,7 @@ from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from rich.console import Console from rich.console import Console, Group
from rich.layout import Layout
from rich.live import Live from rich.live import Live
from rich.panel import Panel from rich.panel import Panel
from rich.progress_bar import ProgressBar from rich.progress_bar import ProgressBar
@@ -606,19 +605,12 @@ def _build_display(
completed: dict[str, PlatformResult], completed: dict[str, PlatformResult],
start_times: dict[str, float], start_times: dict[str, float],
log_max_lines: int, log_max_lines: int,
) -> Layout: ) -> Group:
layout = Layout() table = Table(padding=(0, 1), expand=True, show_edge=False)
status_height = len(platforms) + 4 table.add_column("Platform", style="cyan", no_wrap=True)
layout.split_column( table.add_column("Phase", no_wrap=True)
Layout(name="status", size=status_height), table.add_column("Progress", no_wrap=True)
Layout(name="logs"), table.add_column("Time", justify="right", no_wrap=True)
)
table = Table(padding=(0, 1), expand=True)
table.add_column("Platform", style="cyan", min_width=28, no_wrap=True)
table.add_column("Phase", min_width=20, no_wrap=True)
table.add_column("Progress", min_width=22, no_wrap=True)
table.add_column("Time", justify="right", min_width=6, no_wrap=True)
with _progress_lock: with _progress_lock:
progress_snapshot = dict(_build_progress) progress_snapshot = dict(_build_progress)
@@ -634,7 +626,7 @@ def _build_display(
phase = Text(f"OK ({n} artifacts)", style="green") phase = Text(f"OK ({n} artifacts)", style="green")
bar = ProgressBar(total=total, completed=total, width=20, complete_style="green") bar = ProgressBar(total=total, completed=total, width=20, complete_style="green")
else: else:
phase = Text(f"FAIL", style="red") phase = Text("FAIL", style="red")
bar = ProgressBar(total=total, completed=total, width=20, complete_style="red") bar = ProgressBar(total=total, completed=total, width=20, complete_style="red")
elapsed = f"{r.elapsed:.0f}s" elapsed = f"{r.elapsed:.0f}s"
elif alias in progress_snapshot: elif alias in progress_snapshot:
@@ -649,23 +641,18 @@ def _build_display(
table.add_row(p.label, phase, bar, elapsed) table.add_row(p.label, phase, bar, elapsed)
layout["status"].update(Panel(table, title="[bold blue]Build Progress[/]", border_style="blue"))
with _progress_lock: with _progress_lock:
recent = _build_logs[-log_max_lines:] recent = _build_logs[-log_max_lines:]
if recent: if recent:
lines: list[str] = [] lines: list[str] = []
for alias, line in recent: for alias, line in recent:
short = alias.split("-")[0][:3] lines.append(f"[dim]{alias}[/] {line.rstrip()}")
lines.append(f"[dim]{short}[/] {line.rstrip()}") log_text = Text("\n") + Text.from_markup("\n".join(lines))
log_text = "\n".join(lines)
else: else:
log_text = "[dim]waiting for output...[/]" log_text = Text("\nwaiting for output...", style="dim")
layout["logs"].update(Panel(log_text, title="[bold]Build Output[/]", border_style="dim")) return Group(table, log_text)
return layout
def run_builds( def run_builds(
@@ -685,17 +672,10 @@ def run_builds(
term_height = console.size.height term_height = console.size.height
log_max_lines = max(term_height - len(platforms) - 10, 5) log_max_lines = max(term_height - len(platforms) - 10, 5)
def make_display() -> Layout: def make_display() -> Group:
return _build_display(platforms, config, completed, start_times, log_max_lines) return _build_display(platforms, config, completed, start_times, log_max_lines)
with Live(make_display(), console=console, refresh_per_second=4) as live: with Live(make_display(), console=console, refresh_per_second=4) as live:
if len(platforms) == 1:
p = platforms[0]
r = build_platform(root, p, config)
completed[p.alias] = r
results.append(r)
live.update(make_display())
else:
with ThreadPoolExecutor(max_workers=len(platforms)) as pool: with ThreadPoolExecutor(max_workers=len(platforms)) as pool:
futures = {pool.submit(build_platform, root, p, config): p for p in platforms} futures = {pool.submit(build_platform, root, p, config): p for p in platforms}
pending = set(futures.keys()) pending = set(futures.keys())
@@ -716,13 +696,21 @@ def run_builds(
return results return results
_FAILURE_LOG_TAIL = 50
def _print_platform_log(r: PlatformResult, verbose: bool = False) -> None: def _print_platform_log(r: PlatformResult, verbose: bool = False) -> None:
if r.success and not verbose: if r.success and not verbose:
return return
style = "green" if r.success else "red" style = "green" if r.success else "red"
status = "OK" if r.success else "FAIL" status = "OK" if r.success else "FAIL"
lines = r.log_lines or []
if not r.success and not verbose and len(lines) > _FAILURE_LOG_TAIL:
lines = [f" ... ({len(r.log_lines) - _FAILURE_LOG_TAIL} lines omitted, use --verbose for full output)"] + lines[-_FAILURE_LOG_TAIL:]
console.print(Panel( console.print(Panel(
"\n".join(r.log_lines) if r.log_lines else "[dim]no output[/]", "\n".join(lines) if lines else "[dim]no output[/]",
title=f"{r.platform.label} [{status}] {r.elapsed:.1f}s", title=f"{r.platform.label} [{status}] {r.elapsed:.1f}s",
border_style=style, border_style=style,
)) ))