memstead_cli/commands/
reload.rs1use clap::Parser;
11
12use crate::CliError;
13use crate::output::{print_json, print_markdown};
14use crate::setup::CliContext;
15
16#[derive(Parser, Debug)]
17pub struct Args {
18 #[arg(long)]
25 pub mem: Option<String>,
26
27 #[arg(long, conflicts_with = "mem")]
37 pub full: bool,
38}
39
40pub fn run(ctx: &CliContext, args: Args) -> anyhow::Result<()> {
41 let mut engine = ctx.cli_engine()?.into_base();
42 let refresh = args.full.then(|| engine.full_refresh());
43 let reports = match args.mem.as_deref() {
44 Some(name) => engine
45 .reload_one_mem_report(name)
46 .map(|r| vec![r])
47 .map_err(CliError::from_engine_op)?,
48 None => engine
49 .reload_each_writable_mem_reports()
50 .map_err(CliError::from_engine_op)?,
51 };
52
53 if ctx.json {
54 let mut payload = serde_json::json!({ "reports": reports });
55 if let Some(refresh) = &refresh {
56 payload["refresh"] = serde_json::to_value(refresh).unwrap_or(serde_json::Value::Null);
57 }
58 print_json(&payload)?;
59 } else {
60 let mut lines = vec![
61 format!("# Reloaded {} mem(s)", reports.len()),
62 String::new(),
63 ];
64 for r in &reports {
65 lines.push(format!(
66 "- `{}` — {} entities, head {} → {}{}",
67 r.mem,
68 r.entities_loaded,
69 short_sha(&r.head_before),
70 short_sha(&r.head_after),
71 if r.changed_entity_ids.is_empty() {
72 String::new()
73 } else {
74 format!(" ({} changed)", r.changed_entity_ids.len())
75 },
76 ));
77 }
78 if let Some(refresh) = &refresh {
79 lines.push(String::new());
80 lines.push(format!("## Full refresh ({} ms)", refresh.elapsed_ms));
81 lines.push(format!(
82 "- schemas added: {}",
83 render_list(&refresh.schemas_added)
84 ));
85 lines.push(format!(
86 "- schema removals skipped: {}",
87 render_list(&refresh.schema_removals_skipped)
88 ));
89 lines.push(format!(
90 "- mems mounted: {}",
91 render_list(&refresh.mems_mounted)
92 ));
93 lines.push(format!(
94 "- mem removals skipped: {}",
95 render_list(&refresh.mem_removals_skipped)
96 ));
97 for f in &refresh.failures {
98 lines.push(format!("- ✗ {} — {}", f.item, f.error));
99 }
100 }
101 print_markdown(&lines.join("\n"));
102 }
103 Ok(())
104}
105
106fn render_list(items: &[String]) -> String {
107 if items.is_empty() {
108 "(none)".to_string()
109 } else {
110 items.join(", ")
111 }
112}
113
114fn short_sha(sha: &str) -> &str {
115 let n = sha.len().min(8);
116 &sha[..n]
117}