feat(build): live-stream Linux build output; ns7zip via in-guest clone
- SshTransport.run_streaming: incremental channel recv, forwards stdout/stderr live (no more one-block-at-end). _linux_build uses it with PYTHONUNBUFFERED so the guest python flushes promptly. - _tail_lines split out for failure messages (no double print). - Windows live streaming deferred (TODO 8.2) — pypsrp execute_ps returns only at completion. - build-ns7zip.yml: use-git-clone:'true' (in-guest), repo-url -> https://gitea.emulab.it/... (guest-reachable; host SSH alias was host-only). Requires GiteaPAT in the LocalSystem keyring or a public nsis-plugin-ns7zip. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -112,6 +112,11 @@ def _report_build_output(stdout: str, stderr: str) -> str:
|
||||
sys.stderr.write(stderr if stderr.endswith("\n") else stderr + "\n")
|
||||
sys.stderr.flush()
|
||||
click.echo("[build run] ----- end build output -----")
|
||||
return _tail_lines(stdout, stderr)
|
||||
|
||||
|
||||
def _tail_lines(stdout: str, stderr: str) -> str:
|
||||
"""Last few output lines for a failure message (no printing)."""
|
||||
combined = (stderr or "").strip() or (stdout or "").strip()
|
||||
lines = combined.splitlines()
|
||||
return " | ".join(lines[-5:]) if lines else "(no build output)"
|
||||
@@ -189,13 +194,20 @@ def _linux_build(
|
||||
f"export {k}={_sh_quote(v)}; " for k, v in extra_env.items()
|
||||
)
|
||||
cmd = build_command or "make"
|
||||
full_cmd = f"{env_prefix}cd {_sh_quote(workdir)} && {cmd}"
|
||||
# PYTHONUNBUFFERED so the guest python flushes promptly and the
|
||||
# streamed output is timely rather than emitted in one block.
|
||||
full_cmd = (
|
||||
f"{env_prefix}export PYTHONUNBUFFERED=1; "
|
||||
f"cd {_sh_quote(workdir)} && {cmd}"
|
||||
)
|
||||
click.echo(f"[build run] running build (env vars redacted): cd {workdir} && {cmd}")
|
||||
result = t.run(full_cmd, check=False)
|
||||
tail = _report_build_output(result.stdout, result.stderr)
|
||||
click.echo("[build run] ----- build output (live) -----")
|
||||
result = t.run_streaming(full_cmd, check=False)
|
||||
click.echo("[build run] ----- end build output -----")
|
||||
if result.returncode != 0:
|
||||
raise click.ClickException(
|
||||
f"build command failed (exit {result.returncode}): {tail}"
|
||||
"build command failed "
|
||||
f"(exit {result.returncode}): {_tail_lines(result.stdout, result.stderr)}"
|
||||
)
|
||||
|
||||
if skip_artifact:
|
||||
|
||||
Reference in New Issue
Block a user