use smix_capsule::runner_view::{self, Seen};
use smix_lease::store::{self, CheckoutLedgers, LeaseDir};
pub fn run(leases: &LeaseDir) -> Result<u8, crate::CliError> {
let machine = ledgers_in(leases);
let checkout_dir = std::env::current_dir()
.ok()
.and_then(|cwd| CheckoutLedgers::discover(&cwd));
let checkout: Vec<(String, smix_lease::Lease)> = match &checkout_dir {
Some(c) => c
.device_ids()
.into_iter()
.filter_map(|id| c.read(&id).ok().flatten().map(|l| (id, l)))
.collect(),
None => Vec::new(),
};
let listeners = runner_view::listeners();
let rows = runner_view::attribute(&machine, &listeners, &checkout);
if rows.is_empty() {
println!(
"no runner ledgers under {leases}, and nothing on this machine is \
listening as a smix runner"
);
return Ok(0);
}
for row in &rows {
match &row.seen {
Seen::Both {
app_pid,
ledger_session_pid,
live_session_pid,
} => {
println!(
":{:<6} {:<40} both app pid {app_pid}, ledger session pid \
{ledger_session_pid}",
row.port, row.device_id
);
match live_session_pid {
Some(live) if live != ledger_session_pid => println!(
"{:>8} the session driving it now is pid {live}, not the one \
recorded",
""
),
None => println!(
"{:>8} no xcodebuild session here answers for it — it keeps \
serving after the session that started it exits",
""
),
_ => {}
}
}
Seen::LedgerOnly { ledger_pid } => {
println!(
":{:<6} {:<40} ledger-only recorded at pid {ledger_pid}; nothing is \
listening there",
row.port, row.device_id
);
}
Seen::ProcessOnly {
app_pid,
session_pid,
named_by,
} => {
println!(
":{:<6} {:<40} process-only app pid {app_pid}{}",
row.port,
row.device_id,
match session_pid {
Some(p) => format!(", session pid {p}"),
None => String::new(),
}
);
println!("{:>8} this machine's ledgers have no record of it.", "");
if let (Some(c), Some(_)) = (&checkout_dir, named_by) {
println!(
"{:>8} {c} names this device — that book is evidence about \
where to look, not authority.",
""
);
}
}
Seen::NotProbed { ledger_pid, why } => {
println!(
":{:<6} {:<40} not-probed recorded at pid {ledger_pid} — {why}",
row.port, row.device_id
);
}
}
}
Ok(0)
}
fn ledgers_in(leases: &LeaseDir) -> Vec<(String, smix_lease::Lease)> {
let Ok(entries) = std::fs::read_dir(leases.path()) else {
return Vec::new();
};
let mut ids: Vec<String> = entries
.flatten()
.filter_map(|e| {
e.file_name()
.to_string_lossy()
.strip_suffix(".json")
.map(str::to_string)
})
.collect();
ids.sort();
ids.into_iter()
.filter_map(|id| store::read(leases, &id).ok().flatten().map(|l| (id, l)))
.collect()
}