use crate::cli::args::{GlobalFlags, StatusArgs};
use anyhow::Result;
use grex_core::sync::{self, SyncOptions, SyncReport};
use std::collections::BTreeMap;
use tokio_util::sync::CancellationToken;
pub fn run(args: StatusArgs, global: &GlobalFlags, cancel: &CancellationToken) -> Result<()> {
let Some(pack_root) = super::resolve_pack_root_or_cwd(args.pack_root.as_deref()) else {
emit_error(
global.json,
"usage",
"`<pack_root>` required (directory with `.grex/pack.yaml`)",
);
std::process::exit(2);
};
let opts = SyncOptions::new().with_dry_run(true).with_validate(true);
match sync::run(&pack_root, &opts, cancel) {
Ok(report) => {
render(&report, global.json);
if report.halted.is_some() {
std::process::exit(2);
}
Ok(())
}
Err(err) => {
let outcome = super::sync::classify_sync_err(err, global.json, "status");
match outcome {
super::sync::RunOutcome::Validation => std::process::exit(1),
super::sync::RunOutcome::Tree | super::sync::RunOutcome::UsageError => {
std::process::exit(2)
}
super::sync::RunOutcome::Exec => std::process::exit(2),
super::sync::RunOutcome::Ok => Ok(()),
}
}
}
}
fn render(report: &SyncReport, json: bool) {
let mut per_pack: BTreeMap<String, usize> = BTreeMap::new();
for s in &report.steps {
*per_pack.entry(s.pack.clone()).or_insert(0) += 1;
}
if json {
let packs: Vec<serde_json::Value> = per_pack
.iter()
.map(|(pack, &count)| {
let state = if count == 0 { "clean" } else { "would_update" };
serde_json::json!({
"path": pack,
"state": state,
"drift_count": count,
})
})
.collect();
let clean = per_pack.values().all(|&n| n == 0);
let doc = serde_json::json!({
"verb": "status",
"clean": clean,
"packs": packs,
});
println!("{}", serde_json::to_string(&doc).unwrap_or_default());
} else if per_pack.is_empty() {
println!("clean");
} else {
for (pack, count) in &per_pack {
if *count == 0 {
println!("clean {pack}");
} else {
println!("would-update {count:>3} {pack}");
}
}
}
}
fn emit_error(json: bool, kind: &str, msg: &str) {
if json {
let doc = serde_json::json!({
"verb": "status",
"error": { "kind": kind, "message": msg },
});
println!("{}", serde_json::to_string(&doc).unwrap_or_default());
} else {
eprintln!("grex status: {msg}");
}
}