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;
9
10pub struct Workspace {
12 pub path: PathBuf,
14 pub issue: IssueRef,
16 pub created: bool,
18}
19
20impl Workspace {
21 pub fn open_or_create(issue: IssueRef) -> Result<Self> {
28 let worktree_path = issue.temp_path();
29 let bare_path = issue.bare_clone_path();
30
31 if worktree_path.exists() {
33 return Ok(Self {
34 path: worktree_path,
35 issue,
36 created: false,
37 });
38 }
39
40 if let IssueRef::Local { project_path, .. } = &issue {
42 eprintln!("Creating local worktree at {}…", worktree_path.display());
44 let branch = issue.branch_name();
45 let branch_exists = branch_exists_local(project_path, &branch);
46 std::fs::create_dir_all(worktree_path.parent().unwrap_or(&worktree_path))?;
47 create_local_worktree(project_path, &worktree_path, &branch, branch_exists)?;
48 } else {
49 if bare_path.exists() {
50 eprintln!("Fetching origin…");
51 git_fetch(&bare_path)?;
52 } else {
53 eprintln!(
54 "Cloning {} (bare) into {}…",
55 issue.clone_url(),
56 bare_path.display()
57 );
58 bare_clone(&issue.clone_url(), &bare_path)?;
59 }
60
61 let base_branch = detect_default_branch(&bare_path)?;
62 eprintln!("Default branch: {base_branch}");
63
64 let branch = issue.branch_name();
65 let branch_exists = branch_exists_remote(&bare_path, &branch);
66
67 eprintln!(
68 "Creating worktree {} at {}…",
69 branch,
70 worktree_path.display()
71 );
72 create_worktree(
73 &bare_path,
74 &worktree_path,
75 &branch,
76 &base_branch,
77 branch_exists,
78 )?;
79 }
80
81 Ok(Self {
82 path: worktree_path,
83 issue,
84 created: true,
85 })
86 }
88}
89
90#[cfg(test)]
91#[path = "workspace_tests.rs"]
92mod workspace_tests;