zoi/pkg/
lock.rs

1use anyhow::{Result, anyhow};
2use colored::*;
3use std::fs;
4use std::path::PathBuf;
5
6fn get_lock_path() -> Result<PathBuf> {
7    let home_dir = home::home_dir().ok_or_else(|| anyhow!("Could not find home directory."))?;
8    Ok(home_dir.join(".zoi").join("pkgs").join("lock"))
9}
10
11pub fn acquire_lock() -> Result<LockGuard> {
12    let lock_path = match get_lock_path() {
13        Ok(p) => p,
14        Err(_) => {
15            return Ok(LockGuard { path: None });
16        }
17    };
18
19    if lock_path.exists() {
20        eprintln!(
21            "{}: Another Zoi process may be running.",
22            "Error".red().bold()
23        );
24        eprintln!(
25            "If you are sure no other Zoi process is running, you can remove the lock file at:"
26        );
27        eprintln!("  {}", lock_path.display());
28        eprintln!("This can happen if a previous operation was interrupted.");
29        return Err(anyhow!("Could not acquire lock."));
30    }
31
32    if let Some(parent) = lock_path.parent()
33        && let Err(e) = fs::create_dir_all(parent)
34    {
35        eprintln!(
36            "Warning: could not create lock directory {}: {}",
37            parent.display(),
38            e
39        );
40        return Ok(LockGuard { path: None });
41    }
42
43    match fs::File::create(&lock_path) {
44        Ok(_) => Ok(LockGuard {
45            path: Some(lock_path),
46        }),
47        Err(e) => {
48            eprintln!("Warning: could not create lock file: {}", e);
49            Ok(LockGuard { path: None })
50        }
51    }
52}
53
54pub struct LockGuard {
55    path: Option<PathBuf>,
56}
57
58impl Drop for LockGuard {
59    fn drop(&mut self) {
60        if let Some(path) = &self.path
61            && path.exists()
62            && let Err(e) = fs::remove_file(path)
63        {
64            eprintln!("Warning: Failed to remove lock file: {}", e);
65        }
66    }
67}