149 lines
4.6 KiB
Rust
149 lines
4.6 KiB
Rust
use crate::resolver::resolve_file;
|
|
use crate::{verify, RunScriptArgs};
|
|
use rust_util::util_cmd;
|
|
use rust_util::util_env::is_env_on;
|
|
use std::fs;
|
|
use std::process::Command;
|
|
|
|
const RUNTIME_DENO: &str = "--runtime-deno";
|
|
const RUNTIME_BUN: &str = "--runtime-bun";
|
|
|
|
pub fn do_run_script(args: &RunScriptArgs) {
|
|
if args.arguments.is_empty() {
|
|
failure_and_exit!("Must assign a script file name");
|
|
}
|
|
debugging!("Run ts args: {:?}", args.arguments);
|
|
|
|
let mut is_runtime_deno = true;
|
|
let (raw_script_file, first_arg) = (|| {
|
|
for (i, arg) in args.arguments.iter().enumerate() {
|
|
if arg == RUNTIME_DENO || arg == RUNTIME_BUN {
|
|
is_runtime_deno = arg == RUNTIME_DENO;
|
|
}
|
|
if !arg.starts_with("--") {
|
|
return (arg, i == 0);
|
|
}
|
|
}
|
|
(&args.arguments[args.arguments.len() - 1], false)
|
|
})();
|
|
let script_file = resolve_file(raw_script_file, args.force_update)
|
|
.unwrap_or_else(|e| failure_and_exit!("Failed to resolve script: {}", e));
|
|
let script_file = &script_file;
|
|
verify::verify_script(script_file, is_env_on("RUNTS_SKIP_VERIFY") || is_env_on("RSV"));
|
|
|
|
let mut cmd = Command::new("/usr/bin/env");
|
|
// #!/usr/bin/env runts -- --allow-env
|
|
// #!/usr/bin/env runts -- [--runtime-deno | --runtime-bun] <args>
|
|
if first_arg {
|
|
let first_line_args = read_first_line_parse_args(script_file);
|
|
debugging!("Runts first line args: {:?}", first_line_args);
|
|
let left_first_line_args = first_line_args
|
|
.iter()
|
|
.skip_while(|arg| *arg != "--" && *arg != "run")
|
|
.skip(1)
|
|
.filter(|arg| {
|
|
if *arg == RUNTIME_DENO || *arg == RUNTIME_BUN {
|
|
is_runtime_deno = *arg == RUNTIME_DENO;
|
|
debugging!(
|
|
"Runts runtime arg: {}, is runtime deno: {}",
|
|
*arg,
|
|
is_runtime_deno
|
|
);
|
|
return false;
|
|
}
|
|
true
|
|
})
|
|
.collect::<Vec<_>>();
|
|
cmd.args(["-S", iff!(is_runtime_deno, "deno", "bun"), "run"]);
|
|
cmd.args(left_first_line_args);
|
|
} else {
|
|
cmd.args(["-S", iff!(is_runtime_deno, "deno", "bun"), "run"]);
|
|
}
|
|
for arg in &args.arguments {
|
|
if arg == RUNTIME_DENO || arg == RUNTIME_BUN {
|
|
continue;
|
|
}
|
|
if arg == raw_script_file { // replace remote file with local file
|
|
cmd.arg(script_file);
|
|
} else {
|
|
cmd.arg(arg);
|
|
}
|
|
}
|
|
|
|
debugging!("Run command: {cmd:?}");
|
|
if let Err(e) = util_cmd::run_command_and_wait(&mut cmd) {
|
|
failure_and_exit!("Run deno: {script_file} failed: {e}");
|
|
}
|
|
}
|
|
|
|
fn read_first_line_parse_args(script_file: &str) -> Vec<String> {
|
|
if let Ok(script_content) = fs::read_to_string(script_file) {
|
|
if let Some(first_line) = script_content.lines().next() {
|
|
if first_line.starts_with("#!") {
|
|
return parse_args_line(&first_line);
|
|
}
|
|
}
|
|
}
|
|
vec![]
|
|
}
|
|
|
|
fn parse_args_line(line: &str) -> Vec<String> {
|
|
let mut args = vec![];
|
|
|
|
let mut ln = String::new();
|
|
let mut in_quota = false;
|
|
let mut single_quota = false;
|
|
let chars = line.chars().collect::<Vec<_>>();
|
|
let mut i = 0;
|
|
while i < chars.len() {
|
|
let c = chars[i];
|
|
if in_quota {
|
|
if (single_quota && c == '\'') || (!single_quota && c == '"') {
|
|
in_quota = false;
|
|
} else if c == '\\' {
|
|
if i + 1 < chars.len() {
|
|
i += 1;
|
|
let nc = chars[i];
|
|
ln.push(nc);
|
|
} else {
|
|
ln.push(c);
|
|
}
|
|
} else {
|
|
ln.push(c);
|
|
}
|
|
} else if c == ' ' || c == '\t' {
|
|
if !ln.is_empty() {
|
|
args.push(ln.clone());
|
|
ln.clear();
|
|
}
|
|
} else if c == '\'' {
|
|
in_quota = true;
|
|
single_quota = true;
|
|
} else if c == '"' {
|
|
in_quota = true;
|
|
single_quota = false;
|
|
} else {
|
|
ln.push(c);
|
|
}
|
|
i += 1;
|
|
}
|
|
if !ln.is_empty() {
|
|
args.push(ln);
|
|
}
|
|
args
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_args_line() {
|
|
assert!(parse_args_line("").is_empty());
|
|
assert_eq!(vec!["a".to_string()], parse_args_line("a"));
|
|
assert_eq!(
|
|
vec!["a".to_string(), "aaaa'bbb".to_string()],
|
|
parse_args_line("a 'aaaa\\'bbb'")
|
|
);
|
|
assert_eq!(
|
|
vec!["--allow-a".to_string(), "--allow-b".to_string()],
|
|
parse_args_line(" --allow-a --allow-b")
|
|
);
|
|
}
|