use anyhow::{Context, Result};
use directories::ProjectDirs;
use std::fs;
use std::path::Path;
use crate::key::{get_config_dir, get_keys_dir};
const KEY_FILENAME: &str = "identity.key.enc";
pub fn ensure_migrated() -> Result<()> {
let new_home = get_config_dir()?;
if new_home.join("keys.json").exists() || new_home.join("keys").is_dir() {
return Ok(());
}
let old_home = match ProjectDirs::from("", "", "vwh-author") {
Some(p) => p.config_dir().to_path_buf(),
None => return Ok(()),
};
if !old_home.is_dir() {
return Ok(());
}
let entries = match fs::read_dir(&old_home) {
Ok(e) => e,
Err(_) => return Ok(()),
};
let new_keys = get_keys_dir()?;
let mut migrated_keys = 0usize;
let mut migrated_state = false;
for entry in entries.flatten() {
let path = entry.path();
let name = match path.file_name().and_then(|n| n.to_str()) {
Some(n) => n.to_string(),
None => continue,
};
if path.is_file() && (name == "keys.json" || name == "ledger.json") {
fs::create_dir_all(&new_home)?;
fs::copy(&path, new_home.join(&name))
.with_context(|| format!("Failed to copy {name} during migration"))?;
migrated_state = true;
} else if path.is_dir() && name == "registry" {
copy_dir_all(&path, &new_home.join("registry"))
.context("Failed to copy registry/ during migration")?;
} else if path.is_dir() && path.join(KEY_FILENAME).exists() {
copy_dir_all(&path, &new_keys.join(&name))
.with_context(|| format!("Failed to copy key '{name}' during migration"))?;
migrated_keys += 1;
}
}
if migrated_keys > 0 || migrated_state {
println!(
"[migrate] Imported existing keystore into {}",
new_home.display()
);
println!(
"[migrate] {migrated_keys} key(s) moved under keys/. Originals left untouched at:"
);
println!("[migrate] {}", old_home.display());
println!("[migrate] Remove the old directory once you've verified the new one.\n");
}
Ok(())
}
fn copy_dir_all(src: &Path, dst: &Path) -> Result<()> {
fs::create_dir_all(dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let from = entry.path();
let to = dst.join(entry.file_name());
if entry.file_type()?.is_dir() {
copy_dir_all(&from, &to)?;
} else {
fs::copy(&from, &to)?;
}
}
Ok(())
}