git_claw/workflow/
list.rs1use crate::cli::output::{print_worktree_table, WorktreeRow};
4use crate::core::config::Config;
5use crate::core::port::calculate_effective_ports;
6use crate::infra::git::{
7 git_head_commit, resolve_git_common_dir, resolve_repo_name, resolve_toplevel,
8};
9use crate::infra::lock::SlotLock;
10use crate::infra::registry::SlotRegistry;
11use crate::workflow::error::WorkflowError;
12use std::path::Path;
13
14pub fn list_worktrees(repo_root: Option<&Path>) -> Result<(), WorkflowError> {
16 let toplevel = resolve_toplevel(repo_root)?;
17 let common_dir = resolve_git_common_dir(Some(&toplevel))?;
18 let repo_name = resolve_repo_name(&toplevel);
19
20 let config_path = toplevel.join(".git-claw.toml");
21 let config = Config::load_or_default(&config_path, &repo_name)?;
22
23 let registry_path = common_dir.join("claw/slots.json");
24 let lock_path = common_dir.join("claw/slots.lock");
25
26 let _lock = SlotLock::acquire(&lock_path)?;
27 let mut registry = SlotRegistry::load_or_empty(®istry_path)?;
28
29 let _ = registry.auto_gc(®istry_path, Some(&toplevel), true);
31
32 let mut rows = Vec::new();
33 for slot in ®istry.slots {
34 let ports_map = calculate_effective_ports(&config.ports, slot.id)?;
35 let ports_str = if ports_map.is_empty() {
36 "-".to_string()
37 } else {
38 ports_map
39 .into_iter()
40 .map(|(name, port)| format!("{}:{}", name, port))
41 .collect::<Vec<_>>()
42 .join(", ")
43 };
44
45 let commit_str = git_head_commit(Path::new(&slot.path)).unwrap_or_else(|_| "-".to_string());
46
47 rows.push(WorktreeRow {
48 slot: slot.id,
49 branch: slot.branch.clone(),
50 path: slot.path.clone(),
51 ports: ports_str,
52 commit: commit_str,
53 });
54 }
55
56 drop(_lock);
57
58 print_worktree_table(&rows);
59
60 Ok(())
61}