Feat: build script UI/UX
This commit is contained in:
@@ -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,
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user