Goal
248 println! / eprintln! calls in fbuild-cli are how CLI output reaches the user today. This is intentional but uncontrolled — there's no structured separation between progress, results, errors, and diagnostics. Replace with a curated fbuild_cli::output::* API backed by tracing so users (and CI consumers) can filter / format.
Sub-issue of #844.
Why it matters
- JSON / machine-readable output — currently impossible without a workspace-wide rewrite. Hard for CI to consume.
- Verbosity control —
--verbose / --quiet flags exist but are not consistently honored.
- Linker debug traces — 12+
println! calls in per-platform linkers (avr/, ch32v/, esp8266/, generic_arm/, nrf52/, renesas/, sam/, silabs/, teensy/) leak debug output to stdout in normal builds.
- Color discipline — currently every CLI subcommand handles ANSI separately. Centralized output makes
--color={auto,always,never} enforceable.
Bridge API
// crates/fbuild-cli/src/output.rs
pub fn progress(msg: impl Display); // tracing::info!
pub fn result(msg: impl Display); // stdout, always shown (the actual output)
pub fn warn(msg: impl Display); // tracing::warn!
pub fn error(msg: impl Display); // stderr + tracing::error!
pub fn debug(msg: impl Display); // tracing::debug!
For linker debug traces (separately in fbuild-build):
- Replace
println!("[linker] {}", ...) with tracing::debug!(target = "fbuild_build::linker", ...).
Migration phases
- Phase 1 — fbuild-cli output API (this sub-issue):
- Add
crates/fbuild-cli/src/output.rs with the curated API.
- Migrate all 248
println! / eprintln! calls.
- Add
ban_print_in_fbuild_cli lint scoped to crates/fbuild-cli/src/** excluding the bridge module.
- Phase 2 — linker debug traces (could be a separate follow-up):
- Replace 12+
println!/eprintln! calls in crates/fbuild-build/src/*/linker.rsand per-platform orchestrators withtracing::debug!`.
- Add
ban_print_in_fbuild_build lint (allowlist: none).
Lint
ban_print_in_production — file-path scoped to crates/fbuild-cli/src/** and crates/fbuild-build/src/**, excluding the bridge module in fbuild-cli.
Acceptance
References: #844.
Goal
248
println!/eprintln!calls infbuild-cliare how CLI output reaches the user today. This is intentional but uncontrolled — there's no structured separation between progress, results, errors, and diagnostics. Replace with a curatedfbuild_cli::output::*API backed bytracingso users (and CI consumers) can filter / format.Sub-issue of #844.
Why it matters
--verbose/--quietflags exist but are not consistently honored.println!calls in per-platform linkers (avr/,ch32v/,esp8266/,generic_arm/,nrf52/,renesas/,sam/,silabs/,teensy/) leak debug output to stdout in normal builds.--color={auto,always,never}enforceable.Bridge API
For linker debug traces (separately in fbuild-build):
println!("[linker] {}", ...)withtracing::debug!(target = "fbuild_build::linker", ...).Migration phases
crates/fbuild-cli/src/output.rswith the curated API.println!/eprintln!calls.ban_print_in_fbuild_clilint scoped tocrates/fbuild-cli/src/**excluding the bridge module.println!/eprintln!calls incrates/fbuild-build/src/*/linker.rsand per-platform orchestrators withtracing::debug!`.ban_print_in_fbuild_buildlint (allowlist: none).Lint
ban_print_in_production— file-path scoped tocrates/fbuild-cli/src/**andcrates/fbuild-build/src/**, excluding the bridge module in fbuild-cli.Acceptance
fbuild_cli::output::*API exists with teststracing::debug!ban_print_in_productionlint deployed with allowlist exactly =[crates/fbuild-cli/src/output.rs]--color={auto,always,never}flag works consistently across all subcommands--quietand--verboseflags consistently routed through tracing's level filterReferences: #844.