1use std::mem;
2use crate::constants::HELP_KEYS;
3use crate::runners::helper::make_node_help;
4use crate::runners::main_executor;
5use crate::utils::print_n_exit;
6
7use mddd_traits::IRunner;
8
9pub struct NodeRunner {
10 description: String,
11 default_params: Vec<String>,
12 runners: Vec<(String, Box<dyn IRunner>)>,
13}
14
15impl NodeRunner {
16 pub fn new(description: impl ToString) -> Self {
17 Self {
18 description: description.to_string(),
19 default_params: Default::default(),
20 runners: Vec::new(),
21 }
22 }
23
24 pub fn add(mut self, cmd: impl ToString, runner: impl IRunner + 'static) -> Self {
25 self.runners.push((cmd.to_string(), Box::new(runner)));
26 self
27 }
28
29 pub fn add_box(mut self, cmd: impl ToString, runner: Box<dyn IRunner>) -> Self {
30 self.runners.push((cmd.to_string(), runner));
31 self
32 }
33
34 pub fn set_default_params<T: ToString>(mut self, params: &[T]) -> Self {
35 self.default_params = params.iter()
36 .map(|p|p.to_string())
37 .collect();
38 self
39 }
40
41 pub fn run(self) {
42 main_executor::run(self)
43 }
44
45 fn execute_command(&mut self, prefix: &str, cmd: &str, args: &[&str]) {
46 let found = self.runners.iter_mut().find(|(key, _)| key == cmd);
47 let child = match found {
48 Some((_, val)) => val,
49 None => print_n_exit(&format!("Invalid command: {}", cmd)),
50 };
51 let prefix = format!("{} {}", prefix, cmd);
52 child.execute(&prefix, args)
53 }
54
55 fn execute_without_args(&mut self, prefix: &str) {
56 if self.default_params.is_empty() {
57 self.execute_with_args(prefix, &[HELP_KEYS[0]])
58 } else {
59 let args = mem::take(&mut self.default_params);
60 let ptr_args = args.iter()
61 .map(|s| -> &str {s})
62 .collect::<Vec<_>>();
63 self.execute_with_args(prefix, &ptr_args)
64 }
65 }
66
67 fn execute_with_args(&mut self, prefix: &str, args: &[&str]) {
68 if HELP_KEYS.contains(&args[0]) {
69 let help = make_node_help(prefix, &self.short_description(), &self.runners);
70 println!("{}", help);
71 } else {
72 self.execute_command(prefix, args[0], &args[1..])
73 }
74 }
75}
76
77impl IRunner for NodeRunner {
78 fn short_description(&self) -> String {
79 self.description.clone()
80 }
81
82 fn execute(&mut self, prefix: &str, args: &[&str]) {
83 if args.is_empty() {
84 self.execute_without_args(prefix)
85 } else {
86 self.execute_with_args(prefix, args)
87 }
88 }
89}