mk_lib/schema/
task_context.rs

1use std::sync::Arc;
2
3use hashbrown::HashMap;
4use indicatif::{
5  MultiProgress,
6  ProgressDrawTarget,
7};
8
9use crate::defaults::{
10  default_ignore_errors,
11  default_shell,
12  default_verbose,
13};
14
15use super::{
16  ExecutionStack,
17  Shell,
18  TaskRoot,
19};
20
21/// Used to pass information to tasks
22/// This use arc to allow for sharing of data between tasks
23/// and allow parallel runs of tasks
24#[derive(Clone)]
25pub struct TaskContext {
26  pub task_root: Arc<TaskRoot>,
27  pub execution_stack: ExecutionStack,
28  pub multi: Arc<MultiProgress>,
29  pub env_vars: HashMap<String, String>,
30  pub shell: Option<Arc<Shell>>,
31  pub ignore_errors: Option<bool>,
32  pub verbose: Option<bool>,
33  pub is_nested: bool,
34}
35
36impl TaskContext {
37  pub fn empty() -> Self {
38    let mp = MultiProgress::with_draw_target(ProgressDrawTarget::hidden());
39    Self {
40      task_root: Arc::new(TaskRoot::default()),
41      execution_stack: ExecutionStack::default(),
42      multi: Arc::new(mp),
43      env_vars: HashMap::new(),
44      shell: None,
45      ignore_errors: None,
46      verbose: None,
47      is_nested: false,
48    }
49  }
50
51  pub fn empty_with_root(task_root: Arc<TaskRoot>) -> Self {
52    let mp = MultiProgress::with_draw_target(ProgressDrawTarget::hidden());
53    Self {
54      task_root: task_root.clone(),
55      execution_stack: ExecutionStack::default(),
56      multi: Arc::new(mp),
57      env_vars: HashMap::new(),
58      shell: None,
59      ignore_errors: None,
60      verbose: None,
61      is_nested: false,
62    }
63  }
64
65  pub fn new(task_root: Arc<TaskRoot>, execution_stack: ExecutionStack) -> Self {
66    Self {
67      task_root: task_root.clone(),
68      execution_stack,
69      multi: Arc::new(MultiProgress::new()),
70      env_vars: HashMap::new(),
71      shell: None,
72      ignore_errors: None,
73      verbose: None,
74      is_nested: false,
75    }
76  }
77
78  pub fn from_context(context: &TaskContext) -> Self {
79    Self {
80      task_root: context.task_root.clone(),
81      execution_stack: context.execution_stack.clone(),
82      multi: context.multi.clone(),
83      env_vars: context.env_vars.clone(),
84      shell: context.shell.clone(),
85      ignore_errors: context.ignore_errors,
86      verbose: context.verbose,
87      is_nested: true,
88    }
89  }
90
91  pub fn from_context_with_args(context: &TaskContext, ignore_errors: bool, verbose: bool) -> Self {
92    Self {
93      task_root: context.task_root.clone(),
94      execution_stack: context.execution_stack.clone(),
95      multi: context.multi.clone(),
96      env_vars: context.env_vars.clone(),
97      shell: context.shell.clone(),
98      ignore_errors: Some(ignore_errors),
99      verbose: Some(verbose),
100      is_nested: true,
101    }
102  }
103
104  pub fn extend_env_vars<I>(&mut self, iter: I)
105  where
106    I: IntoIterator<Item = (String, String)>,
107  {
108    self.env_vars.extend(iter);
109  }
110
111  pub fn set_shell(&mut self, shell: &Shell) {
112    let shell = Arc::new(Shell::from_shell(shell));
113    self.shell = Some(shell);
114  }
115
116  pub fn set_ignore_errors(&mut self, ignore_errors: bool) {
117    self.ignore_errors = Some(ignore_errors);
118  }
119
120  pub fn set_verbose(&mut self, verbose: bool) {
121    self.verbose = Some(verbose);
122  }
123
124  pub fn shell(&self) -> Arc<Shell> {
125    self.shell.clone().unwrap_or_else(|| Arc::new(default_shell()))
126  }
127
128  pub fn ignore_errors(&self) -> bool {
129    self.ignore_errors.unwrap_or(default_ignore_errors())
130  }
131
132  pub fn verbose(&self) -> bool {
133    self.verbose.unwrap_or(default_verbose())
134  }
135}
136
137#[cfg(test)]
138mod test {
139  use super::*;
140
141  #[test]
142  fn test_task_context_1() -> anyhow::Result<()> {
143    {
144      let context = TaskContext::empty();
145      assert_eq!(context.shell().cmd(), "sh".to_string());
146      assert!(!context.ignore_errors());
147      assert!(context.verbose());
148    }
149
150    Ok(())
151  }
152
153  #[test]
154  fn test_task_context_2() -> anyhow::Result<()> {
155    {
156      let mut context = TaskContext::empty();
157      context.set_shell(&Shell::String("bash".to_string()));
158      assert_eq!(context.shell().cmd(), "bash".to_string());
159    }
160
161    Ok(())
162  }
163
164  #[test]
165  fn test_task_context_3() -> anyhow::Result<()> {
166    {
167      let mut context = TaskContext::empty();
168      context.extend_env_vars(vec![("key".to_string(), "value".to_string())]);
169      assert_eq!(context.env_vars.get("key"), Some(&"value".to_string()));
170    }
171
172    Ok(())
173  }
174
175  #[test]
176  fn test_task_context_4() -> anyhow::Result<()> {
177    {
178      let mut context = TaskContext::empty();
179      context.set_ignore_errors(true);
180      assert!(context.ignore_errors());
181    }
182
183    Ok(())
184  }
185
186  #[test]
187  fn test_task_context_5() -> anyhow::Result<()> {
188    {
189      let mut context = TaskContext::empty();
190      context.set_verbose(true);
191      assert!(context.verbose());
192    }
193
194    Ok(())
195  }
196}