origen/framework/
app_cmds.rs

1use super::build_commands;
2use crate::commands::_prelude::*;
3use indexmap::IndexMap;
4use origen::core::application::Application;
5use origen::{Result, STATUS};
6use std::fs;
7use std::path::PathBuf;
8
9use super::{Command, CommandTOML, CommandsToml, Extensions};
10
11pub const APP_COMMANDS: [&'static str; 2] = [crate::commands::app::BASE_CMD, "commands"];
12
13pub struct AppCmds {
14    pub root: PathBuf,
15    pub top_commands: Vec<String>,
16    pub commands: IndexMap<String, Command>,
17}
18
19impl AppCmds {
20    fn _add_cmd(
21        slf: &mut Self,
22        current_path: String,
23        current_cmd: &mut CommandTOML,
24        parent_cmd: Option<&Command>,
25    ) -> Result<bool> {
26        if let Some(c) = Command::from_toml_cmd(
27            current_cmd,
28            CmdSrc::App(current_path.to_string()),
29            parent_cmd,
30        )? {
31            if let Some(ref mut sub_cmds) = current_cmd.subcommand {
32                for mut sub in sub_cmds {
33                    Self::_add_cmd(
34                        slf,
35                        format!("{}.{}", current_path, &sub.name),
36                        &mut sub,
37                        Some(&c),
38                    )?;
39                }
40            }
41            slf.commands.insert(current_path.clone(), c);
42            Ok(true)
43        } else {
44            Ok(false)
45        }
46    }
47
48    pub fn new(app: &Application, exts: &mut Extensions) -> Result<Self> {
49        let mut slf = Self {
50            root: app.root.to_owned(),
51            top_commands: vec![],
52            commands: IndexMap::new(),
53        };
54
55        for commands_toml in app.config().cmd_paths() {
56            let content = match fs::read_to_string(&commands_toml) {
57                Ok(x) => x,
58                Err(e) => {
59                    bail!("{}", e);
60                }
61            };
62
63            let command_config: CommandsToml = match toml::from_str(&content) {
64                Ok(x) => x,
65                Err(e) => {
66                    log_error!(
67                        "Malformed Commands TOML '{}': {}",
68                        &commands_toml.display(),
69                        e
70                    );
71                    continue;
72                }
73            };
74            // FEATURE: help on cmd nspace (app) error on help given?
75            // slf.help = command_config.help.to_owned();
76            // Help for the app-cmd namespace is not supported. Origen provides the help message.
77            // Display a warning saying this will have not effect
78            // if command_config.help.is_some() {
79            //     log_warning!("Custom help messages from app commands are not supported and will be ignored (from '{}')", commands_toml.display())
80            // }
81
82            if let Some(commands) = command_config.command {
83                for mut cmd in commands {
84                    if Self::_add_cmd(&mut slf, cmd.name.to_owned(), &mut cmd, None)? {
85                        slf.top_commands.push(cmd.name.to_owned());
86                    }
87                }
88            }
89
90            if let Some(extensions) = command_config.extension {
91                for ext in extensions {
92                    match exts.add_from_app_toml(ext) {
93                        Ok(_) => {}
94                        Err(e) => log_error!(
95                            "Failed to add extensions from application from '{}': {}",
96                            &commands_toml.display(),
97                            e
98                        ),
99                    }
100                }
101            }
102        }
103        Ok(slf)
104    }
105
106    pub fn cmds_root(&self) -> Result<PathBuf> {
107        let mut r = self.root.to_owned();
108        r.push(STATUS.app.as_ref().unwrap().name());
109        r.push("commands");
110        Ok(r)
111    }
112}
113
114pub(crate) fn add_helps(helps: &mut CmdHelps, app_cmds: &AppCmds) {
115    helps
116        .add_core_sub_cmd(&APP_COMMANDS)
117        .set_help_msg("Interface with commands added by the application")
118        .set_as_not_extendable();
119    for (n, c) in app_cmds.commands.iter() {
120        helps.add_app_cmd(n).set_help_msg(&c.help);
121    }
122}
123
124pub(crate) fn add_commands<'a>(
125    app: App,
126    helps: &'a CmdHelps,
127    app_commands: &'a AppCmds,
128    exts: &'a Extensions,
129) -> Result<App> {
130    let mut app_cmds_cmd = helps
131        .core_subc(&APP_COMMANDS)
132        .visible_alias("cmds")
133        .arg_required_else_help(true);
134
135    for top_cmd_name in app_commands.top_commands.iter() {
136        app_cmds_cmd = app_cmds_cmd.subcommand(build_commands(
137            &app_commands.commands.get(top_cmd_name).unwrap(),
138            &|cmd, app, opt_cache| exts.apply_to_app_cmd(cmd, app, opt_cache),
139            &|cmd| app_commands.commands.get(cmd).unwrap(),
140            &|cmd, app| helps.apply_helps(&CmdSrc::App(cmd.to_string()), app),
141        ));
142    }
143    Ok(app.subcommand(app_cmds_cmd))
144}