1.1.8 supports url scripts

This commit is contained in:
2026-02-08 19:31:20 +08:00
parent 41f1eeeb9e
commit edd4cbdc92
7 changed files with 131 additions and 7 deletions

View File

@@ -13,6 +13,7 @@ mod run_ts;
mod template;
mod util;
mod verify;
mod resolver;
#[derive(FromArgs, PartialEq, Debug)]
/// Run script

97
src/resolver.rs Normal file
View File

@@ -0,0 +1,97 @@
use crate::util;
use rust_util::XResult;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
// download from internet if starts with https://
pub fn resolve_file(script_file: &str) -> XResult<String> {
if script_file.starts_with("http://") {
return simple_error!("Insecure script file: {}", script_file);
}
if !script_file.starts_with("https://") {
return Ok(script_file.to_string());
}
let file_sha256 = sha256::digest(script_file);
let file_name = get_file_name(script_file)?;
let cache_file_path = format!(
"{}/.cache/runrs/{}/{}",
util::get_user_home_or_die(),
file_sha256,
file_name
);
debugging!("Cache file: {}", cache_file_path);
if let Ok(metadata) = fs::metadata(&cache_file_path) {
if metadata.is_file() {
debugging!("Found cache file: {}", cache_file_path);
return Ok(cache_file_path);
}
return simple_error!("Cache file is not a file: {}", cache_file_path);
}
// create cache file parent path if not exists
let cache_file_path_path = Path::new(&cache_file_path);
match cache_file_path_path.parent() {
None => return simple_error!("Cache file has no parent: {}", cache_file_path),
Some(cache_file_path_path_parent) => {
if let Err(_) = fs::metadata(cache_file_path_path_parent) {
debugging!(
"Create cache file parent path: {:?}",
cache_file_path_path_parent
);
if let Err(e) = fs::create_dir_all(cache_file_path_path_parent) {
return simple_error!(
"Create cache file parent dir: {:?}, failed: {}",
cache_file_path_path_parent,
e
);
}
}
}
}
// download script file
debugging!("Try get script: {}", script_file);
let get_script_response_result = reqwest::blocking::get(script_file);
debugging!("Get script response: {:#?}", &get_script_response_result);
let get_script_response = match get_script_response_result {
Err(e) => return simple_error!("Get script failed: {}", e),
Ok(response) => response,
};
let get_script_response_status = get_script_response.status().as_u16();
if get_script_response_status == 404 {
return simple_error!("Script not found!");
} else if get_script_response_status != 200 {
return simple_error!("Get script failed: {}", get_script_response_status);
}
let remote_script_content = match get_script_response.text() {
Err(e) => {
return simple_error!("Get script: {} failed: {}", &script_file, e);
}
Ok(remote_script_content) => remote_script_content,
};
// write script file to cache
if let Err(e) = fs::write(&cache_file_path, remote_script_content) {
return simple_error!("Write script: {} failed: {}", cache_file_path, e);
}
if let Err(_) = fs::write(&format!("{}.url", cache_file_path), script_file) {
// JUST IGNORE
}
// change script file permission
debugging!("Write file: {} success", cache_file_path);
match fs::set_permissions(&cache_file_path, PermissionsExt::from_mode(0o755)) {
Err(e) => {
return simple_error!("Chmod script: {} permission failed: {}", cache_file_path, e)
}
Ok(_) => debugging!("Chmod script: {} permission succeed", cache_file_path),
}
Ok(cache_file_path)
}
fn get_file_name(script_file: &str) -> XResult<String> {
match script_file.split("/").last() {
None => simple_error!("Invalid script file: {}", script_file),
Some(file_name) => Ok(file_name.to_string()),
}
}

View File

@@ -1,3 +1,4 @@
use crate::resolver::resolve_file;
use crate::{util, verify, RunScriptArgs};
use rust_util::util_env::is_env_on;
use rust_util::util_os::get_user_home;
@@ -7,6 +8,10 @@ pub fn do_run_script(args: &RunScriptArgs) {
failure_and_exit!("Must assign a script file name");
}
let script_file = &args.arguments[0];
let script_file = resolve_file(script_file)
.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("RUNRS_SKIP_VERIFY"));
let (_, script_sha256) = util::read_file_and_digest(script_file);

View File

@@ -1,3 +1,4 @@
use crate::resolver::resolve_file;
use crate::{verify, RunScriptArgs};
use rust_util::util_cmd;
use rust_util::util_env::is_env_on;
@@ -14,7 +15,7 @@ pub fn do_run_script(args: &RunScriptArgs) {
debugging!("Run ts args: {:?}", args.arguments);
let mut is_runtime_deno = true;
let (script_file, first_arg) = (|| {
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;
@@ -25,6 +26,9 @@ pub fn do_run_script(args: &RunScriptArgs) {
}
(&args.arguments[args.arguments.len() - 1], false)
})();
let script_file = resolve_file(raw_script_file)
.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"));
let mut cmd = Command::new("/usr/bin/env");
@@ -40,7 +44,11 @@ pub fn do_run_script(args: &RunScriptArgs) {
.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);
debugging!(
"Runts runtime arg: {}, is runtime deno: {}",
*arg,
is_runtime_deno
);
return false;
}
true
@@ -55,7 +63,11 @@ pub fn do_run_script(args: &RunScriptArgs) {
if arg == RUNTIME_DENO || arg == RUNTIME_BUN {
continue;
}
cmd.arg(arg);
if arg == raw_script_file { // replace remote file with local file
cmd.arg(script_file);
} else {
cmd.arg(arg);
}
}
debugging!("Run command: {cmd:?}");