use anstyle::AnsiColor;
use anstyle::Effects;
use anstyle::Reset;
use std::cmp::max;
use std::io::Write;
use thiserror::Error;
pub mod checks;
#[cfg(test)]
mod tests;
mod types;
pub use types::Check;
pub use types::CheckFn;
pub use types::CheckResult;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum MedicError {
#[error("IO error")]
IoError(#[from] std::io::Error),
#[error("Error from check")]
CheckError(#[from] Box<dyn std::error::Error + Send + Sync>),
}
pub fn medic<'iter>(
output: &mut impl Write,
checks: impl Iterator<Item = &'iter Check>,
) -> Result<CheckResult, MedicError> {
let mut worst_issues_found = CheckResult::Ok;
let mut results = vec![];
for Check { name, func } in checks {
match func() {
Ok((result, text)) => {
results.push((result, *name, text));
if result >= worst_issues_found {
worst_issues_found = result;
}
}
Err(err) => {
results.push((CheckResult::Fatal, *name, format!("{err}")));
worst_issues_found = CheckResult::Fatal;
}
}
}
let mut status_width = "RESULT".len();
let mut name_width = "CHECK".len();
for (status, name, _) in &results {
status_width = max(
status_width,
<&CheckResult as Into<&str>>::into(status).len(),
);
name_width = max(name_width, name.len());
}
let text_alignment = status_width + name_width + 4;
writeln!(
output,
"{}{: <status_width$} {: <name_width$} MESSAGE{}",
Effects::BOLD.render(),
"RESULT",
"CHECK",
Reset.render()
)?;
for (status, name, text) in results {
let text = text.replace(
'\n',
&("\n".to_owned() + " ".repeat(text_alignment).as_str()),
);
writeln!(
output,
"{status: <status_width$} {name: <name_width$} {text}"
)?;
}
Ok(worst_issues_found)
}
pub fn summary(output: &mut impl Write, worst_issues_found: CheckResult) -> Result<(), MedicError> {
if worst_issues_found >= CheckResult::Error {
writeln!(
output,
"\n{}Error{}: Error(s) found, you should rectify these for proper operation",
AnsiColor::Red.render_fg(),
Reset.render()
)?;
} else if worst_issues_found >= CheckResult::Warning {
writeln!(
output,
"\n{}Warning{}: Warning(s) found, consider investigating (especially if you have \
issues)",
AnsiColor::Yellow.render_fg(),
Reset.render()
)?;
}
Ok(())
}