agentree 0.1.0

A safety-oriented local CLI for isolated Git worktree tasks
Documentation
use std::{
    fs::{File, OpenOptions},
    path::Path,
};

use crate::domain::{AppError, ErrorKind};

pub struct FileLock {
    file: File,
    path: std::path::PathBuf,
}

impl FileLock {
    pub fn acquire(path: &Path) -> Result<Self, AppError> {
        if let Some(parent) = path.parent() {
            std::fs::create_dir_all(parent)?;
        }
        let file = OpenOptions::new()
            .create(true)
            .truncate(false)
            .read(true)
            .write(true)
            .open(path)?;
        #[cfg(unix)]
        {
            let result = unsafe {
                libc::flock(
                    std::os::fd::AsRawFd::as_raw_fd(&file),
                    libc::LOCK_EX | libc::LOCK_NB,
                )
            };
            if result != 0 {
                return Err(AppError::diagnostic(
                    "AGT-0601",
                    format!("lock is busy: {}", path.display()),
                    ErrorKind::LockConflict,
                ));
            }
        }
        Ok(Self {
            file,
            path: path.to_path_buf(),
        })
    }
}

impl Drop for FileLock {
    fn drop(&mut self) {
        #[cfg(unix)]
        unsafe {
            libc::flock(std::os::fd::AsRawFd::as_raw_fd(&self.file), libc::LOCK_UN);
        }
        let _ = &self.path;
    }
}