use std::io::Write;
pub fn enabled() -> bool {
crate::json_output::human_output_enabled()
}
pub fn info(msg: &str) {
if !enabled() {
return;
}
let mut out = std::io::stdout().lock();
let _ = writeln!(out, "{msg}");
}
pub fn detail(verbose: bool, msg: &str) {
if verbose {
info(msg);
}
}
pub fn warn(msg: &str) {
let mut err = std::io::stderr().lock();
let _ = writeln!(err, "{} {}", crate::color::yellow("Warning:"), msg);
}
pub fn error(msg: &str) {
let mut err = std::io::stderr().lock();
let _ = writeln!(err, "{} {}", crate::color::red("Error:"), msg);
}
pub fn diagnostic(msg: &str) {
if crate::runtime_flags::quiet_or_default() {
return;
}
let mut err = std::io::stderr().lock();
let _ = writeln!(err, "{msg}");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn enabled_tracks_the_json_output_predicate() {
assert_eq!(enabled(), crate::json_output::human_output_enabled());
}
#[test]
fn defaults_allow_human_output() {
assert!(enabled(), "uninitialized flags must not suppress output");
}
#[test]
fn build_path_has_no_bare_println() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
let build_path_modules = [
"executor/mod.rs",
"executor/execution.rs",
"executor/handlers.rs",
"executor/policy.rs",
"object_store/mod.rs",
"object_store/blobs.rs",
"object_store/descriptors.rs",
"object_store/restore.rs",
"object_store/operations.rs",
];
let mut offenders = Vec::new();
for rel in build_path_modules {
let path = root.join(rel);
let src = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("cannot read {}: {e}", path.display()));
for (i, line) in src.lines().enumerate() {
let trimmed = line.trim_start();
if trimmed.starts_with("//") {
continue;
}
if trimmed.contains("println!(") && !trimmed.contains("eprintln!(") {
offenders.push(format!("{rel}:{}: {}", i + 1, trimmed));
}
}
}
assert!(
offenders.is_empty(),
"bare println! on the build path corrupts --json stdout; \
use output::info/detail instead:\n{}",
offenders.join("\n"),
);
}
}