use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use fs2::FileExt;
use crate::error::{Error, Result};
#[derive(Debug)]
#[must_use = "lock is released as soon as the guard is dropped"]
pub struct WorkspaceLock {
file: File,
path: PathBuf,
}
impl WorkspaceLock {
pub fn path(&self) -> &Path {
&self.path
}
}
impl Drop for WorkspaceLock {
fn drop(&mut self) {
let _ = self.file.unlock();
}
}
pub fn acquire_workspace_lock(lock_path: &Path) -> Result<WorkspaceLock> {
if let Some(parent) = lock_path.parent() {
std::fs::create_dir_all(parent)
.map_err(|e| Error::Io { path: lock_path.to_path_buf(), source: e })?;
}
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(lock_path)
.map_err(|e| Error::Io { path: lock_path.to_path_buf(), source: e })?;
file.try_lock_exclusive().map_err(|_| Error::Locked { path: lock_path.to_path_buf() })?;
Ok(WorkspaceLock { file, path: lock_path.to_path_buf() })
}
#[cfg(test)]
#[path = "lockfile_tests.rs"]
mod tests;