From dd33ddf28d693b2c64ed91f75656c61416ee2538 Mon Sep 17 00:00:00 2001 From: JJ Liebig Date: Tue, 22 Sep 2026 18:43:12 +0200 Subject: fix: move worktree lookups async (#4492) --- src/worktree.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'src/worktree.rs') diff --git a/src/worktree.rs b/src/worktree.rs index 72cdb3d2..17f560a4 100644 --- a/src/worktree.rs +++ b/src/worktree.rs @@ -495,6 +495,8 @@ pub(crate) fn list_existing_worktrees( repo_root: &Path, trust_repository: bool, ) -> Result, String> { + #[cfg(test)] + test_list_gate::wait(repo_root); let output = repository_git_command(repo_root, trust_repository) .args(["worktree", "list", "--porcelain"]) .output() @@ -513,6 +515,47 @@ pub(crate) fn list_existing_worktrees( }) } +#[cfg(test)] +pub(crate) mod test_list_gate { + use std::path::{Path, PathBuf}; + use std::sync::{mpsc, Mutex}; + + struct Gate { + path: PathBuf, + entered: mpsc::Sender<()>, + release: mpsc::Receiver<()>, + } + + static GATES: Mutex> = Mutex::new(Vec::new()); + + pub(crate) fn block(path: &Path) -> (mpsc::Receiver<()>, mpsc::Sender<()>) { + let (entered, entry_rx) = mpsc::channel(); + let (release_tx, release) = mpsc::channel(); + GATES.lock().unwrap().push(Gate { + path: super::canonical_or_original(path), + entered, + release, + }); + (entry_rx, release_tx) + } + + pub(super) fn wait(path: &Path) { + let gate = { + let mut gates = GATES.lock().unwrap(); + gates + .iter() + .position(|gate| gate.path == super::canonical_or_original(path)) + .map(|index| gates.remove(index)) + }; + if let Some(gate) = gate { + gate.entered.send(()).unwrap(); + gate.release + .recv_timeout(std::time::Duration::from_secs(10)) + .expect("test must release worktree discovery without blocking the server loop"); + } + } +} + fn worktree_list_contains_path( repo_root: &Path, path: &Path, -- cgit v1.2.3