use crate::paths::EddaPaths;
use fs2::FileExt;
use std::fs::{File, OpenOptions};
pub struct WorkspaceLock {
_file: File,
}
impl WorkspaceLock {
pub fn acquire(paths: &EddaPaths) -> anyhow::Result<Self> {
let file = OpenOptions::new()
.create(true)
.truncate(false)
.read(true)
.write(true)
.open(&paths.lock_file)
.map_err(|e| {
anyhow::anyhow!("cannot open lock file {}: {}", paths.lock_file.display(), e)
})?;
file.try_lock_exclusive().map_err(|_| {
anyhow::anyhow!(
"workspace is locked by another process ({})",
paths.lock_file.display()
)
})?;
Ok(Self { _file: file })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn acquire_and_drop() {
let tmp = std::env::temp_dir().join(format!("edda_lock_test_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&tmp);
let p = EddaPaths::discover(&tmp);
p.ensure_layout().unwrap();
let lock = WorkspaceLock::acquire(&p).unwrap();
assert!(WorkspaceLock::acquire(&p).is_err());
drop(lock);
let _lock2 = WorkspaceLock::acquire(&p).unwrap();
let _ = std::fs::remove_dir_all(&tmp);
}
}