This commit is contained in:
2026-02-09 22:27:54 +08:00
parent b41778d0bc
commit 582279b1b8
6 changed files with 96 additions and 16 deletions

2
Cargo.lock generated
View File

@@ -1221,7 +1221,7 @@ dependencies = [
[[package]] [[package]]
name = "runrs" name = "runrs"
version = "1.1.8" version = "1.1.9"
dependencies = [ dependencies = [
"argh", "argh",
"reqwest", "reqwest",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "runrs" name = "runrs"
version = "1.1.8" version = "1.1.9"
edition = "2018" edition = "2018"
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A Tool for Run Rust/TypeScript Scripts" description = "A Tool for Run Rust/TypeScript Scripts"

View File

@@ -31,8 +31,11 @@ struct RunScriptArgs {
#[argh(switch, short = 'i')] #[argh(switch, short = 'i')]
install: bool, install: bool,
/// update listed scripts /// update listed scripts
#[argh(switch)] #[argh(switch, short = 'U')]
update_listed_scripts: bool, update_listed_scripts: bool,
/// force update https script file
#[argh(switch)]
force_update: bool,
/// script repo /// script repo
#[argh(option, short = 'R')] #[argh(option, short = 'R')]
script_repo: Option<String>, script_repo: Option<String>,

View File

@@ -1,10 +1,31 @@
use crate::util; use crate::util;
use rust_util::util_time::get_current_millis;
use rust_util::XResult; use rust_util::XResult;
use serde::{Deserialize, Serialize};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
#[allow(unreachable_code)]
fn get_script_cache_dir() -> &'static str {
#[cfg(feature = "switch-rust-lang")]
{
return "runrs";
}
#[cfg(feature = "switch-ts-lang")]
{
return "runts";
}
failure_and_exit!("Only rust/ts script supported.");
}
#[derive(Debug, Serialize, Deserialize)]
struct HttpsScriptMeta {
url: String,
download_time: u128,
}
// download from internet if starts with https:// // download from internet if starts with https://
pub fn resolve_file(script_file: &str) -> XResult<String> { pub fn resolve_file(script_file: &str, force_update: bool) -> XResult<String> {
if script_file.starts_with("http://") { if script_file.starts_with("http://") {
return simple_error!("Insecure script file: {}", script_file); return simple_error!("Insecure script file: {}", script_file);
} }
@@ -14,23 +35,55 @@ pub fn resolve_file(script_file: &str) -> XResult<String> {
let file_sha256 = sha256::digest(script_file); let file_sha256 = sha256::digest(script_file);
let file_name = get_file_name(script_file)?; let file_name = get_file_name(script_file)?;
let cache_file_path = format!( let cache_file_path = format!(
"{}/.cache/runrs/{}/{}", "{}/.cache/{}/{}/{}",
util::get_user_home_or_die(), util::get_user_home_or_die(),
get_script_cache_dir(),
file_sha256, file_sha256,
file_name file_name
); );
let cache_file_path_url = format!( let cache_file_path_meta = format!(
"{}/.cache/runrs/{}.url", "{}/.cache/{}/{}.meta",
util::get_user_home_or_die(), util::get_user_home_or_die(),
get_script_cache_dir(),
file_sha256 file_sha256
); );
debugging!("Cache file: {}", cache_file_path); let is_script_path_latest_version = script_file.contains("/@latest/");
if let Ok(metadata) = fs::metadata(&cache_file_path) { let cache_file_path_exists = fs::metadata(&cache_file_path).is_ok();
if metadata.is_file() { debugging!(
"Cache file: {}, is latest version: {}, cache file exists: {}",
cache_file_path,
is_script_path_latest_version,
cache_file_path_exists
);
if force_update {
debugging!("Force update is on, skip cache file check");
} else if is_script_path_latest_version {
// force update is not on, and script file is @latest version
if let Ok(cache_file_path_meta_content) = fs::read_to_string(&cache_file_path_meta) {
if let Ok(http_script_meta) =
serde_json::from_str::<HttpsScriptMeta>(&cache_file_path_meta_content)
{
let current_millis = get_current_millis();
debugging!(
"Read from meta: {:?}, current millis: {}",
http_script_meta,
current_millis
);
if current_millis - http_script_meta.download_time < 12 * 60 * 60 * 1000
&& cache_file_path_exists
{
// script file is download in 12 hours
return Ok(cache_file_path);
}
}
}
} else {
// force update is not on, and script is static version, check file existence only
if cache_file_path_exists {
debugging!("Found cache file: {}", cache_file_path); debugging!("Found cache file: {}", cache_file_path);
return Ok(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 // create cache file parent path if not exists
@@ -59,13 +112,31 @@ pub fn resolve_file(script_file: &str) -> XResult<String> {
let get_script_response_result = reqwest::blocking::get(script_file); let get_script_response_result = reqwest::blocking::get(script_file);
debugging!("Get script response: {:#?}", &get_script_response_result); debugging!("Get script response: {:#?}", &get_script_response_result);
let get_script_response = match get_script_response_result { let get_script_response = match get_script_response_result {
Err(e) => return simple_error!("Get script failed: {}", e), Err(e) => {
if cache_file_path_exists {
warning!(
"Get script failed, reuse local cache file: {}",
cache_file_path
);
return Ok(cache_file_path);
}
return simple_error!("Get script failed: {}", e);
}
Ok(response) => response, Ok(response) => response,
}; };
let get_script_response_status = get_script_response.status().as_u16(); let get_script_response_status = get_script_response.status().as_u16();
if get_script_response_status == 404 { if get_script_response_status == 404 {
// when 404 do not reuse local cache file
return simple_error!("Script not found!"); return simple_error!("Script not found!");
} else if get_script_response_status != 200 { } else if get_script_response_status != 200 {
if cache_file_path_exists {
warning!(
"Get script failed, status: {}, reuse local cache file: {}",
get_script_response_status,
cache_file_path
);
return Ok(cache_file_path);
}
return simple_error!("Get script failed: {}", get_script_response_status); return simple_error!("Get script failed: {}", get_script_response_status);
} }
let remote_script_content = match get_script_response.text() { let remote_script_content = match get_script_response.text() {
@@ -78,8 +149,14 @@ pub fn resolve_file(script_file: &str) -> XResult<String> {
if let Err(e) = fs::write(&cache_file_path, remote_script_content) { if let Err(e) = fs::write(&cache_file_path, remote_script_content) {
return simple_error!("Write script: {} failed: {}", cache_file_path, e); return simple_error!("Write script: {} failed: {}", cache_file_path, e);
} }
if let Err(_) = fs::write(&cache_file_path_url, script_file) { let meta = HttpsScriptMeta {
// JUST IGNORE url: script_file.to_string(),
download_time: get_current_millis(),
};
if let Ok(meta_json) = serde_json::to_string_pretty(&meta) {
if let Err(_) = fs::write(&cache_file_path_meta, &meta_json) {
// JUST IGNORE
}
} }
Ok(cache_file_path) Ok(cache_file_path)

View File

@@ -8,7 +8,7 @@ pub fn do_run_script(args: &RunScriptArgs) {
failure_and_exit!("Must assign a script file name"); failure_and_exit!("Must assign a script file name");
} }
let script_file = &args.arguments[0]; let script_file = &args.arguments[0];
let script_file = resolve_file(script_file) let script_file = resolve_file(script_file, args.force_update)
.unwrap_or_else(|e| failure_and_exit!("Failed to resolve script: {}", e)); .unwrap_or_else(|e| failure_and_exit!("Failed to resolve script: {}", e));
let script_file = &script_file; let script_file = &script_file;

View File

@@ -26,7 +26,7 @@ pub fn do_run_script(args: &RunScriptArgs) {
} }
(&args.arguments[args.arguments.len() - 1], false) (&args.arguments[args.arguments.len() - 1], false)
})(); })();
let script_file = resolve_file(raw_script_file) let script_file = resolve_file(raw_script_file, args.force_update)
.unwrap_or_else(|e| failure_and_exit!("Failed to resolve script: {}", e)); .unwrap_or_else(|e| failure_and_exit!("Failed to resolve script: {}", e));
let script_file = &script_file; let script_file = &script_file;
verify::verify_script(script_file, is_env_on("RUNTS_SKIP_VERIFY")); verify::verify_script(script_file, is_env_on("RUNTS_SKIP_VERIFY"));