origen/commands/
mod.rs

1pub mod app;
2pub mod env;
3pub mod exec;
4// pub mod fmt;
5pub mod interactive;
6// pub mod mode;
7pub mod new;
8// pub mod proj;
9pub mod rc;
10pub mod save_ref;
11pub mod target;
12pub mod web;
13// pub mod mailer;
14pub mod _prelude;
15pub mod aux_cmds;
16pub mod credentials;
17pub mod develop_origen;
18pub mod eval;
19pub mod generate;
20pub mod plugin;
21pub mod plugins;
22
23use crate::python;
24use crate::strs_to_cli_arr;
25
26use _prelude::{CountArgs, SetArgTrue};
27use indexmap::map::IndexMap;
28use origen::{LOGGER, STATUS}; // clean_mode # O1_MODE_SUPPORT clean_mode function available, or remove
29use std::process::exit;
30
31use crate::framework::extensions::{Extension, ExtensionSource};
32use crate::Plugins;
33use clap::{ArgMatches, Command as App};
34use std::collections::HashMap;
35
36#[macro_export]
37macro_rules! unreachable_invalid_subc {
38    ($subcmd:expr) => {{
39        unreachable!(
40            "Uncaught Invalid Subcommand {} From {}",
41            $subcmd,
42            module_path!()
43        )
44    }};
45}
46
47#[macro_export]
48macro_rules! print_subcmds_available_msg {
49    () => {{
50        println!("Run with 'help' or '-h' to see available subcommands");
51    }};
52}
53
54#[macro_export]
55macro_rules! gen_simple_run_func {
56    ($base_cmd: expr) => {
57        pub(crate) fn run(
58            mut invocation: &clap::ArgMatches,
59            mut cmd_def: &clap::Command,
60            exts: &crate::Extensions,
61            plugins: Option<&crate::Plugins>,
62        ) -> origen::Result<()> {
63            let mut path_pieces: Vec<String> = vec![];
64            cmd_def = cmd_def.find_subcommand($base_cmd).unwrap();
65            if invocation.subcommand_name().is_some() {
66                while invocation.subcommand_name().is_some() {
67                    let n = invocation.subcommand_name().unwrap();
68                    invocation = invocation.subcommand_matches(&n).unwrap();
69                    cmd_def = cmd_def.find_subcommand(n).unwrap();
70                    path_pieces.push(n.to_string());
71                }
72                crate::commands::launch(
73                    Some($base_cmd),
74                    Some(&path_pieces),
75                    invocation,
76                    cmd_def,
77                    exts.get_core_ext(&format!("{}.{}", $base_cmd, path_pieces.join("."))),
78                    plugins,
79                    None,
80                );
81            } else {
82                crate::commands::launch_from_invocation(
83                    invocation,
84                    cmd_def,
85                    exts.get_core_ext($base_cmd),
86                    plugins,
87                );
88            }
89            Ok(())
90        }
91    };
92    () => {
93        crate::gen_simple_run_func!(BASE_CMD);
94    };
95}
96
97pub fn launch_as(
98    cmd: &str,
99    subcmds: Option<&Vec<String>>,
100    invocation: &ArgMatches,
101    cmd_def: &App,
102    cmd_exts: Option<&Vec<Extension>>,
103    plugins: Option<&Plugins>,
104    overrides: Option<IndexMap<String, Option<String>>>,
105) -> () {
106    launch(
107        Some(cmd),
108        subcmds,
109        invocation,
110        cmd_def,
111        cmd_exts,
112        plugins,
113        overrides,
114    )
115}
116pub fn launch_from_invocation(
117    invocation: &ArgMatches,
118    cmd_def: &App,
119    cmd_exts: Option<&Vec<Extension>>,
120    plugins: Option<&Plugins>,
121) {
122    launch(None, None, invocation, cmd_def, cmd_exts, plugins, None)
123}
124
125pub fn launch(
126    base_cmd: Option<&str>,
127    subcmds: Option<&Vec<String>>,
128    invocation: &ArgMatches,
129    cmd_def: &App,
130    cmd_exts: Option<&Vec<Extension>>,
131    plugins: Option<&Plugins>,
132    overrides: Option<IndexMap<String, Option<String>>>,
133) {
134    macro_rules! as_name {
135        ($arg_name:expr) => {{
136            if $arg_name.starts_with(crate::framework::extensions::EXT_BASE_NAME) {
137                $arg_name.splitn(4, ".").last().unwrap()
138            } else {
139                $arg_name
140            }
141        }};
142    }
143
144    let mut args: Vec<String> = vec![];
145    let mut arg_indices: Vec<String> = vec![];
146
147    let mut opt_names = HashMap::new();
148    let mut ext_args: HashMap<&ExtensionSource, Vec<String>> = HashMap::new();
149    let mut ext_arg_indices: HashMap<&ExtensionSource, Vec<String>> = HashMap::new();
150    if let Some(exts) = cmd_exts {
151        for ext in exts {
152            if let Some(opts) = ext.opts.as_ref() {
153                for opt in opts {
154                    opt_names.insert(opt.full_name.as_ref().unwrap().as_str(), &ext.source);
155                    if !ext_args.contains_key(&ext.source) {
156                        ext_args.insert(&ext.source, vec![]);
157                        ext_arg_indices.insert(&ext.source, vec![]);
158                    }
159                }
160            }
161        }
162    }
163
164    let mut targets = None;
165
166    for arg in cmd_def.get_arguments() {
167        let arg_n = arg.get_id().as_str();
168        if arg_n == "verbose" || arg_n == "verbosity_keywords" {
169            continue;
170        }
171
172        if invocation.contains_id(arg_n) {
173            if arg_n == "targets" {
174                targets = Some(invocation.get_many::<String>(arg_n).unwrap());
175                continue;
176            } else if arg_n == "no_targets" {
177                if *invocation.get_one::<bool>(arg_n).unwrap() {
178                    targets = Some(clap::parser::ValuesRef::default());
179                }
180                continue;
181            } else if arg_n == "mode" {
182                // O1_MODE_SUPPORT
183                todo!("Mode argument is not currently supported!");
184            }
185
186            let arg_str: String;
187            if arg.get_action().takes_values() {
188                let multiple_values = matches!(arg.get_action(), clap::ArgAction::Append)
189                    || arg
190                        .get_num_args()
191                        .map(|range| range.max_values() > 1)
192                        .unwrap_or(false);
193                if multiple_values {
194                    // Give to Python as an array of string values - prevent windows path strings causing issues (replace \ with /)
195                    let r = invocation
196                        .get_many::<String>(arg_n)
197                        .unwrap()
198                        .map(|x| format!("\"{}\"", x).replace("\\", "/"))
199                        .collect::<Vec<String>>();
200                    arg_str = format!("r'{}': [{}]", as_name!(arg_n), r.join(", "));
201                } else {
202                    // Give to Python a single string value
203                    arg_str = format!(
204                        "r'{}': r'{}'",
205                        as_name!(arg_n),
206                        invocation.get_one::<String>(arg_n).unwrap()
207                    );
208                }
209            } else {
210                match arg.get_action() {
211                    SetArgTrue => {
212                        if *(invocation.get_one::<bool>(arg_n).unwrap()) {
213                            arg_str = format!("r'{}': True", as_name!(arg_n));
214                        } else {
215                            continue;
216                        }
217                    }
218                    CountArgs => {
219                        let count = *(invocation.get_one::<u8>(arg_n).unwrap());
220                        if count > 0 {
221                            arg_str = format!("r'{}': {}", as_name!(arg_n), count);
222                        } else {
223                            continue;
224                        }
225                    }
226                    _ => {
227                        log_error!(
228                            "Unsupported action '{:#?}' for arg '{}'",
229                            arg.get_action(),
230                            as_name!(arg_n)
231                        ); //arg_str = format!("r'{}': True", arg_n)
232                        exit(1);
233                    }
234                }
235            }
236            let indices_str = format!(
237                "r'{}': [{}]",
238                as_name!(arg_n),
239                invocation
240                    .indices_of(arg_n)
241                    .unwrap()
242                    .map(|i| i.to_string())
243                    .collect::<Vec<String>>()
244                    .join(", ")
245            );
246            if let Some(ext_src) = opt_names.get(arg_n) {
247                ext_args.get_mut(ext_src).unwrap().push(arg_str);
248                ext_arg_indices.get_mut(ext_src).unwrap().push(indices_str);
249            } else {
250                args.push(arg_str);
251                arg_indices.push(indices_str);
252            }
253        }
254    }
255
256    let mut cmd = format!(
257        "from origen.boot import run_cmd; run_cmd('{}'",
258        base_cmd.unwrap_or_else(|| cmd_def.get_name())
259    );
260    if let Some(subs) = subcmds.as_ref() {
261        cmd += &format!(
262            ", subcmds=[{}]",
263            subs.iter()
264                .map(|s| format!("r'{}'", s))
265                .collect::<Vec<String>>()
266                .join(", ")
267        );
268    }
269    cmd += &format!(
270        ", args={{{}}}, arg_indices={{{}}}",
271        args.join(", "),
272        arg_indices.join(", ")
273    );
274
275    let mut app_ext_str = "".to_string();
276    let mut pl_ext_str = "".to_string();
277    let mut aux_ext_str = "".to_string();
278    let mut app_ext_indices_str = "".to_string();
279    let mut pl_ext_indices_str = "".to_string();
280    let mut aux_ext_indices_str = "".to_string();
281    if !ext_args.is_empty() {
282        for ext in ext_args {
283            match ext.0 {
284                ExtensionSource::App => {
285                    app_ext_str = ext.1.join(", ");
286                    app_ext_indices_str = ext_arg_indices[ext.0].join(", ");
287                }
288                ExtensionSource::Plugin(ref pl_name) => {
289                    pl_ext_str += &format!(", '{}': {{{}}}", pl_name, ext.1.join(", "));
290                    pl_ext_indices_str +=
291                        &format!(", '{}': {{{}}}", pl_name, ext_arg_indices[ext.0].join(", "));
292                }
293                ExtensionSource::Aux(ref ns, _) => {
294                    aux_ext_str += &format!(", '{}': {{{}}}", ns, ext.1.join(", "));
295                    aux_ext_indices_str +=
296                        &format!(", '{}': {{{}}}", ns, ext_arg_indices[ext.0].join(", "));
297                }
298            }
299        }
300        if !pl_ext_str.is_empty() {
301            pl_ext_str = pl_ext_str[2..].to_string();
302            pl_ext_indices_str = pl_ext_indices_str[2..].to_string();
303        }
304        if !aux_ext_str.is_empty() {
305            aux_ext_str = aux_ext_str[2..].to_string();
306            aux_ext_indices_str = aux_ext_indices_str[2..].to_string();
307        }
308    }
309    cmd += &format!(
310        concat!(
311            ", ext_args={{'app': {{{}}}, 'plugin': {{{}}}, 'aux': {{{}}}}}",
312            ", ext_arg_indices={{'app': {{{}}}, 'plugin': {{{}}}, 'aux': {{{}}}}}"
313        ),
314        app_ext_str,
315        pl_ext_str,
316        aux_ext_str,
317        app_ext_indices_str,
318        pl_ext_indices_str,
319        aux_ext_indices_str,
320    );
321
322    if let Some(exts) = cmd_exts {
323        let mut ext_setups: Vec<String> = vec![];
324        for ext in exts {
325            let mut ext_setup = "{".to_string();
326            match ext.source {
327                ExtensionSource::App => {
328                    ext_setup += &format!(
329                        "'source': 'app', 'root': r'{}', 'name': None",
330                        origen::app()
331                            .unwrap()
332                            .root
333                            .join(format!(
334                                "{}/commands/extensions/",
335                                STATUS.app.as_ref().unwrap().name()
336                            ))
337                            .display()
338                    );
339                }
340                ExtensionSource::Plugin(ref pl_name) => {
341                    ext_setup += &format!(
342                        "'root': r'{}', 'name': r'{}', 'source': 'plugin'",
343                        plugins
344                            .unwrap()
345                            .plugins
346                            .get(pl_name)
347                            .unwrap()
348                            .root
349                            .as_path()
350                            .join("commands/extensions/")
351                            .display(),
352                        pl_name,
353                    );
354                }
355                ExtensionSource::Aux(ref ns, ref path) => {
356                    ext_setup += &format!(
357                        "'root': r'{}', 'name': r'{}', 'source': 'aux'",
358                        path.display(),
359                        ns,
360                    );
361                }
362            }
363            ext_setup += "}";
364            ext_setups.push(ext_setup);
365        }
366        cmd += &format!(", extensions=[{}]", ext_setups.join(", "));
367    }
368
369    if let Some(pls) = plugins {
370        cmd += &format!(
371            ", plugins={{{}}}",
372            pls.plugins
373                .iter()
374                .map(|(n, pl)| format!("'{}': {{'root': r'{}'}}", n, pl.root.display()))
375                .collect::<Vec<String>>()
376                .join(", ")
377        );
378    }
379
380    if let Some(top_overrides) = overrides {
381        for (name, val) in top_overrides.iter() {
382            if let Some(v) = val {
383                cmd += &format!(", {}={}", name, v);
384            }
385        }
386    }
387
388    if let Some(targs) = targets {
389        if targs.clone().count() == 0 {
390            cmd += ", targets=False"
391        } else {
392            cmd += &format!(", {}", strs_to_cli_arr!("targets", targs));
393        }
394    }
395    cmd += &format!(", verbosity={}", LOGGER.verbosity());
396    cmd += &format!(
397        ", {}",
398        strs_to_cli_arr!("verbosity_keywords", origen::LOGGER.data().keywords.iter())
399    );
400    cmd += ");";
401
402    log_debug!("Launching Python: '{}'", &cmd);
403
404    match python::run(&cmd) {
405        Err(e) => {
406            log_error!("{}", &e);
407            exit(1);
408        }
409        Ok(exit_status) => {
410            if exit_status.success() {
411                exit(0);
412            } else {
413                exit(exit_status.code().unwrap_or(1));
414            }
415        }
416    }
417}