use std::path::PathBuf;
use crate::cli::{MigrateBrainArgs, MigrationCommands};
pub async fn handle_migrate(cmd: MigrationCommands) -> i32 {
match cmd {
MigrationCommands::Brain(args) => handle_migrate_brain(args).await,
}
}
async fn handle_migrate_brain(args: MigrateBrainArgs) -> i32 {
let socket = args
.socket
.unwrap_or_else(crate::foundation::brain::default_socket_path);
println!("Foundation v1 brain migration");
println!("-----------------------------");
println!("socket: {}", socket.display());
println!("dry-run: {}", args.dry_run);
println!("archive-legacy: {}", args.archive_legacy);
println!("checkpoint: {}", args.checkpoint.display());
println!("batch size: {}", args.batch_size);
if args.dry_run {
println!("\nDRY RUN: no memory will be written, no checkpoint advanced.");
println!("The legacy store will be enumerated but not read for content.");
}
let backend = crate::foundation::brain::BrainMemoryBackend::new(socket.clone());
let probe = backend.ping().await;
println!(
"\nbackend health: {}",
match &probe {
Ok(()) => "ok: oxibrain daemon connected".to_string(),
Err(e) => format!("degraded ({e})"),
}
);
if args.dry_run {
println!("\nDry run complete. Re-run without --dry-run to perform the migration.");
return 0;
}
let checkpoint = crate::foundation::migrate::Checkpoint::load(&args.checkpoint);
if let Some(last) = checkpoint.last_id() {
println!("resuming after id: {last}");
} else {
println!("starting fresh (no checkpoint found)");
}
let legacy = crate::foundation::migrate::LegacyMemoryReader::for_default_home();
let mut migrated = 0usize;
let mut failed = 0usize;
let mut tx = crate::foundation::migrate::Migration::new(&backend, &args.checkpoint);
for batch in legacy.batches(args.batch_size) {
for item in batch {
match tx.migrate_one(item) {
Ok(crate::foundation::migrate::MigrationOutcome::Inserted(id)) => {
println!(" + {id}");
migrated += 1;
}
Ok(crate::foundation::migrate::MigrationOutcome::Skipped(id)) => {
println!(" ~ {id} (already in brain)");
}
Err(e) => {
println!(" ! {e}");
failed += 1;
}
}
}
}
println!("\nMigration summary");
println!(" inserted: {migrated}");
println!(" failed: {failed}");
if args.archive_legacy {
match crate::foundation::migrate::archive_legacy_default() {
Ok(archive_path) => {
println!("\nLegacy store archived to: {}", archive_path.display());
}
Err(e) => {
println!("\nArchive failed: {e}");
return 2;
}
}
}
if failed > 0 { 1 } else { 0 }
}
impl Default for MigrateBrainArgs {
fn default() -> Self {
Self {
socket: None,
dry_run: false,
archive_legacy: false,
checkpoint: PathBuf::from("~/.oxicode/migration/brain.json"),
batch_size: 64,
}
}
}