1use std::path::PathBuf;
5
6use objects::HeddleError;
7use repo::{FsMonitorMode, Repository, WorktreeStatusOptions};
8
9pub struct ExecutionContext {
14 repo: Option<Repository>,
15 start_path: Option<PathBuf>,
16 principal_fallback: Option<(String, String)>,
17 hosted_principal: Option<(String, String)>,
18 hosted_account_unclaimed: bool,
19 fsmonitor_mode: FsMonitorMode,
20}
21
22impl ExecutionContext {
23 pub fn builder() -> ExecutionContextBuilder {
24 ExecutionContextBuilder::default()
25 }
26
27 pub fn require_repo(&self) -> Result<&Repository, HeddleError> {
28 self.repo
29 .as_ref()
30 .ok_or_else(|| HeddleError::RepositoryNotFound(PathBuf::from(".")))
31 }
32
33 pub fn repo(&self) -> Option<&Repository> {
34 self.repo.as_ref()
35 }
36
37 pub fn start_path(&self) -> Option<&std::path::Path> {
38 self.start_path.as_deref()
39 }
40
41 pub fn principal_fallback(&self) -> Option<(&str, &str)> {
43 self.principal_fallback
44 .as_ref()
45 .map(|(name, email)| (name.as_str(), email.as_str()))
46 }
47
48 pub fn hosted_principal(&self) -> Option<(&str, &str)> {
51 self.hosted_principal
52 .as_ref()
53 .map(|(name, email)| (name.as_str(), email.as_str()))
54 }
55
56 pub fn hosted_account_unclaimed(&self) -> bool {
59 self.hosted_account_unclaimed
60 }
61
62 pub fn fsmonitor_mode(&self) -> FsMonitorMode {
64 self.fsmonitor_mode
65 }
66
67 pub fn worktree_status_options(&self) -> WorktreeStatusOptions {
68 WorktreeStatusOptions {
69 fsmonitor: repo::FsMonitorSettings {
70 mode: self.fsmonitor_mode,
71 },
72 }
73 }
74}
75
76#[derive(Default)]
78pub struct ExecutionContextBuilder {
79 repo: Option<Repository>,
80 start_path: Option<PathBuf>,
81 principal_fallback: Option<(String, String)>,
82 hosted_principal: Option<(String, String)>,
83 hosted_account_unclaimed: bool,
84 fsmonitor_mode: FsMonitorMode,
85}
86
87impl ExecutionContextBuilder {
88 pub fn repo(mut self, repo: Repository) -> Self {
89 self.repo = Some(repo);
90 self
91 }
92
93 pub fn start_path(mut self, path: impl Into<PathBuf>) -> Self {
94 self.start_path = Some(path.into());
95 self
96 }
97
98 pub fn principal_fallback(mut self, principal: Option<(String, String)>) -> Self {
99 self.principal_fallback = principal;
100 self
101 }
102
103 pub fn hosted_principal(mut self, principal: Option<(String, String)>) -> Self {
104 self.hosted_principal = principal;
105 self
106 }
107
108 pub fn hosted_account_unclaimed(mut self, unclaimed: bool) -> Self {
109 self.hosted_account_unclaimed = unclaimed;
110 self
111 }
112
113 pub fn fsmonitor_mode(mut self, mode: FsMonitorMode) -> Self {
114 self.fsmonitor_mode = mode;
115 self
116 }
117
118 pub fn build(self) -> ExecutionContext {
119 ExecutionContext {
120 repo: self.repo,
121 start_path: self.start_path,
122 principal_fallback: self.principal_fallback,
123 hosted_principal: self.hosted_principal,
124 hosted_account_unclaimed: self.hosted_account_unclaimed,
125 fsmonitor_mode: self.fsmonitor_mode,
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn default_context_has_no_repo_and_noop_sinks() {
136 let ctx = ExecutionContext::builder().build();
137
138 assert!(matches!(
139 ctx.require_repo(),
140 Err(HeddleError::RepositoryNotFound(_))
141 ));
142 assert_eq!(ctx.fsmonitor_mode(), FsMonitorMode::Off);
143 assert!(ctx.principal_fallback().is_none());
144 assert!(!ctx.hosted_account_unclaimed());
145 }
146
147 #[test]
148 fn builder_sets_non_repo_fields() {
149 let ctx = ExecutionContext::builder()
150 .start_path("/tmp/heddle-verbs-context-test")
151 .principal_fallback(Some(("Luke".into(), "luke@example.com".into())))
152 .hosted_account_unclaimed(true)
153 .fsmonitor_mode(FsMonitorMode::Watchman)
154 .build();
155
156 assert_eq!(
157 ctx.start_path(),
158 Some(std::path::Path::new("/tmp/heddle-verbs-context-test"))
159 );
160 assert_eq!(ctx.principal_fallback(), Some(("Luke", "luke@example.com")));
161 assert!(ctx.hosted_account_unclaimed());
162 assert_eq!(
163 ctx.worktree_status_options().fsmonitor.mode,
164 FsMonitorMode::Watchman
165 );
166 }
167}