1use anyhow::Result;
2use std::path::PathBuf;
3
4use crate::git::{
5 bare_clone, branch_exists_local, branch_exists_remote, create_local_worktree, create_worktree,
6 detect_default_branch, git_fetch,
7};
8use crate::issue::IssueRef;
9use crate::ttl::WorkspaceRegistry;
10
11pub struct Workspace {
13 pub path: PathBuf,
15 pub issue: IssueRef,
17 pub created: bool,
19}
20
21impl Workspace {
22 pub fn open_or_create(issue: IssueRef) -> Result<Self> {
29 let worktree_path = issue.temp_path();
30 let bare_path = issue.bare_clone_path();
31
32 if worktree_path.exists() {
34 return Ok(Self {
35 path: worktree_path,
36 issue,
37 created: false,
38 });
39 }
40
41 if let IssueRef::Local { project_path, .. } = &issue {
43 eprintln!("Creating local worktree at {}…", worktree_path.display());
45 let branch = issue.branch_name();
46 let branch_exists = branch_exists_local(project_path, &branch);
47 std::fs::create_dir_all(worktree_path.parent().unwrap_or(&worktree_path))?;
48 create_local_worktree(project_path, &worktree_path, &branch, branch_exists)?;
49 } else {
50 if bare_path.exists() {
51 eprintln!("Fetching origin…");
52 git_fetch(&bare_path)?;
53 } else {
54 eprintln!(
55 "Cloning {} (bare) into {}…",
56 issue.clone_url(),
57 bare_path.display()
58 );
59 bare_clone(&issue.clone_url(), &bare_path)?;
60 }
61
62 let base_branch = detect_default_branch(&bare_path)?;
63 eprintln!("Default branch: {base_branch}");
64
65 let branch = issue.branch_name();
66 let branch_exists = branch_exists_remote(&bare_path, &branch);
67
68 eprintln!(
69 "Creating worktree {} at {}…",
70 branch,
71 worktree_path.display()
72 );
73 create_worktree(
74 &bare_path,
75 &worktree_path,
76 &branch,
77 &base_branch,
78 branch_exists,
79 )?;
80 }
81
82 if let Ok(mut registry) = WorkspaceRegistry::load() {
83 registry.register(worktree_path.clone());
84 let _ = registry.save();
85 }
86
87 Ok(Self {
88 path: worktree_path,
89 issue,
90 created: true,
91 })
92 }
94}
95
96#[cfg(test)]
97#[path = "workspace_tests.rs"]
98mod workspace_tests;