mod bash;
mod cmd_exe;
use std::path::Path;
use rattler_conda_types::Platform;
use rattler_shell::shell::{Shell, ShellEnum};
pub(crate) trait NativeShellRunner: Send + Sync {
fn shell(&self) -> ShellEnum;
fn default_interpreter(&self) -> &'static str;
fn preamble(&self, activation_script_path: &Path) -> String;
fn command_to_run_script<'a>(&self, build_script_path: &'a str) -> Vec<&'a str>;
fn replacements_template(&self) -> &'static str;
fn supports_sandbox(&self) -> bool {
true
}
fn debug_info(&self, work_dir: &Path, run_prefix: &Path, build_prefix: Option<&Path>)
-> String;
}
pub(crate) fn native_runner(platform: Platform) -> Box<dyn NativeShellRunner> {
if platform.is_windows() {
Box::new(cmd_exe::CmdExeNativeRunner)
} else {
Box::new(bash::BashNativeRunner)
}
}
pub(crate) fn write_shell_script(
shell: ShellEnum,
script: &str,
) -> Result<Vec<u8>, std::io::Error> {
let mut bytes = Vec::new();
shell.write_script(&mut bytes, script)?;
Ok(bytes)
}
pub(crate) fn quote_arg(shell: &ShellEnum, arg: &str) -> String {
if !arg.is_empty() && !arg.chars().any(char::is_whitespace) {
return arg.to_string();
}
match shell {
ShellEnum::CmdExe(_) => format!("\"{arg}\""),
_ => format!("'{}'", arg.replace('\'', r"'\''")),
}
}
#[cfg(test)]
mod tests {
use super::{native_runner, quote_arg};
use rattler_conda_types::Platform;
use rattler_shell::shell::{self, Shell};
#[test]
fn native_runner_follows_the_platform() {
assert_eq!(native_runner(Platform::Win64).shell().extension(), "bat");
assert_eq!(native_runner(Platform::Linux64).shell().extension(), "sh");
assert_eq!(native_runner(Platform::OsxArm64).shell().extension(), "sh");
assert_eq!(native_runner(Platform::Win64).default_interpreter(), "cmd");
assert_eq!(
native_runner(Platform::Linux64).default_interpreter(),
"bash"
);
}
#[test]
fn quotes_only_when_needed() {
let bash = shell::Bash::default().into();
assert_eq!(quote_arg(&bash, "-NoLogo"), "-NoLogo");
assert_eq!(quote_arg(&bash, "/usr/bin/python"), "/usr/bin/python");
assert_eq!(
quote_arg(&bash, "/opt/my tools/node"),
"'/opt/my tools/node'"
);
assert_eq!(quote_arg(&bash, "a'b c"), "'a'\\''b c'");
}
#[test]
fn quotes_for_cmd_with_double_quotes() {
let cmd = shell::CmdExe.into();
assert_eq!(quote_arg(&cmd, "/d"), "/d");
assert_eq!(
quote_arg(&cmd, r"C:\Program Files\nodejs\node.exe"),
"\"C:\\Program Files\\nodejs\\node.exe\""
);
}
}