use std::fmt;
use std::path::PathBuf;
use vti_common::config::StoreConfig;
use vti_common::error::AppError;
use super::Store;
#[derive(Debug)]
pub enum OfflineStoreError {
DaemonRunning { data_dir: PathBuf },
Other(AppError),
}
impl fmt::Display for OfflineStoreError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DaemonRunning { data_dir } => write!(
f,
"the VTC daemon is running and holds the store at {} — this command \
opens the store directly, and only one process can. Stop the daemon \
and re-run it",
data_dir.display()
),
Self::Other(e) => write!(f, "{e}"),
}
}
}
impl std::error::Error for OfflineStoreError {}
pub fn open_offline(config: &StoreConfig) -> Result<Store, OfflineStoreError> {
match Store::open(config) {
Ok(store) => Ok(store),
Err(AppError::Store(fjall::Error::Locked)) => Err(OfflineStoreError::DaemonRunning {
data_dir: config.data_dir.clone(),
}),
Err(e) => Err(OfflineStoreError::Other(e)),
}
}
#[cfg(test)]
fn held_by_another(data_dir: &std::path::Path) -> bool {
matches!(
open_offline(&StoreConfig {
data_dir: data_dir.to_path_buf()
}),
Err(OfflineStoreError::DaemonRunning { .. })
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_held_store_is_reported_as_the_daemon_running() {
let dir = tempfile::tempdir().unwrap();
let config = StoreConfig {
data_dir: dir.path().to_path_buf(),
};
let _daemon = Store::open(&config).expect("the first open succeeds");
match open_offline(&config) {
Err(OfflineStoreError::DaemonRunning { data_dir }) => {
assert_eq!(data_dir, dir.path());
}
Err(OfflineStoreError::Other(e)) => {
panic!("a held store must read as the daemon running, got: {e}")
}
Ok(_) => panic!("fjall allowed a second process on one data dir"),
}
}
#[test]
fn the_message_names_the_situation_not_the_storage_engine() {
let msg = OfflineStoreError::DaemonRunning {
data_dir: PathBuf::from("/var/lib/vtc"),
}
.to_string();
assert!(msg.contains("daemon is running"), "{msg}");
assert!(msg.contains("/var/lib/vtc"), "{msg}");
assert!(!msg.contains("Fjall"), "{msg}");
}
#[test]
fn a_free_store_opens() {
let dir = tempfile::tempdir().unwrap();
assert!(!held_by_another(dir.path()));
}
}