use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use fs2::FileExt;
use crate::error::{Error, IoCtx, 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).io_ctx(lock_path)?;
}
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(lock_path)
.io_ctx(lock_path)?;
if let Err(e) = file.try_lock_exclusive() {
return match e.kind() {
std::io::ErrorKind::WouldBlock => Err(Error::Locked { path: lock_path.to_path_buf() }),
_ => Err(Error::Io { path: lock_path.to_path_buf(), source: e }),
};
}
Ok(WorkspaceLock { file, path: lock_path.to_path_buf() })
}
#[cfg(test)]
#[path = "lockfile_tests.rs"]
mod tests;