use std::fs;
use std::io::{ErrorKind, Write};
use std::path::PathBuf;
use anyhow::{Context, Result, bail};
use crate::git;
const LOCK_FILE: &str = "stk-lock";
pub struct Lock {
path: Option<PathBuf>,
}
impl Lock {
pub fn acquire(command: &str) -> Result<Self> {
let Ok(path) = git::git_path(LOCK_FILE) else {
return Ok(Self { path: None });
};
let path = PathBuf::from(path);
match fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&path)
{
Ok(mut file) => {
let _ = writeln!(file, "{} {command}", std::process::id());
Ok(Self { path: Some(path) })
}
Err(error) if error.kind() == ErrorKind::AlreadyExists => {
let holder = fs::read_to_string(&path).unwrap_or_default();
let holder = holder.trim();
let by = if holder.is_empty() {
String::new()
} else {
format!(" ({holder})")
};
bail!(
"another git stk operation is in progress{by}; wait for it to \
finish, or remove {} if it is stale",
path.display()
);
}
Err(error) => {
Err(error).with_context(|| format!("failed to take the lock at {}", path.display()))
}
}
}
}
impl Drop for Lock {
fn drop(&mut self) {
if let Some(path) = &self.path {
let _ = fs::remove_file(path);
}
}
}