weavatrix-worktree 0.2.0

Bounded, crash-recoverable multi-file worktree edits for source refactoring
Documentation
use crate::{
    error::{TransactionPhase, WorktreeError, WorktreeErrorCode},
    filesystem::{ControlDir, FsRoot},
};

pub(crate) struct TransactionLock {
    pub(crate) control: ControlDir,
    pub(crate) file: std::fs::File,
}

pub(crate) fn acquire(root: &FsRoot) -> Result<TransactionLock, WorktreeError> {
    let control = root
        .open_control(true)
        .map_err(|error| {
            WorktreeError::with_source(
                WorktreeErrorCode::Io,
                TransactionPhase::Lock,
                "failed to open the worktree control directory",
                error,
            )
        })?
        .ok_or_else(|| {
            WorktreeError::new(
                WorktreeErrorCode::Io,
                TransactionPhase::Lock,
                "worktree control directory was unavailable after creation",
            )
        })?;
    let file = control.open_lock().map_err(|error| {
        WorktreeError::with_source(
            WorktreeErrorCode::Io,
            TransactionPhase::Lock,
            "failed to open the worktree lock",
            error,
        )
    })?;
    match fs4::FileExt::try_lock(&file) {
        Ok(()) => Ok(TransactionLock { control, file }),
        Err(fs4::TryLockError::WouldBlock) => Err(WorktreeError::new(
            WorktreeErrorCode::RootBusy,
            TransactionPhase::Lock,
            "another worktree transaction holds the root lock",
        )),
        Err(fs4::TryLockError::Error(error)) => Err(WorktreeError::with_source(
            WorktreeErrorCode::Io,
            TransactionPhase::Lock,
            "failed to acquire the worktree lock",
            error,
        )),
    }
}