Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Run it inside a Cargo project (or anywhere, for the global suggestions):
```sh
frd # report, then the interactive wizard
frd report # print the system and project report, then exit
frd doctor # audit which optimizations are applied; exit non-zero if any are pending
frd --dry-run # show every change as a diff, write and run nothing
frd --yes # accept every applicable suggestion without prompting
frd --root DIR # operate on DIR instead of the current directory
Expand Down
3 changes: 3 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ pub struct Cli {
pub enum Commands {
/// Print the system and project report, then exit.
Report,

/// Audit which optimizations are applied, change nothing, and exit non-zero if any are pending.
Doctor,
}
76 changes: 76 additions & 0 deletions src/doctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//! The `doctor` command: a read-only audit of which catalog optimizations are already
//! applied on this machine and project. Writes and runs nothing, and returns false when
//! any state-based optimization is still pending so the caller can exit non-zero, which
//! makes it usable as a CI or pre-commit check.

use crate::catalog;
use crate::status_of;
use crate::suggestion::{Action, Status, Suggestion};
use crate::system::SystemReport;
use console::{StyledObject, style};

/// Print the checkup. Returns true when every state-based optimization is applied.
pub fn run(report: &SystemReport) -> bool {
// Run actions (e.g. sweeping stale artifacts) are recurring maintenance, not a state we
// can detect as "done", so they never count toward the verdict. Check only the config-
// and tool-based items, which status_of can classify as applied or pending.
let (maintenance, checkable): (Vec<Suggestion>, Vec<Suggestion>) = catalog::build(report)
.into_iter()
.partition(|s| matches!(s.action, Action::Run(_)));

println!("{}", style("Doctor: optimization checkup").bold().cyan());
let mut pending = 0usize;
for s in &checkable {
let applied = status_of(report, s) == Status::AlreadyApplied;
if !applied {
pending += 1;
}
println!(" {} {} {}", mark(applied), tag(s), s.title);
}

if !maintenance.is_empty() {
println!();
println!("{}", style("Maintenance (re-run anytime):").dim());
for s in &maintenance {
if let Action::Run(spec) = &s.action {
println!(
" {} {}",
style(format!("{}:", s.title)).dim(),
style(spec.display()).dim()
);
}
}
}

println!();
let total = checkable.len();
if pending == 0 {
println!(
"{}",
style(format!("All {total} optimizations applied; nothing to do.")).green()
);
true
} else {
println!(
"{}",
style(format!(
"{}/{total} applied, {pending} pending. Run `frd` to apply them.",
total - pending
))
.yellow()
);
false
}
}

fn mark(applied: bool) -> StyledObject<&'static str> {
if applied {
style("[ok]").green().bold()
} else {
style("[--]").red().bold()
}
}

fn tag(s: &Suggestion) -> StyledObject<String> {
style(format!("{:<5}", s.tag.label())).dim()
}
10 changes: 9 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod catalog;
mod cli;
mod doctor;
mod runner;
mod suggestion;
mod system;
Expand All @@ -25,6 +26,13 @@ fn main() -> Result<()> {
return Ok(());
}

if matches!(args.command, Some(cli::Commands::Doctor)) {
if !doctor::run(&report) {
std::process::exit(1);
}
return Ok(());
}

if !report.project.has_cargo_toml {
println!(
"{}",
Expand Down Expand Up @@ -96,7 +104,7 @@ fn main() -> Result<()> {
Ok(())
}

fn status_of(r: &SystemReport, s: &Suggestion) -> Status {
pub(crate) fn status_of(r: &SystemReport, s: &Suggestion) -> Status {
match &s.action {
Action::Toml(c) => {
if toml_ops::is_applied(r, c) {
Expand Down
Loading