1use std::fs::{File, OpenOptions};
2use std::path::Path;
3
4use fs4::fs_std::FileExt;
5use linkrs_core::StorageError;
6
7use crate::error::MigrationError;
8
9pub struct MigrationFileLock {
10 _file: File,
11 path: std::path::PathBuf,
12}
13
14impl MigrationFileLock {
15 pub fn try_acquire(path: &Path) -> Result<Self, MigrationError> {
16 let file = OpenOptions::new()
17 .write(true)
18 .create(true)
19 .truncate(true)
20 .open(path)
21 .map_err(|e| MigrationError::Storage(Box::new(StorageError::from(e))))?;
22
23 file.try_lock_exclusive().map_err(|e| {
24 MigrationError::Lock(format!(
25 "migration in progress (lock file: {}): {}",
26 path.display(),
27 e
28 ))
29 })?;
30
31 Ok(Self {
32 _file: file,
33 path: path.to_path_buf(),
34 })
35 }
36}
37
38impl Drop for MigrationFileLock {
39 fn drop(&mut self) {
40 let _ = fs4::fs_std::FileExt::unlock(&self._file);
43 let _ = std::fs::remove_file(&self.path);
44 }
45}
46
47impl std::fmt::Debug for MigrationFileLock {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 f.debug_struct("MigrationFileLock")
50 .field("path", &self.path)
51 .finish()
52 }
53}