report: add BuildView/Prompter ports and drive pkh build through them

Core flows no longer reach into the terminal UI: build_source_package
takes a BuildSourceOptions struct (source tree, domain options, view,
prompter) and reports phases, messages and outcomes through the
environment-agnostic ports in the new report module. The classifiers
move from ui/logfmt to the core logfmt module, DebUi becomes a
BuildView adapter, the re-vendor retry asks the prompter instead of
checking for a TTY, and artifact/success printing moves to the CLI.

Headless consumers pass report::Quiet; an embedding (e.g. a builder
server forwarding events to a web frontend) implements BuildView and
maps the plain-data events onto its own wire format.
This commit is contained in:
2026-09-18 20:02:56 +02:00
parent a7d2cfdc6e
commit 27b1083b15
11 changed files with 335 additions and 179 deletions
+37 -20
View File
@@ -490,13 +490,12 @@ fn main() {
.copied()
.unwrap_or(false);
// Live build view: disabled by --verbose or when stdout is not a
// terminal (DebUi handles the non-TTY case itself)
let ui = if verbose {
None
} else {
Some(std::sync::Arc::new(pkh::ui::deb::DebUi::new(&multi)))
};
// Live build view, unless --verbose (DebUi additionally disables
// itself when stdout is not a terminal)
let quiet = pkh::report::Quiet;
let live = pkh::ui::deb::DebUi::new(&multi);
let view: &dyn pkh::report::BuildView = if verbose { &quiet } else { &live };
let prompter = pkh::ui::prompt::TerminalPrompter;
let orig_source = match sub_matches.get_one::<String>("orig").map(String::as_str) {
Some("always") => pkh::build::OrigSourceMode::Always,
@@ -504,23 +503,41 @@ fn main() {
_ => pkh::build::OrigSourceMode::Auto,
};
if let Err(e) = pkh::build::build_source_package(
Some(&cwd),
pkh::build::SourceBuildOptions {
match pkh::build::build_source_package(pkh::build::BuildSourceOptions {
source: Some(cwd),
options: pkh::build::SourceBuildOptions {
orig_source,
..Default::default()
},
ui,
) {
error!("{}", e);
// Unmet build dependencies/conflicts exit with status 3,
// like dpkg-buildpackage does.
if e.downcast_ref::<pkh::debian::deps::UnmetBuildDependencies>()
.is_some()
{
std::process::exit(3);
view,
prompter: &prompter,
}) {
Ok(output) => {
// The live view lists the artifacts itself when it
// renders; otherwise (verbose mode or non-TTY stdout)
// print them as plain lines.
if !view.is_enabled() {
for artifact in output.artifacts() {
println!(" {}", pkh::ui::display_path(&artifact));
}
}
if output.signed {
info!("Package built and signed successfully!");
} else {
info!("Package built successfully (unsigned).");
}
}
Err(e) => {
error!("{}", e);
// Unmet build dependencies/conflicts exit with status 3,
// like dpkg-buildpackage does.
if e.downcast_ref::<pkh::debian::deps::UnmetBuildDependencies>()
.is_some()
{
std::process::exit(3);
}
std::process::exit(1);
}
std::process::exit(1);
}
}
Some(("put", sub_matches)) => {