gitoxide_core/repository/
worktree.rs1use anyhow::bail;
2use gix::prelude::ObjectIdExt;
3use unicode_width::UnicodeWidthStr;
4
5use crate::OutputFormat;
6
7pub fn list(repo: gix::Repository, out: &mut dyn std::io::Write, format: OutputFormat) -> anyhow::Result<()> {
8 if format != OutputFormat::Human {
9 bail!("JSON output isn't implemented yet");
10 }
11 let main_repo = repo.main_repo()?;
12 let mut worktrees = Vec::new();
13
14 if let Some(worktree) = main_repo.worktree() {
15 worktrees.push(create_worktree_info(&main_repo, gix::path::realpath(worktree.base())?)?);
16 }
17
18 for proxy in main_repo.worktrees()? {
19 let base = gix::path::realpath(proxy.base()?)?;
20
21 match proxy.into_repo() {
22 Ok(worktree_repo) => {
23 worktrees.push(create_worktree_info(&worktree_repo, base)?);
24 }
25 Err(_) => {
26 worktrees.push(create_inaccessible_worktree_info(&repo, base));
27 }
28 }
29 }
30
31 let path_width = worktrees
32 .iter()
33 .map(|worktree| UnicodeWidthStr::width(worktree.base.as_str()))
34 .max()
35 .unwrap_or(0);
36
37 for worktree in worktrees {
38 worktree.write(out, path_width)?;
39 }
40
41 Ok(())
42}
43
44struct WorktreeInfo {
45 base: String,
46 head: String,
47 branch: String,
48}
49
50impl WorktreeInfo {
51 fn write(&self, out: &mut dyn std::io::Write, path_width: usize) -> std::io::Result<()> {
52 writeln!(
53 out,
54 "{}{} {} [{}]",
55 self.base,
56 " ".repeat(path_width.saturating_sub(UnicodeWidthStr::width(self.base.as_str()))),
57 self.head,
58 self.branch,
59 )
60 }
61}
62
63fn create_worktree_info(repo: &gix::Repository, base: std::path::PathBuf) -> anyhow::Result<WorktreeInfo> {
64 let head = repo
65 .head_id()
66 .map_or_else(
67 |_| repo.object_hash().null().attach(repo).shorten_or_id(),
68 |id| id.shorten_or_id(),
69 )
70 .to_string();
71
72 let branch = repo.head_name()?.map_or_else(
73 || "<detached>".to_string(),
74 |name| name.shorten().to_owned().to_string(),
75 );
76
77 Ok(WorktreeInfo {
78 base: base.display().to_string(),
79 head,
80 branch,
81 })
82}
83
84fn create_inaccessible_worktree_info(repo: &gix::Repository, base: std::path::PathBuf) -> WorktreeInfo {
85 WorktreeInfo {
86 base: base.display().to_string(),
87 head: repo.object_hash().null().attach(repo).shorten_or_id().to_string(),
88 branch: "<unknown>".to_string(),
89 }
90}