//! serializes generation publication, activation, and CAS collection within one output root. use std::fs::{File, OpenOptions}; use std::path::Path; use anyhow::Context as _; /// keep the file alive for the whole operation; never unlink the lock. /// the OS releases this advisory lock on process exit, including crashes. pub fn lock(root: &Path) -> anyhow::Result { std::fs::create_dir_all(root).context("create output root")?; let file = OpenOptions::new() .create(true) .read(true) .write(true) .open(root.join(".admin.lock")) .context("open output lock")?; file.lock().context("lock output root")?; Ok(file) } #[cfg(test)] mod tests { use super::*; #[test] fn lock_is_exclusive_and_released_on_drop() { let root = tempfile::tempdir().unwrap(); let first = lock(root.path()).unwrap(); let second = OpenOptions::new() .read(true) .write(true) .open(root.path().join(".admin.lock")) .unwrap(); assert!(second.try_lock().is_err()); drop(first); second.try_lock().unwrap(); } }