use std::collections::BTreeMap;
use std::path::Path;
use serde::{Deserialize, Serialize};
use lean_ctx_protocol::hive::vault::VaultV1;
pub const VAULTS_FILE: &str = "projects.json";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct VaultRecord {
#[serde(rename = "project_id", alias = "vault_id")]
pub vault_id: String,
pub ns: String,
pub name: String,
pub sealed: bool,
#[serde(default)]
pub roots: Vec<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct VaultMap {
#[serde(default, rename = "projects", alias = "vaults")]
pub vaults: BTreeMap<String, VaultRecord>,
}
impl VaultMap {
pub fn load(data_dir: &Path) -> Self {
std::fs::read(data_dir.join(VAULTS_FILE))
.ok()
.and_then(|bytes| serde_json::from_slice(&bytes).ok())
.unwrap_or_default()
}
pub fn for_root(&self, root: &str) -> Option<&VaultRecord> {
let find = |root: &str| {
self.vaults.values().find(|record| {
record
.roots
.iter()
.any(|known| crate::core::pathutil::same_project(known, root))
})
};
find(root).or_else(|| {
let main = crate::core::git_worktree::main_worktree_root(Path::new(root))?;
find(&main.to_string_lossy())
})
}
pub fn save(&self, data_dir: &Path) -> std::io::Result<()> {
let bytes = serde_json::to_vec_pretty(self).map_err(std::io::Error::other)?;
crate::core::secure_fs::write_private(data_dir, VAULTS_FILE, &bytes)
}
pub fn record(&mut self, stable: &str, vault: &VaultV1, root: &Path) {
let root = root.to_string_lossy().into_owned();
let entry = self
.vaults
.entry(stable.to_string())
.or_insert_with(|| VaultRecord {
vault_id: vault.vault_id.clone(),
ns: vault.vault.ns.clone(),
name: vault.vault.name.clone(),
sealed: false,
roots: Vec::new(),
});
entry.vault_id.clone_from(&vault.vault_id);
entry.ns.clone_from(&vault.vault.ns);
entry.name.clone_from(&vault.vault.name);
entry.sealed = false;
if !entry.roots.contains(&root) {
entry.roots.push(root);
}
}
}