use anyhow::Context;
use oxibrain::{vault, vault::SyncReport};
#[cfg(unix)]
use oxibrain_client::default_socket_path;
use std::path::Path;
pub async fn run(dir: &Path, root: &Path, space: &str) -> anyhow::Result<()> {
let report = match oxibrain::Brain::open(oxibrain::BrainConfig::at(dir)).await {
Ok(brain) => vault::sync_vault(&brain, root, space).await?,
Err(oxibrain::BrainError::Locked { holder }) => {
eprintln!("note: store locked ({holder}); attaching to the daemon socket");
run_via_daemon(root, space).await?
}
Err(e) => return Err(e.into()),
};
print_report(&report);
Ok(())
}
async fn run_via_daemon(root: &Path, space: &str) -> anyhow::Result<SyncReport> {
let socket = socket_path()?;
let mut client = oxibrain_client::BrainClient::connect(&socket)
.await
.with_context(|| format!("attach to daemon at {}", socket.display()))?;
let out = client
.sync_run(&root.to_string_lossy(), space)
.await
.context("sync/run on daemon")?;
Ok(SyncReport {
new: out.new,
modified: out.modified,
unchanged: out.unchanged,
})
}
#[cfg(unix)]
fn socket_path() -> anyhow::Result<std::path::PathBuf> {
default_socket_path().ok_or_else(|| {
anyhow::anyhow!("no daemon socket: $OXIBRAIN_SOCKET unset and $HOME unavailable")
})
}
#[cfg(not(unix))]
fn socket_path() -> anyhow::Result<std::path::PathBuf> {
anyhow::bail!("daemon attach is only supported on Unix")
}
fn print_report(report: &SyncReport) {
if !report.new.is_empty() {
for p in &report.new {
println!(" new: {p}");
}
}
if !report.modified.is_empty() {
for p in &report.modified {
println!(" modified: {p}");
}
}
println!(
"sync complete: {} new, {} unchanged, {} modified",
report.new.len(),
report.unchanged.len(),
report.modified.len()
);
}