linkrs-migration 0.1.0

Schema and data migration for Linkrs
Documentation
use std::fs::{File, OpenOptions};
use std::path::Path;

use fs4::fs_std::FileExt;
use linkrs_core::StorageError;

use crate::error::MigrationError;

pub struct MigrationFileLock {
    _file: File,
    path: std::path::PathBuf,
}

impl MigrationFileLock {
    pub fn try_acquire(path: &Path) -> Result<Self, MigrationError> {
        let file = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .map_err(|e| MigrationError::Storage(Box::new(StorageError::from(e))))?;

        file.try_lock_exclusive().map_err(|e| {
            MigrationError::Lock(format!(
                "migration in progress (lock file: {}): {}",
                path.display(),
                e
            ))
        })?;

        Ok(Self {
            _file: file,
            path: path.to_path_buf(),
        })
    }
}

impl Drop for MigrationFileLock {
    fn drop(&mut self) {
        // Fully-qualified to avoid `unstable_name_collisions` once std adds
        // `File::unlock`.
        let _ = fs4::fs_std::FileExt::unlock(&self._file);
        let _ = std::fs::remove_file(&self.path);
    }
}

impl std::fmt::Debug for MigrationFileLock {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MigrationFileLock")
            .field("path", &self.path)
            .finish()
    }
}