use std::io::Write as _;
use owo_colors::OwoColorize;
use crate::build_log::{BuildLog, DisplayEvent};
use crate::cargo::CargoExecution;
use crate::explain;
pub fn print_stream_event(event: &DisplayEvent, show_fresh: bool) {
let mut out = std::io::stdout().lock();
match event {
DisplayEvent::Fresh { id } => {
if show_fresh {
let _ = writeln!(out, "{} {}", "Fresh".dimmed(), id.dimmed());
}
}
DisplayEvent::WorkStarted { kind, id, reason } => {
let _ = writeln!(out, "{} {}", kind.verb().green().bold(), id.bold());
if let Some(reason) = reason {
let _ = writeln!(out, " {} {}", "reason:".dimmed(), reason.dimmed());
}
}
DisplayEvent::LateReason { id, reason } => {
let label = format!("reason({id}):");
let _ = writeln!(out, " {} {}", label.dimmed(), reason.dimmed());
}
}
}
pub fn print_summary(exec: &CargoExecution) {
let counts = exec.log.counts();
let secs = exec.duration.as_secs_f64();
let details = format!(
"in {:.2}s (fresh {}, dirty {}, work {})",
secs, counts.fresh, counts.dirty, counts.work
);
let mut out = std::io::stdout().lock();
if exec.status.success() {
let _ = writeln!(out, "{} {}", "ok".green(), details.dimmed());
} else {
let _ = writeln!(out, "{} {}", "failed".red(), details.dimmed());
}
}
pub fn print_errors(messages: &[cargo_metadata::Message]) -> usize {
let mut err = std::io::stderr().lock();
let mut printed = 0;
for msg in messages {
if let cargo_metadata::Message::CompilerMessage(cm) = msg
&& matches!(
cm.message.level,
cargo_metadata::diagnostic::DiagnosticLevel::Error
)
&& let Some(rendered) = cm.message.rendered.as_deref()
{
let _ = writeln!(err, "{rendered}");
printed += 1;
}
}
printed
}
const RAW_STDERR_TAIL_LINES: usize = 20;
pub fn print_raw_stderr_tail(log: &BuildLog) {
let other_stderr = log.other_stderr();
let start = other_stderr
.iter()
.position(|line| line.trim_start().starts_with("error"))
.unwrap_or_else(|| other_stderr.len().saturating_sub(RAW_STDERR_TAIL_LINES));
let mut err = std::io::stderr().lock();
for line in other_stderr.get(start..).unwrap_or_default() {
let _ = writeln!(err, "{line}");
}
}
pub fn print_explain(log: &BuildLog) {
let Some(analysis) = explain::analyze(log) else {
return;
};
let mut out = std::io::stdout().lock();
let _ = writeln!(
out,
"{} {}",
"culprit".green().bold(),
analysis.culprit.bold()
);
for (idx, entry) in analysis.cascade.iter().enumerate() {
let idx_raw = format!("{:>3}", idx + 1);
let idx_s = idx_raw.dimmed();
let _ = writeln!(
out,
"{idx_s} {} {}",
entry.kind.verb().green().bold(),
entry.crate_id.bold()
);
if let Some(caused_by) = &entry.caused_by {
let _ = writeln!(out, " {} {}", "caused by:".dimmed(), caused_by.dimmed());
}
if let Some(reason) = &entry.reason {
let _ = writeln!(out, " {} {}", "reason:".dimmed(), reason.dimmed());
}
for detail in &entry.details {
let _ = writeln!(out, " {} {}", "detail:".dimmed(), detail.dimmed());
}
}
}