1
use std::sync::Arc;
2

            
3
use hashbrown::HashMap;
4
use indicatif::{
5
  MultiProgress,
6
  ProgressDrawTarget,
7
};
8

            
9
use crate::defaults::{
10
  default_ignore_errors,
11
  default_shell,
12
  default_verbose,
13
};
14

            
15
use super::{
16
  ExecutionStack,
17
  TaskRoot,
18
};
19

            
20
pub struct TaskContext {
21
  pub task_root: Arc<TaskRoot>,
22
  pub execution_stack: ExecutionStack,
23
  pub multi: Arc<MultiProgress>,
24
  pub env_vars: HashMap<String, String>,
25
  pub shell: Option<String>,
26
  pub ignore_errors: Option<bool>,
27
  pub verbose: Option<bool>,
28
  pub is_nested: bool,
29
}
30

            
31
impl TaskContext {
32
100
  pub fn empty() -> Self {
33
100
    let mp = MultiProgress::with_draw_target(ProgressDrawTarget::hidden());
34
100
    Self {
35
100
      task_root: Arc::new(TaskRoot::default()),
36
100
      execution_stack: ExecutionStack::default(),
37
100
      multi: Arc::new(mp),
38
100
      env_vars: HashMap::new(),
39
100
      shell: None,
40
100
      ignore_errors: None,
41
100
      verbose: None,
42
100
      is_nested: false,
43
100
    }
44
100
  }
45

            
46
20
  pub fn empty_with_root(task_root: Arc<TaskRoot>) -> Self {
47
20
    let mp = MultiProgress::with_draw_target(ProgressDrawTarget::hidden());
48
20
    Self {
49
20
      task_root: task_root.clone(),
50
20
      execution_stack: ExecutionStack::default(),
51
20
      multi: Arc::new(mp),
52
20
      env_vars: HashMap::new(),
53
20
      shell: None,
54
20
      ignore_errors: None,
55
20
      verbose: None,
56
20
      is_nested: false,
57
20
    }
58
20
  }
59

            
60
93
  pub fn new(task_root: Arc<TaskRoot>, execution_stack: ExecutionStack) -> Self {
61
93
    Self {
62
93
      task_root: task_root.clone(),
63
93
      execution_stack,
64
93
      multi: Arc::new(MultiProgress::new()),
65
93
      env_vars: HashMap::new(),
66
93
      shell: None,
67
93
      ignore_errors: None,
68
93
      verbose: None,
69
93
      is_nested: false,
70
93
    }
71
93
  }
72

            
73
20
  pub fn from_context(context: &TaskContext) -> Self {
74
20
    Self {
75
20
      task_root: context.task_root.clone(),
76
20
      execution_stack: context.execution_stack.clone(),
77
20
      multi: context.multi.clone(),
78
20
      env_vars: context.env_vars.clone(),
79
20
      shell: context.shell.clone(),
80
20
      ignore_errors: context.ignore_errors,
81
20
      verbose: context.verbose,
82
20
      is_nested: true,
83
20
    }
84
20
  }
85

            
86
  pub fn from_context_with_args(context: &TaskContext, ignore_errors: bool, verbose: bool) -> Self {
87
    Self {
88
      task_root: context.task_root.clone(),
89
      execution_stack: context.execution_stack.clone(),
90
      multi: context.multi.clone(),
91
      env_vars: context.env_vars.clone(),
92
      shell: context.shell.clone(),
93
      ignore_errors: Some(ignore_errors),
94
      verbose: Some(verbose),
95
      is_nested: true,
96
    }
97
  }
98

            
99
246
  pub fn extend_env_vars<I>(&mut self, iter: I)
100
246
  where
101
246
    I: IntoIterator<Item = (String, String)>,
102
246
  {
103
246
    self.env_vars.extend(iter);
104
246
  }
105

            
106
20
  pub fn set_shell(&mut self, shell: &str) {
107
20
    self.shell = Some(shell.to_string());
108
20
  }
109

            
110
20
  pub fn set_ignore_errors(&mut self, ignore_errors: bool) {
111
20
    self.ignore_errors = Some(ignore_errors);
112
20
  }
113

            
114
20
  pub fn set_verbose(&mut self, verbose: bool) {
115
20
    self.verbose = Some(verbose);
116
20
  }
117

            
118
40
  pub fn shell(&self) -> String {
119
40
    self.shell.clone().unwrap_or(default_shell())
120
40
  }
121

            
122
40
  pub fn ignore_errors(&self) -> bool {
123
40
    self.ignore_errors.unwrap_or(default_ignore_errors())
124
40
  }
125

            
126
40
  pub fn verbose(&self) -> bool {
127
40
    self.verbose.unwrap_or(default_verbose())
128
40
  }
129
}
130

            
131
#[cfg(test)]
132
mod test {
133
  use super::*;
134

            
135
  #[test]
136
20
  fn test_task_context_1() -> anyhow::Result<()> {
137
20
    {
138
20
      let context = TaskContext::empty();
139
20
      assert_eq!(context.shell(), "sh");
140
20
      assert!(!context.ignore_errors());
141
20
      assert!(context.verbose());
142
    }
143

            
144
20
    Ok(())
145
20
  }
146

            
147
  #[test]
148
20
  fn test_task_context_2() -> anyhow::Result<()> {
149
20
    {
150
20
      let mut context = TaskContext::empty();
151
20
      context.set_shell("bash");
152
20
      assert_eq!(context.shell(), "bash");
153
    }
154

            
155
20
    Ok(())
156
20
  }
157

            
158
  #[test]
159
20
  fn test_task_context_3() -> anyhow::Result<()> {
160
20
    {
161
20
      let mut context = TaskContext::empty();
162
20
      context.extend_env_vars(vec![("key".to_string(), "value".to_string())]);
163
20
      assert_eq!(context.env_vars.get("key"), Some(&"value".to_string()));
164
    }
165

            
166
20
    Ok(())
167
20
  }
168

            
169
  #[test]
170
20
  fn test_task_context_4() -> anyhow::Result<()> {
171
20
    {
172
20
      let mut context = TaskContext::empty();
173
20
      context.set_ignore_errors(true);
174
20
      assert!(context.ignore_errors());
175
    }
176

            
177
20
    Ok(())
178
20
  }
179

            
180
  #[test]
181
20
  fn test_task_context_5() -> anyhow::Result<()> {
182
20
    {
183
20
      let mut context = TaskContext::empty();
184
20
      context.set_verbose(true);
185
20
      assert!(context.verbose());
186
    }
187

            
188
20
    Ok(())
189
20
  }
190
}