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}