use std::process::ExitCode;
use anyhow::Result;
use serde::Serialize;
use crate::output::CommandReport;
use crate::paths::state::default_ccd_root;
use crate::state::machine_registry;
use crate::state::machine_registry::MachineTrustClass;
#[derive(Serialize)]
pub struct MachineListEntry {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
pub trust_class: MachineTrustClass,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub profiles: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub capabilities: Vec<String>,
pub source: &'static str,
pub manifest_path: String,
}
#[derive(Serialize)]
pub struct MachineListReport {
command: &'static str,
ok: bool,
pub machines: Vec<MachineListEntry>,
}
impl CommandReport for MachineListReport {
fn exit_code(&self) -> ExitCode {
if self.ok {
ExitCode::SUCCESS
} else {
ExitCode::FAILURE
}
}
fn render_text(&self) {
if self.machines.is_empty() {
println!("No machines registered.");
return;
}
println!("{:<24} {:<10} {:<10}", "Machine ID", "Trust", "Source");
for entry in &self.machines {
let trust = match entry.trust_class {
MachineTrustClass::Owned => "owned",
MachineTrustClass::Limited => "limited",
MachineTrustClass::Observer => "observer",
};
println!("{:<24} {:<10} {:<10}", entry.id, trust, entry.source);
}
}
}
pub fn list() -> Result<MachineListReport> {
let ccd_root = default_ccd_root()?;
let records = machine_registry::load_all_machines(&ccd_root)?;
let machines: Vec<MachineListEntry> = records
.into_iter()
.map(|record| MachineListEntry {
id: record.id,
display_name: record.display_name,
trust_class: record.trust_class,
profiles: record.profiles,
capabilities: record.capabilities,
source: record.source.as_str(),
manifest_path: record.manifest_path,
})
.collect();
Ok(MachineListReport {
command: "machine-list",
ok: true,
machines,
})
}