cli/scriptengine/
rsscript.rs

1//! # rsscript
2//!
3//! Compiles and runs rust code.
4//!
5
6#[cfg(test)]
7#[path = "rsscript_test.rs"]
8mod rsscript_test;
9
10use crate::command;
11use crate::error::CargoMakeError;
12use crate::installer::{cargo_plugin_installer, crate_installer};
13use crate::scriptengine::script_utils::create_persisted_script_file;
14use crate::types::{InstallCrateInfo, TestArg};
15
16#[derive(PartialEq, Debug)]
17enum ScriptRunner {
18    RustScript,
19    CargoScript,
20    CargoPlay,
21}
22
23fn get_script_runner() -> ScriptRunner {
24    let provider = envmnt::get_or("CARGO_MAKE_RUST_SCRIPT_PROVIDER", "rust-script");
25
26    match provider.as_str() {
27        "rust-script" => ScriptRunner::RustScript,
28        "cargo-script" => ScriptRunner::CargoScript,
29        "cargo-play" => ScriptRunner::CargoPlay,
30        _ => ScriptRunner::RustScript,
31    }
32}
33
34fn install_crate(provider: &ScriptRunner) -> Result<(), CargoMakeError> {
35    // install dependencies
36    match provider {
37        ScriptRunner::RustScript => {
38            let info = InstallCrateInfo {
39                crate_name: "rust-script".to_string(),
40                rustup_component_name: None,
41                binary: "rust-script".to_string(),
42                test_arg: TestArg {
43                    inner: vec!["--version".to_string()],
44                },
45                min_version: None,
46                version: None,
47                install_command: None,
48                force: None,
49            };
50
51            crate_installer::install(&None, &info, &None, false)?;
52        }
53        ScriptRunner::CargoScript => cargo_plugin_installer::install_crate(
54            &None,
55            Some("script"),
56            "cargo-script",
57            &None,
58            true,
59            &None,
60            &None,
61            &None,
62        )?,
63        ScriptRunner::CargoPlay => cargo_plugin_installer::install_crate(
64            &None,
65            Some("play"),
66            "cargo-play",
67            &None,
68            true,
69            &None,
70            &None,
71            &None,
72        )?,
73    };
74    Ok(())
75}
76
77fn create_rust_file(rust_script: &Vec<String>) -> Result<String, CargoMakeError> {
78    create_persisted_script_file(rust_script, "rs")
79}
80
81fn run_file(
82    file: &str,
83    runner_arguments: Option<Vec<String>>,
84    cli_arguments: &Vec<String>,
85    provider: &ScriptRunner,
86) -> Result<bool, CargoMakeError> {
87    let (use_cargo, command) = match provider {
88        ScriptRunner::RustScript => (false, "rust-script"),
89        ScriptRunner::CargoScript => (true, "script"),
90        ScriptRunner::CargoPlay => (true, "play"),
91    };
92
93    let mut args = vec![];
94    if use_cargo {
95        args.push(command.to_string());
96    }
97    if let Some(mut runner_args) = runner_arguments {
98        args.append(&mut runner_args);
99    }
100    args.push(file.to_string());
101    let mut cli_args = cli_arguments.clone();
102    args.append(&mut cli_args);
103
104    let exit_code = if use_cargo {
105        command::run_command("cargo", &Some(args), false)
106    } else {
107        command::run_command(command, &Some(args), false)
108    }?;
109    debug!("Executed rust code, exit code: {}", exit_code);
110
111    Ok(exit_code == 0)
112}
113
114pub(crate) fn execute(
115    rust_script: &Vec<String>,
116    runner_arguments: Option<Vec<String>>,
117    cli_arguments: &Vec<String>,
118    validate: bool,
119) -> Result<bool, CargoMakeError> {
120    let provider = get_script_runner();
121
122    install_crate(&provider)?;
123
124    let file = create_rust_file(rust_script)?;
125
126    let valid = run_file(&file, runner_arguments, &cli_arguments, &provider)?;
127
128    if validate && !valid {
129        error!("Unable to execute rust code.");
130    }
131
132    Ok(valid)
133}