use std::fs;
use std::path::{Path, PathBuf};
const WORKTREES_DIR: &str = "worktrees";
const GITDIR_POINTER: &str = "gitdir";
const LOCK_MARKER: &str = "locked";
pub fn stale_worktree_records(git_dir: &Path) -> Vec<PathBuf> {
let Ok(entries) = fs::read_dir(git_dir.join(WORKTREES_DIR)) else {
return Vec::new();
};
entries
.filter_map(Result::ok)
.map(|entry| entry.path())
.filter(|record| is_stale(record))
.collect()
}
pub fn linked_worktree_paths(git_dir: &Path) -> Vec<PathBuf> {
let Ok(entries) = fs::read_dir(git_dir.join(WORKTREES_DIR)) else {
return Vec::new();
};
entries
.filter_map(Result::ok)
.filter_map(|entry| checkout_path(&entry.path()))
.collect()
}
fn checkout_path(record: &Path) -> Option<PathBuf> {
let pointer = fs::read_to_string(record.join(GITDIR_POINTER)).ok()?;
let git_file = Path::new(pointer.trim());
if git_file.exists() {
git_file.parent().map(Path::to_path_buf)
} else {
None
}
}
fn is_stale(record: &Path) -> bool {
if record.join(LOCK_MARKER).exists() {
false
} else {
match fs::read_to_string(record.join(GITDIR_POINTER)) {
Ok(pointer) => !Path::new(pointer.trim()).exists(),
Err(_) => false,
}
}
}
#[cfg(test)]
mod tests;