use anyhow::{Context, Result};
use std::fs::{self, File, OpenOptions};
use std::path::Path;
use super::time::modified_age_secs;
pub(crate) fn acquire_lock_file(lock_path: &Path, max_age_secs: u64) -> Result<Option<File>> {
if let Some(parent) = lock_path.parent() {
fs::create_dir_all(parent).with_context(|| format!("Failed to create {}", parent.display()))?;
}
if let Some(file) = try_create_new_lock_file(lock_path)? {
return Ok(Some(file));
}
if !lock_is_active(lock_path, max_age_secs) {
let _ = fs::remove_file(lock_path);
return try_create_new_lock_file(lock_path);
}
Ok(None)
}
fn try_create_new_lock_file(lock_path: &Path) -> Result<Option<File>> {
match OpenOptions::new().create_new(true).write(true).open(lock_path) {
Ok(file) => Ok(Some(file)),
Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => Ok(None),
Err(err) => Err(err).with_context(|| format!("Failed to create lock file {}", lock_path.display())),
}
}
pub(crate) fn lock_is_active(lock_path: &Path, max_age_secs: u64) -> bool {
modified_age_secs(lock_path).is_some_and(|age| age < max_age_secs)
}