pub mod cli;
pub mod mock;
pub mod provider;
pub mod repo;
pub use cli::CliGitProvider;
pub use provider::GitProvider;
pub use repo::{Repo, Worktree};
pub fn parse_worktree_porcelain(output: &str) -> Vec<Worktree> {
let mut worktrees = Vec::new();
let mut current_path: Option<std::path::PathBuf> = None;
let mut current_branch: Option<String> = None;
let mut is_first = true;
for line in output.lines() {
if let Some(p) = line.strip_prefix("worktree ") {
current_path = Some(std::path::PathBuf::from(p));
} else if let Some(b) = line.strip_prefix("branch refs/heads/") {
current_branch = Some(b.to_string());
} else if line.is_empty() {
if let Some(path) = current_path.take() {
worktrees.push(Worktree {
path,
branch: current_branch.take(),
is_main: is_first,
});
is_first = false;
}
current_branch = None;
}
}
if let Some(path) = current_path {
worktrees.push(Worktree {
path,
branch: current_branch,
is_main: is_first,
});
}
worktrees
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_parse_worktree_porcelain_single() {
let output = "worktree /home/user/project\nHEAD abc123\nbranch refs/heads/main\n\n";
let wts = parse_worktree_porcelain(output);
assert_eq!(wts.len(), 1);
assert_eq!(wts[0].path, PathBuf::from("/home/user/project"));
assert_eq!(wts[0].branch.as_deref(), Some("main"));
assert!(wts[0].is_main);
}
#[test]
fn test_parse_worktree_porcelain_multiple() {
let output = "\
worktree /home/user/project
HEAD abc123
branch refs/heads/main
worktree /home/user/project-feat
HEAD def456
branch refs/heads/feat/thing
";
let wts = parse_worktree_porcelain(output);
assert_eq!(wts.len(), 2);
assert!(wts[0].is_main);
assert!(!wts[1].is_main);
assert_eq!(wts[1].branch.as_deref(), Some("feat/thing"));
}
#[test]
fn test_parse_worktree_porcelain_detached() {
let output = "worktree /home/user/project\nHEAD abc123\ndetached\n\n";
let wts = parse_worktree_porcelain(output);
assert_eq!(wts.len(), 1);
assert!(wts[0].branch.is_none());
}
#[test]
fn test_parse_worktree_porcelain_no_trailing_newline() {
let output = "worktree /home/user/project\nbranch refs/heads/main";
let wts = parse_worktree_porcelain(output);
assert_eq!(wts.len(), 1);
assert_eq!(wts[0].branch.as_deref(), Some("main"));
}
#[test]
fn test_parse_worktree_porcelain_empty() {
let wts = parse_worktree_porcelain("");
assert!(wts.is_empty());
}
}