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