1use std::cell::RefCell;
7use std::collections::HashMap;
8use std::path::PathBuf;
9use std::time::Duration;
10
11#[derive(Debug, Clone, Default)]
13pub struct BuildContext {
14 pub success: bool,
16 pub duration: Duration,
18 pub warnings: Vec<String>,
20 pub errors: Vec<String>,
22}
23
24#[derive(Debug, Clone, Default)]
26pub struct TestContext {
27 pub passed: bool,
29 pub passed_count: usize,
31 pub failed_count: usize,
33 pub skipped_count: usize,
35 pub duration: Duration,
37}
38
39#[derive(Debug, Clone)]
41pub struct PluginContext {
42 pub project_root: PathBuf,
44
45 pub project_name: String,
47
48 pub ghc_version: Option<String>,
50
51 pub cabal_file: Option<PathBuf>,
53
54 pub build: Option<BuildContext>,
56
57 pub test: Option<TestContext>,
59
60 pub env_vars: HashMap<String, String>,
62
63 pub verbose: bool,
65}
66
67impl PluginContext {
68 pub fn new(project_root: PathBuf, project_name: String) -> Self {
70 PluginContext {
71 project_root,
72 project_name,
73 ghc_version: None,
74 cabal_file: None,
75 build: None,
76 test: None,
77 env_vars: HashMap::new(),
78 verbose: false,
79 }
80 }
81
82 pub fn with_ghc_version(mut self, version: impl Into<String>) -> Self {
84 self.ghc_version = Some(version.into());
85 self
86 }
87
88 pub fn with_cabal_file(mut self, path: impl Into<PathBuf>) -> Self {
90 self.cabal_file = Some(path.into());
91 self
92 }
93
94 pub fn with_build_context(mut self, build: BuildContext) -> Self {
96 self.build = Some(build);
97 self
98 }
99
100 pub fn with_test_context(mut self, test: TestContext) -> Self {
102 self.test = Some(test);
103 self
104 }
105
106 pub fn with_verbose(mut self, verbose: bool) -> Self {
108 self.verbose = verbose;
109 self
110 }
111
112 pub fn set_env(&mut self, key: impl Into<String>, value: impl Into<String>) {
114 self.env_vars.insert(key.into(), value.into());
115 }
116}
117
118thread_local! {
121 static CONTEXT: RefCell<Option<PluginContext>> = const { RefCell::new(None) };
122}
123
124pub fn set_context(ctx: PluginContext) {
126 CONTEXT.with(|c| {
127 *c.borrow_mut() = Some(ctx);
128 });
129}
130
131pub fn clear_context() {
133 CONTEXT.with(|c| {
134 *c.borrow_mut() = None;
135 });
136}
137
138pub fn with_context<F, R>(f: F) -> Option<R>
142where
143 F: FnOnce(&PluginContext) -> R,
144{
145 CONTEXT.with(|c| c.borrow().as_ref().map(f))
146}
147
148pub fn with_context_mut<F, R>(f: F) -> Option<R>
150where
151 F: FnOnce(&mut PluginContext) -> R,
152{
153 CONTEXT.with(|c| c.borrow_mut().as_mut().map(f))
154}
155
156pub struct ContextGuard;
158
159impl ContextGuard {
160 pub fn new(ctx: PluginContext) -> Self {
162 set_context(ctx);
163 ContextGuard
164 }
165}
166
167impl Drop for ContextGuard {
168 fn drop(&mut self) {
169 clear_context();
170 }
171}