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 pathlib import Path
|
||||
|
||||
from rich.console import Console
|
||||
from rich.layout import Layout
|
||||
from rich.console import Console, Group
|
||||
from rich.live import Live
|
||||
from rich.panel import Panel
|
||||
from rich.progress_bar import ProgressBar
|
||||
@@ -606,19 +605,12 @@ def _build_display(
|
||||
completed: dict[str, PlatformResult],
|
||||
start_times: dict[str, float],
|
||||
log_max_lines: int,
|
||||
) -> Layout:
|
||||
layout = Layout()
|
||||
status_height = len(platforms) + 4
|
||||
layout.split_column(
|
||||
Layout(name="status", size=status_height),
|
||||
Layout(name="logs"),
|
||||
)
|
||||
|
||||
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)
|
||||
) -> Group:
|
||||
table = Table(padding=(0, 1), expand=True, show_edge=False)
|
||||
table.add_column("Platform", style="cyan", no_wrap=True)
|
||||
table.add_column("Phase", no_wrap=True)
|
||||
table.add_column("Progress", no_wrap=True)
|
||||
table.add_column("Time", justify="right", no_wrap=True)
|
||||
|
||||
with _progress_lock:
|
||||
progress_snapshot = dict(_build_progress)
|
||||
@@ -634,7 +626,7 @@ def _build_display(
|
||||
phase = Text(f"OK ({n} artifacts)", style="green")
|
||||
bar = ProgressBar(total=total, completed=total, width=20, complete_style="green")
|
||||
else:
|
||||
phase = Text(f"FAIL", style="red")
|
||||
phase = Text("FAIL", style="red")
|
||||
bar = ProgressBar(total=total, completed=total, width=20, complete_style="red")
|
||||
elapsed = f"{r.elapsed:.0f}s"
|
||||
elif alias in progress_snapshot:
|
||||
@@ -649,23 +641,18 @@ def _build_display(
|
||||
|
||||
table.add_row(p.label, phase, bar, elapsed)
|
||||
|
||||
layout["status"].update(Panel(table, title="[bold blue]Build Progress[/]", border_style="blue"))
|
||||
|
||||
with _progress_lock:
|
||||
recent = _build_logs[-log_max_lines:]
|
||||
|
||||
if recent:
|
||||
lines: list[str] = []
|
||||
for alias, line in recent:
|
||||
short = alias.split("-")[0][:3]
|
||||
lines.append(f"[dim]{short}[/] {line.rstrip()}")
|
||||
log_text = "\n".join(lines)
|
||||
lines.append(f"[dim]{alias}[/] {line.rstrip()}")
|
||||
log_text = Text("\n") + Text.from_markup("\n".join(lines))
|
||||
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 layout
|
||||
return Group(table, log_text)
|
||||
|
||||
|
||||
def run_builds(
|
||||
@@ -685,30 +672,23 @@ def run_builds(
|
||||
term_height = console.size.height
|
||||
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)
|
||||
|
||||
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:
|
||||
futures = {pool.submit(build_platform, root, p, config): p for p in platforms}
|
||||
pending = set(futures.keys())
|
||||
while pending:
|
||||
done = {f for f in pending if f.done()}
|
||||
for f in done:
|
||||
r = f.result()
|
||||
completed[r.platform.alias] = r
|
||||
results.append(r)
|
||||
pending.discard(f)
|
||||
live.update(make_display())
|
||||
if pending:
|
||||
time.sleep(0.25)
|
||||
with ThreadPoolExecutor(max_workers=len(platforms)) as pool:
|
||||
futures = {pool.submit(build_platform, root, p, config): p for p in platforms}
|
||||
pending = set(futures.keys())
|
||||
while pending:
|
||||
done = {f for f in pending if f.done()}
|
||||
for f in done:
|
||||
r = f.result()
|
||||
completed[r.platform.alias] = r
|
||||
results.append(r)
|
||||
pending.discard(f)
|
||||
live.update(make_display())
|
||||
if pending:
|
||||
time.sleep(0.25)
|
||||
|
||||
for r in results:
|
||||
_print_platform_log(r, verbose)
|
||||
@@ -716,13 +696,21 @@ def run_builds(
|
||||
return results
|
||||
|
||||
|
||||
_FAILURE_LOG_TAIL = 50
|
||||
|
||||
|
||||
def _print_platform_log(r: PlatformResult, verbose: bool = False) -> None:
|
||||
if r.success and not verbose:
|
||||
return
|
||||
style = "green" if r.success else "red"
|
||||
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(
|
||||
"\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",
|
||||
border_style=style,
|
||||
))
|
||||
@@ -748,14 +736,14 @@ def _build_presets(platforms: list[Platform]) -> list[tuple[str, list[Platform],
|
||||
native = _native_platforms(platforms)
|
||||
if native:
|
||||
label = ", ".join(p.label for p in native)
|
||||
presets.append((f"This machine ({label})", native, BuildConfig()))
|
||||
presets.append((f"This machine ({label})", native, BuildConfig()))
|
||||
|
||||
macos = _platforms_by_os(platforms, "macos")
|
||||
if len(macos) > 1:
|
||||
presets.append(("macOS all (arm64 + x86_64)", macos, BuildConfig()))
|
||||
presets.append(("macOS all (arm64 + x86_64)", macos, BuildConfig()))
|
||||
|
||||
presets.append(("Full release (all platforms, all targets)", list(platforms), BuildConfig()))
|
||||
presets.append(("CLI only (all platforms, no desktop/plugins)", list(platforms), BuildConfig(desktop=False, plugins=False)))
|
||||
presets.append(("Full release (all platforms, all targets)", list(platforms), BuildConfig()))
|
||||
presets.append(("CLI only (all platforms, no desktop/plugins)", list(platforms), BuildConfig(desktop=False, plugins=False)))
|
||||
return presets
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user