Skip to main content

embeddenator_cli/commands/
update.rs

1//! Update command implementations (add, remove, modify, compact)
2//!
3//! Incremental update operations for engram files.
4
5use anyhow::{Context, Result};
6use embeddenator_fs::EmbrFS;
7use embeddenator_io::{read_bincode_file, write_bincode_file};
8use embeddenator_vsa::ReversibleVSAConfig;
9use std::path::PathBuf;
10
11/// Load an existing EmbrFS from engram and manifest files
12fn load_embrfs(engram: &PathBuf, manifest: &PathBuf) -> Result<EmbrFS> {
13    let engram_data = read_bincode_file(engram)
14        .with_context(|| format!("Failed to read engram file: {}", engram.display()))?;
15    let manifest_data = read_bincode_file(manifest)
16        .with_context(|| format!("Failed to read manifest file: {}", manifest.display()))?;
17
18    Ok(EmbrFS {
19        engram: engram_data,
20        manifest: manifest_data,
21        resonator: None,
22    })
23}
24
25/// Save EmbrFS to engram and manifest files
26fn save_embrfs(fs: &EmbrFS, engram: &PathBuf, manifest: &PathBuf) -> Result<()> {
27    write_bincode_file(engram, &fs.engram)
28        .with_context(|| format!("Failed to write engram file: {}", engram.display()))?;
29    write_bincode_file(manifest, &fs.manifest)
30        .with_context(|| format!("Failed to write manifest file: {}", manifest.display()))?;
31    Ok(())
32}
33
34pub fn handle_update_add(
35    engram: PathBuf,
36    manifest: PathBuf,
37    file: PathBuf,
38    logical_path: Option<String>,
39    verbose: bool,
40) -> Result<()> {
41    if verbose {
42        println!(
43            "Embeddenator v{} - Incremental Add",
44            env!("CARGO_PKG_VERSION")
45        );
46        println!("===================================");
47    }
48
49    let mut fs = load_embrfs(&engram, &manifest)?;
50    let config = ReversibleVSAConfig::default();
51
52    let logical = logical_path.unwrap_or_else(|| {
53        file.file_name()
54            .map(|s| s.to_string_lossy().to_string())
55            .unwrap_or_else(|| "unnamed".to_string())
56    });
57
58    if verbose {
59        println!("Adding file: {} -> {}", file.display(), logical);
60    }
61
62    fs.add_file(&file, logical.clone(), verbose, &config)
63        .with_context(|| format!("Failed to add file: {}", file.display()))?;
64
65    save_embrfs(&fs, &engram, &manifest)?;
66
67    if verbose {
68        println!("File added successfully: {}", logical);
69    }
70
71    Ok(())
72}
73
74pub fn handle_update_remove(
75    engram: PathBuf,
76    manifest: PathBuf,
77    path: String,
78    verbose: bool,
79) -> Result<()> {
80    if verbose {
81        println!(
82            "Embeddenator v{} - Incremental Remove",
83            env!("CARGO_PKG_VERSION")
84        );
85        println!("======================================");
86    }
87
88    let mut fs = load_embrfs(&engram, &manifest)?;
89
90    if verbose {
91        println!("Removing file: {}", path);
92    }
93
94    fs.remove_file(&path, verbose)
95        .with_context(|| format!("Failed to remove file: {}", path))?;
96
97    save_embrfs(&fs, &engram, &manifest)?;
98
99    if verbose {
100        println!("File marked as deleted: {}", path);
101        println!("Run 'compact' to permanently remove and reclaim space.");
102    }
103
104    Ok(())
105}
106
107pub fn handle_update_modify(
108    engram: PathBuf,
109    manifest: PathBuf,
110    file: PathBuf,
111    logical_path: Option<String>,
112    verbose: bool,
113) -> Result<()> {
114    if verbose {
115        println!(
116            "Embeddenator v{} - Incremental Modify",
117            env!("CARGO_PKG_VERSION")
118        );
119        println!("======================================");
120    }
121
122    let mut fs = load_embrfs(&engram, &manifest)?;
123    let config = ReversibleVSAConfig::default();
124
125    let logical = logical_path.unwrap_or_else(|| {
126        file.file_name()
127            .map(|s| s.to_string_lossy().to_string())
128            .unwrap_or_else(|| "unnamed".to_string())
129    });
130
131    if verbose {
132        println!("Modifying file: {} -> {}", file.display(), logical);
133    }
134
135    fs.modify_file(&file, logical.clone(), verbose, &config)
136        .with_context(|| format!("Failed to modify file: {}", file.display()))?;
137
138    save_embrfs(&fs, &engram, &manifest)?;
139
140    if verbose {
141        println!("File modified successfully: {}", logical);
142    }
143
144    Ok(())
145}
146
147pub fn handle_update_compact(engram: PathBuf, manifest: PathBuf, verbose: bool) -> Result<()> {
148    if verbose {
149        println!(
150            "Embeddenator v{} - Compact Engram",
151            env!("CARGO_PKG_VERSION")
152        );
153        println!("===================================");
154    }
155
156    let mut fs = load_embrfs(&engram, &manifest)?;
157    let config = ReversibleVSAConfig::default();
158
159    let deleted_before = fs.manifest.files.iter().filter(|f| f.deleted).count();
160
161    if deleted_before == 0 {
162        if verbose {
163            println!("No deleted files to compact.");
164        }
165        return Ok(());
166    }
167
168    if verbose {
169        println!("Compacting {} deleted files...", deleted_before);
170    }
171
172    fs.compact(verbose, &config)
173        .context("Failed to compact engram")?;
174
175    save_embrfs(&fs, &engram, &manifest)?;
176
177    if verbose {
178        println!(
179            "Compaction complete. Removed {} deleted entries.",
180            deleted_before
181        );
182    }
183
184    Ok(())
185}