rusty_cli/
command_handler.rs

1use std::collections::HashMap;
2use crate::commands::command::{Callback, Command};
3use crate::commands::help_command::HelpCommand;
4use crate::flags::flag::Flag;
5use crate::flags::flag_parser::FlagParser;
6use crate::meta_data::ApplicationMetaData;
7use crate::option_resolver::clone_meta_data_option;
8
9pub struct CommandHandlerArguments {
10    /// All commands that can be executed by the cli
11    pub commands: Vec<Command>,
12    /// The callback that is executed of no argument is provided
13    /// If this is None, the help command will be executed
14    pub default_no_argument_callback: Option<Callback>,
15    /// All flags that are provided by the cli
16    pub flags: Vec<Flag>
17}
18
19#[derive(Clone)]
20pub(crate) struct CommandHandler {
21    commands: Vec<Command>,
22    command_args: Vec<String>,
23    no_argument_callback: Option<Callback>,
24    meta_data: Option<ApplicationMetaData>,
25    flags: Vec<Flag>
26}
27
28impl CommandHandler {
29    /// Creates a new command handler that can handle
30    /// the command line input by default
31    pub fn new() -> CommandHandler {
32        CommandHandler {
33            commands: vec![],
34            command_args: vec![],
35            no_argument_callback: None,
36            meta_data: None,
37            flags: vec![]
38        }
39    }
40
41    /// Sets the meta data of the application into the command handler
42    pub fn set_meta_data(&mut self, meta_data: Option<ApplicationMetaData>) {
43        self.meta_data = meta_data;
44    }
45
46    /// Sets the commands and the mappings
47    /// to the executor classes
48    pub fn set_args(&mut self, config: CommandHandlerArguments) {
49        self.commands = config.commands.clone();
50        self.command_args = config.commands.into_iter().map(|x|x.caller_arg.clone()).collect::<Vec<String>>();
51        self.no_argument_callback = config.default_no_argument_callback;
52        self.flags = config.flags;
53    }
54
55    /// Executes the command itself
56    /// If no command is provided, the internal help command will
57    /// be used for providing data to the end user
58    pub fn execute_command(&mut self) {
59        let mut arguments= std::env::args();
60        let is_argument_provided = arguments.len() > 0;
61        if !is_argument_provided {
62            HelpCommand::new(self.commands.clone(), clone_meta_data_option(&self.meta_data)).execute();
63            return;
64        }
65
66        let command_argument = arguments.nth(1);
67        if command_argument.is_none() {
68            if self.no_argument_callback.is_none() {
69                HelpCommand::new(self.commands.clone(), clone_meta_data_option(&self.meta_data)).execute();
70            } else {
71                (self.no_argument_callback.unwrap())(HashMap::new());
72            }
73            return;
74        }
75        let arg = command_argument.as_ref().unwrap().to_string();
76        if !self.command_args.contains(&arg.clone()) {
77            HelpCommand::new(self.commands.clone(), clone_meta_data_option(&self.meta_data)).execute();
78            return;
79        }
80        for command in &self.commands {
81            if command.caller_arg == arg {
82                let parsed_flags = FlagParser::new(self.flags.clone()).parse_flags();
83                if parsed_flags.is_some() {
84                    (command.executor)(parsed_flags.unwrap());
85                } else {
86                    // TODO: Log flag error
87                }
88                break;
89            }
90        }
91    }
92
93}