Compare commits

...

28 Commits

Author SHA1 Message Date
f8ec8a7e2e feat: v1.1.6 2026-01-11 23:15:25 +08:00
6a4cd86e25 feat: runrs v1.1.5, support runts deno or bun runtime 2026-01-04 19:34:42 +08:00
69288f9203 feat: v1.1.4, fix runts shebang issue 2025-01-24 23:02:23 +08:00
d581809696 feat: v1.1.3, fix runts script file issue 2025-01-24 22:19:42 +08:00
ae8266db07 feat: make clippy happy 2025-01-24 00:54:11 +08:00
47677f4705 feat: v1.1.2, support runts sign 2025-01-24 00:48:57 +08:00
35a7972673 feat: v1.1.1, add runrs verification 2025-01-23 23:42:05 +08:00
11b4e6c005 feat: v1.1.0, support --script-repo|-R 2025-01-18 20:30:02 +08:00
39c1d0a68c feat: v1.0.1, fix filter issue 2025-01-18 18:53:30 +08:00
2e4c47e936 feat: updates 2025-01-18 14:37:49 +08:00
18d55793d9 feat: v1.0.0 2025-01-18 14:28:43 +08:00
506df24aae feat: v0.4.0, change js to ts 2025-01-12 08:52:28 +08:00
012f75e765 feat: add --output in help message 2025-01-11 01:00:01 +08:00
2c363e9db6 feat: v0.3.0, use argh 2025-01-11 00:56:45 +08:00
1b3c385794 feat: v0.2.8, fix dart issue 2024-12-31 23:57:18 +08:00
91355c1972 feat: update justfile 2024-12-31 00:35:01 +08:00
6543edd395 feat: 0.2.7 2024-12-31 00:26:30 +08:00
18282e2223 feat: v0.2.6 2024-12-29 22:30:46 +08:00
3ace53b509 feat: v0.2.5, support go scripts 2024-12-29 17:13:41 +08:00
affcb233bd feat: v0.2.4, list supports file-meta.json 2024-08-18 11:31:54 +08:00
b75e350db1 feat: 0.2.3, update help message 2023-11-26 09:14:17 +08:00
10a9364f96 feat: supports linux 2023-03-05 22:27:53 +08:00
c1ae6114b3 feat: upate runrs --list 2023-02-23 23:40:44 +08:00
e283a210ad feat: v0.2.2 2023-02-23 01:05:53 +08:00
2d620e963e feat: delete scripts/commit-msg.crs 2023-02-23 00:50:40 +08:00
e8757f827a feat: rm scripts/get_runrs 2023-02-23 00:32:53 +08:00
9f45e784fc feat: rm scripts/show_myip 2023-02-23 00:31:40 +08:00
6aeab782ee fix: install args empty 2023-02-22 23:52:12 +08:00
27 changed files with 2087 additions and 2898 deletions

1613
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "runrs"
version = "0.2.0"
version = "1.1.6"
edition = "2018"
license = "MIT/Apache-2.0"
description = "A Tool for Run Rust Scripts"
@@ -8,7 +8,18 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["switch-rust-lang"]
switch-rust-lang = []
switch-go-lang = []
switch-ts-lang = []
switch-dart-lang = []
[dependencies]
reqwest = { version = "0.11.14", features = ["blocking"] }
rust_util = "0.6.41"
sha256 = "1.0.3"
reqwest = { version = "0.12", features = ["blocking"] }
rust_util = "0.6"
sha256 = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
argh = "0.1"
script-sign = "0.1"

View File

@@ -4,3 +4,50 @@ _:
install:
cargo install --path .
run-rust *args:
cargo run -- {{args}}
run-go *args:
cargo run --no-default-features --features switch-go-lang -- {{args}}
run-ts *args:
cargo run --no-default-features --features switch-ts-lang -- {{args}}
run-dart *args:
cargo run --no-default-features --features switch-dart-lang -- {{args}}
build-run-rust:
cargo build --release
build-run-go:
cargo build --release --no-default-features --features switch-go-lang
build-run-ts:
cargo build --release --no-default-features --features switch-ts-lang
build-run-dart:
cargo build --release --no-default-features --features switch-dart-lang
install-run-go:
cargo build --release --no-default-features --features switch-go-lang
cp target/release/runrs ~/bin/rungo
install-run-ts:
cargo build --release --no-default-features --features switch-ts-lang
cp target/release/runrs ~/bin/runts
install-run-dart:
cargo build --release --no-default-features --features switch-dart-lang
cp target/release/runrs ~/bin/rundart
build-all:
@just build-run-rust
@just build-run-go
@just build-run-ts
@just build-run-dart
install-all:
@just install
@just install-run-go
@just install-run-ts
@just install-run-dart

View File

@@ -1,194 +0,0 @@
#!/usr/bin/env runrs
// cargo-deps: regex="1.3.9"
use std::{ env, fs, process };
use std::path::PathBuf;
use std::os::unix::fs::PermissionsExt;
const RED: &str = "\x1B[91m";
const GREEN: &str = "\x1B[92m";
const YELLOW: &str = "\x1B[93m";
const BOLD: &str = "\x1B[1m";
const UNDER: &str = "\x1B[4m";
const END: &str = "\x1B[0m";
const DEFAULT_COMMIT_MSG_REGEXP: &str = "^(feat|fix|docs|style|refactor|test|chore)(\\([\\w\\-_.]+\\))?:\\s*.*";
/// Git commit message format check util
///
/// Commit format MUST be <type>(<scope>): subject
///
/// Usage:
/// `commit-msg.crs usage`
///
/// Install:
/// `commit-msg.crs install`
fn main() {
if is_verbose() { print_info(&format!("Arguments:\n- {}", env::args().collect::<Vec<_>>().join("\n- "))); }
let arg1 = env::args().nth(1).unwrap_or_else(|| {
exit_with_error_message("Commit message is EMPTY!");
});
if arg1 == "usage" || arg1 == "USAGE" {
print_usage(); return;
}
let is_install = arg1 == "install" || arg1 == "INSTALL";
let is_force_install = arg1 == "forceinstall" || arg1 == "FORCEINSTALL"
|| arg1 == "force-install" || arg1 == "FORCE-INSTALL"
|| arg1 == "installforce" || arg1 == "INSTALLFORCE"
|| arg1 == "install-force" || arg1 == "INSTALL-FORCE";
if is_install || is_force_install {
install_commit_msg(is_force_install); return;
}
let commit_message = fs::read_to_string(arg1).unwrap_or_else(|e| {
exit_with_error_message(&format!("Read commit message failed: {}", e));
});
let re_str = get_commit_msg_regexp();
let re = match regex::Regex::new(re_str.trim()) {
Ok(re) => re, Err(e) => exit_with_error_message(&format!("Parse regexp: {}, failed: {}", re_str, e)),
};
let is_commit_message_matches = re.is_match(&commit_message);
print_info(&format!("Commit message: {}{}{}", UNDER, commit_message.trim(), END));
if is_commit_message_matches {
print_ok("Commit message rule matches");
} else {
print_usage();
exit_with_error_message("Commit message rule is NOT matched");
}
}
fn is_verbose() -> bool {
if let Ok(v) = env::var("VERBOSE") { v == "1" } else { false }
}
fn print_usage() {
if let Some(usage) = get_commit_msg_usage() {
print_info(&usage); return;
}
print_info(&format!(r#"Please follow the commit spec:
Format: {b}<type>{e}(<scope>){b}: <subject>{e}
<scope> is optional
{b}feat{e}: add hat wobble
^--^ ^------------^
| |
| +-> Summary in present tense.
|
+-------> Type: chore, docs, feat, fix, refactor, style, or test.
{b}feat{e} : new feature for the user, not a new feature for build script
{b}fix{e} : bug fix for the user, not a fix to a build script
{b}docs{e} : changes to the documentation
{b}style{e} : formatting, missing semi colons, etc; no production code change
{b}refactor{e} : refactoring production code, eg. renaming a variable
{b}test{e} : adding missing tests, refactoring tests; no production code change
{b}chore{e} : updating grunt tasks etc; no production code change
Reference: {u}https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716{e}
or mirror: {u}https://hatter.ink/wiki/view_raw.action?__access_token=PUBLIC&id=42{e}
"#, b = BOLD, e = END, u = UNDER));
}
fn search_git_root_path() -> Option<PathBuf> {
let mut p = PathBuf::from(".").canonicalize().unwrap_or_else(|e|
exit_with_error_message(&format!("Get current dir failed: {}", e))
);
loop {
if is_verbose() { print_info(&format!("Check git path: {:?}", p)); }
if p.join(".git").is_dir() {
if is_verbose() { print_ok(&format!("Found git path: {:?}", p)); }
return Some(p);
}
if !p.pop() { return None; }
}
}
fn search_git_root_path_e() -> PathBuf {
search_git_root_path().unwrap_or_else(|| exit_with_error_message("Git root path not found!"))
}
fn get_home_e() -> PathBuf {
PathBuf::from(env::var("HOME").unwrap_or_else(|e|
exit_with_error_message(&format!("Get env HOME failed: {}!", e))
))
}
fn get_commit_msg_file(file: &str) -> Option<String> {
let settings_regexp = search_git_root_path_e().join("settings").join(file);
if is_verbose() { print_info(&format!("Check file: {:?}, exists: {}", settings_regexp, settings_regexp.exists())); }
if settings_regexp.exists() {
print_info(&format!("Found file: {:?}", settings_regexp));
return Some(fs::read_to_string(settings_regexp).unwrap());
}
let path_regexp = search_git_root_path_e().join(".git").join("hooks").join(file);
if is_verbose() { print_info(&format!("Check file: {:?}, exists: {}", path_regexp, path_regexp.exists())); }
if path_regexp.exists() {
print_info(&format!("Found file: {:?}", path_regexp));
return Some(fs::read_to_string(path_regexp).unwrap());
}
let home_path_regexp = get_home_e().join(&(".".to_owned() + file));
if is_verbose() { print_info(&format!("Check file: {:?}, exists: {}", home_path_regexp, home_path_regexp.exists())); }
if home_path_regexp.exists() {
print_info(&format!("Found file: {:?}", home_path_regexp));
return Some(fs::read_to_string(home_path_regexp).unwrap());
}
None
}
fn get_commit_msg_regexp() -> String {
get_commit_msg_file("commit-msg-regexp").unwrap_or_else(|| DEFAULT_COMMIT_MSG_REGEXP.to_owned())
}
fn get_commit_msg_usage() -> Option<String> {
get_commit_msg_file("commit-msg-regexp-usage")
}
fn copy_file_and_apply_executable_permission(from: &PathBuf, to: &PathBuf) {
print_info(&format!("Copy file: {:?} to: {:?}", from, to));
let from_content = fs::read(&from).unwrap_or_else(|e|
exit_with_error_message(&format!("Read file: {:?}, failed: {}", from, e))
);
fs::write(to, from_content).unwrap_or_else(|e|
exit_with_error_message(&format!("Write file: {:?}, failed: {}", to, e))
);
fs::set_permissions(to, PermissionsExt::from_mode(0o755)).unwrap_or_else(|e|
exit_with_error_message(&format!("Apply executable permission on file: {:?}, failed: {}", to, e))
);
}
fn install_commit_msg(force: bool) {
let commit_msg_crs = get_home_e().join("bin").join("commit-msg.crs");
let commig_msg_exec_file = if commit_msg_crs.exists() {
commit_msg_crs
} else {
print_warn(&format!("File {:?} NOT exists!", commit_msg_crs));
PathBuf::from(env::args().next().unwrap())
};
let git_hooks = search_git_root_path_e().join(".git").join("hooks");
if !git_hooks.exists() {
exit_with_error_message(&format!("Path {:?} NOT exists!", git_hooks));
}
let git_hooks_commit_msg = git_hooks.join("commit-msg");
if git_hooks_commit_msg.exists() && !force {
exit_with_error_message(&format!("File {:?} exists! or try {}forceinstall{}.", git_hooks_commit_msg, BOLD, END));
}
copy_file_and_apply_executable_permission(&commig_msg_exec_file, &git_hooks_commit_msg);
print_ok("Install commit-msg to repo successed!");
}
fn exit_with_error() -> ! { process::exit(1) }
fn exit_with_error_message(msg: &str) -> ! { print_error(msg); exit_with_error() }
fn print_info(msg: &str) { println!("{b}[INFO ]{e} {m}", b = BOLD, e = END, m = msg); }
fn print_ok(msg: &str) { println!("{g}{b}[OK ]{e} {g}{m}{e}", g = GREEN, b = BOLD, e = END, m = msg); }
fn print_warn(msg: &str) { println!("{y}{b}[WARN ]{e} {y}{m}{e}", y = YELLOW, b = BOLD, e = END, m = msg); }
fn print_error(msg: &str) { println!("{r}{b}[ERROR]{e} {r}{m}{e}", r = RED, b = BOLD, e = END, m = msg); }

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +0,0 @@
[package]
name = "get_runrs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
rust_util = { version = "0.6" }

View File

@@ -1,55 +0,0 @@
#!/usr/bin/env runrs
//! ```cargo
//! [dependencies]
//! reqwest = { version = "0.11", features = ["blocking"] }
//! rust_util = { version = "0.6" }
//! ```
use std::{env, fs};
use std::os::unix::fs::PermissionsExt;
use std::path::PathBuf;
use rust_util::{failure_and_exit, success, util_env, util_os, warning};
fn main() {
let args = env::args().skip(1).collect::<Vec<_>>();
if args.is_empty() { failure_and_exit!("No arguments"); }
let script_name = args.get(0).unwrap_or_else(|| {
failure_and_exit!("No script name assigned")
});
let home = util_os::get_user_home().unwrap_or_else(|| {
failure_and_exit!("Get user home failed");
});
let home_bin = format!("{}/bin", home);
if !PathBuf::from(&home_bin).exists() {
failure_and_exit!("Home bin {} not exists", home_bin);
}
let overwrite_target_resource_script = util_env::is_env_on("OVERWRITE_SCRIPT");
let target_resource_script = format!("{}/bin/{}.rs", home, script_name);
if PathBuf::from(&target_resource_script).exists() {
if overwrite_target_resource_script {
warning!("Script: {} exists, will be overwritten", target_resource_script);
} else {
failure_and_exit!("Target script: {} exists, set env OVERWRITE_SCRIPT=1 for overwrite", target_resource_script);
}
}
let fetch_resource = format!(
"https://git.hatter.ink/hatter/runrs/raw/branch/master/scripts/{}/src/main.rs", script_name);
let response = reqwest::blocking::get(&fetch_resource).unwrap_or_else(|e| {
failure_and_exit!("Get script resource failed: {}\n- {}", e, fetch_resource);
});
if response.status().as_u16() != 200 {
failure_and_exit!("Get script resource not success: {}\n- {}", response.status().as_u16(), fetch_resource);
}
let response_bytes = response.bytes().unwrap_or_else(|e| {
failure_and_exit!("Get script resource failed: {},\n- {}", e, fetch_resource);
});
fs::write(&target_resource_script, response_bytes).unwrap_or_else(|e| {
failure_and_exit!("Write to script file: {} failed: {}", target_resource_script, e);
});
fs::set_permissions(&target_resource_script, PermissionsExt::from_mode(0o755)).unwrap_or_else(|e| {
failure_and_exit!("Apply executable permission to file: {:?} failed: {}", target_resource_script, e);
});
success!("Write to script file: {} success", target_resource_script);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +0,0 @@
[package]
name = "show_myip"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.11", features = ["blocking", "json"] }
rust_util = { version = "0.6" }

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env runrs
//! ```cargo
//! [dependencies]
//! serde = { version = "1.0", features = ["derive"] }
//! serde_json = "1.0"
//! reqwest = { version = "0.11", features = ["blocking", "json"] }
//! rust_util = { version = "0.6" }
//! ```
use rust_util::{failure_and_exit, success};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct IpResponse {
status: u16,
message: String,
ip: String,
#[serde(rename = "userAgent")]
user_agent: Option<String>,
}
const GET_IP_URL: &'static str = "https://hatter.ink/ip/ip.jsonp";
fn main() {
let ip_response: IpResponse = reqwest::blocking::get(GET_IP_URL).unwrap_or_else(|e| {
failure_and_exit!("Send request to: {} failed: {}", GET_IP_URL, e);
}).json().unwrap_or_else(|e| {
failure_and_exit!("Parse response from: {}, failed: {}", GET_IP_URL, e);
});
success!("Your IP address is: {}", ip_response.ip);
}

View File

@@ -1,36 +1,20 @@
pub fn print_help() {
println!(r##"{} v{} - {}
let help = get_help()
.replace("{CARGO_PKG_NAME}", env!("CARGO_PKG_NAME"))
.replace("{CARGO_PKG_VERSION}", env!("CARGO_PKG_VERSION"))
.replace("{CARGO_PKG_DESCRIPTION}", env!("CARGO_PKG_DESCRIPTION"));
println!("{}", help);
}
Show help:
$ runrs -h|--help
Show template:
$ runrs -t|--template
Install script:
$ runrs -i|--install <script.rs>
Run script:
$ runrs <script.rs> [arguments]
Binaries dir:
~/Library/Caches/rust-script/binaries/release/
Environment variables:
┌──────────────────────┬────────────────────────────────────────────────┐
│ Variable │ Description │
├──────────────────────┼────────────────────────────────────────────────┤
│ HOME │ User home, default by OS system │
│ RUNRS_SKIP_CACHE │ Skip compiled cached file, `bool` │
│ RUNRS_REBUILD │ Force rebuild, `bool` │
│ RUNRS_SILENT_BUILD │ Build new binary in silent mode, `bool` │
│ RUNRS_RUST_SCRIPT │ `rust_script` command line bin file │
│ RUNRS_MAX_SCRIPT_LEN │ Max script length, default 1MB │
└──────────────────────┴────────────────────────────────────────────────┘
> Type `bool`: `true`, `yes`, `on` or `1` for true, otherwise false
"##,
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
env!("CARGO_PKG_DESCRIPTION")
);
}
#[allow(unreachable_code)]
fn get_help() -> &'static str {
#[cfg(feature = "switch-rust-lang")]
return include_str!("script.help.rs.txt");
#[cfg(feature = "switch-go-lang")]
return include_str!("script.help.go.txt");
#[cfg(feature = "switch-ts-lang")]
return include_str!("script.help.ts.txt");
#[cfg(feature = "switch-dart-lang")]
return include_str!("script.help.dart.txt");
panic!("Unknown feature assigned.");
}

View File

@@ -1,66 +1,98 @@
use crate::util;
use crate::util::ScriptMeta;
use std::collections::BTreeMap;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::PathBuf;
use rust_util::util_os::get_user_home;
const SCRIPT_PATTERN: &'static str = "https://git.hatter.ink/rust-scripts/scriptbase/raw/branch/main/$NAME/src/main.rs";
pub fn install_script(args: Vec<&String>) {
if args.is_empty() {
failure!("No script name assigned!");
pub fn install_scripts(script_repo: &Option<String>, scripts: &[String]) {
if scripts.is_empty() {
failure_and_exit!("No scripts assigned.");
}
let script_name = &args[0];
let normalized_script_name = if script_name.ends_with(".rs") {
script_name.chars().take(script_name.len() - 3).collect::<String>() + "-rs"
} else if script_name.ends_with("-rs") {
script_name.to_string()
} else {
failure_and_exit!("Invalid script name: {}", script_name);
let script_meta_map = util::fetch_script_meta_or_die(script_repo);
for (i, script_name) in scripts.iter().enumerate() {
information!(
"Installing script: {} [ {} / {} ]",
script_name,
(i + 1),
scripts.len()
);
install_script(script_name, &script_meta_map);
}
}
fn install_script(script_name: &str, script_meta_map: &BTreeMap<String, ScriptMeta>) {
let script_meta = match script_meta_map.get(script_name) {
None => {
failure!("Script not found: {}", script_name);
return;
}
Some(script_meta) => script_meta,
};
let script_file_name = normalized_script_name
.chars().take(normalized_script_name.len() - 3).collect::<String>() + ".rs";
let user_home = get_user_home().expect("Get user home failed!");
let output_file_name = PathBuf::from(&user_home).join("bin").join(&script_file_name);
if output_file_name.exists() {
warning!("Script file: {} exists", output_file_name.to_string_lossy());
}
let script_url = SCRIPT_PATTERN.replace("$NAME", &normalized_script_name);
let script_url = &script_meta.script_full_url;
information!("Script URL: {}", &script_url);
let get_script_response_result = reqwest::blocking::get(&script_url);
let get_script_response_result = reqwest::blocking::get(script_url);
debugging!("Get script response: {:#?}", &get_script_response_result);
let get_script_response = match get_script_response_result {
Err(e) => failure_and_exit!("Get script failed: {}", e),
Ok(response) => response
Err(e) => {
failure!("Get script failed: {}", e);
return;
}
Ok(response) => response,
};
let get_script_response_status = get_script_response.status().as_u16();
if get_script_response_status == 404 {
failure_and_exit!("Script not found!");
failure!("Script not found!");
return;
} else if get_script_response_status != 200 {
failure_and_exit!("Get script failed: {}", get_script_response_status);
failure!("Get script failed: {}", get_script_response_status);
return;
}
let text = match get_script_response.text() {
Err(e) => failure_and_exit!("Get script: {} failed: {}", &script_url, e),
Ok(text) => text
let remote_script_content = match get_script_response.text() {
Err(e) => {
failure!("Get script: {} failed: {}", &script_url, e);
return;
}
Ok(remote_script_content) => remote_script_content,
};
let user_home = util::get_user_home_or_die();
let output_file_name = PathBuf::from(&user_home)
.join("bin")
.join(&script_meta.script_name);
if output_file_name.exists() {
warning!("Script file: {} exists", output_file_name.to_string_lossy());
}
if let Ok(script_content) = fs::read_to_string(&output_file_name) {
if text == script_content {
success!("File is extract same, skip write file: {}", output_file_name.to_string_lossy());
if remote_script_content == script_content {
success!(
"File is extract same, skip write file: {}",
output_file_name.to_string_lossy()
);
return;
}
}
if let Err(e) = fs::write(&output_file_name, text) {
failure_and_exit!("Write script: {} failed: {}", output_file_name.to_string_lossy(), e)
if let Err(e) = fs::write(&output_file_name, remote_script_content) {
failure!(
"Write script: {} failed: {}",
output_file_name.to_string_lossy(),
e
);
return;
}
success!("Write file: {} success", output_file_name.to_string_lossy());
match fs::set_permissions(&output_file_name, PermissionsExt::from_mode(0o755)) {
Err(e) => failure_and_exit!("Chmod script: {} permission failed: {}", output_file_name.to_string_lossy(), e),
Ok(_) => success!("Chmod script: {} permission succeed", output_file_name.to_string_lossy())
Err(e) => failure!(
"Chmod script: {} permission failed: {}",
output_file_name.to_string_lossy(),
e
),
Ok(_) => success!(
"Chmod script: {} permission succeed",
output_file_name.to_string_lossy()
),
}
}
}

72
src/list.rs Normal file
View File

@@ -0,0 +1,72 @@
use crate::install::install_scripts;
use crate::util;
use std::fs;
use std::path::PathBuf;
pub fn list_scripts(
script_repo: &Option<String>,
filter: Option<&String>,
update_listed_scripts: bool,
) {
let script_meta_map = util::fetch_script_meta_or_die(script_repo);
let mut matched_need_update_scripts = vec![];
let mut messages = vec![];
for script_meta in script_meta_map.values() {
let script_name = &script_meta.script_name;
if let Some(filter) = filter {
if !script_name.contains(filter) {
// NOT CONTAINS `filter`, SKIP
continue;
}
}
let user_home = util::get_user_home_or_die();
let full_script_path = PathBuf::from(&user_home).join("bin").join(script_name);
let is_script_exists = full_script_path.is_file();
let script_sha256 = if is_script_exists {
let script_content = fs::read(&full_script_path).unwrap_or(vec![]);
sha256::digest(&script_content)
} else {
"".to_string()
};
let is_script_matches = script_sha256 == script_meta.script_sha256;
let script_size = rust_util::util_size::get_display_size(script_meta.script_length as i64);
let padding_length = 40 - script_name.len();
messages.push(format!(
"- {} {} {} {}",
iff!(is_script_exists, iff!(is_script_matches, "", "✔️ "), ""),
script_name,
".".repeat(iff!(padding_length < 1, 1, padding_length)),
script_size,
));
if is_script_exists && !is_script_matches {
matched_need_update_scripts.push(script_meta.script_name.clone());
}
}
if filter.is_some() {
messages.insert(
0,
format!(
"Total {} script(s), found {} script(s):",
script_meta_map.len(),
messages.len()
),
);
} else {
messages.insert(0, format!("Found {} script(s):", script_meta_map.len()));
}
success!("{}", messages.join("\n"));
if update_listed_scripts {
if matched_need_update_scripts.len() > 0 {
information!(
"Update listed scripts ON:\n- {}\n",
matched_need_update_scripts.join("\n- ")
);
install_scripts(script_repo, &matched_need_update_scripts);
} else {
information!("No update listed scripts");
}
}
}

View File

@@ -1,51 +1,93 @@
#[macro_use]
extern crate rust_util;
use argh::FromArgs;
use std::env;
use rust_util::util_os::get_user_home;
use crate::help::print_help;
use crate::install::install_script;
use crate::util::{build_script_command, get_run_script_bin_name, read_file_and_digest, run_script_command};
mod util;
mod help;
mod install;
mod list;
mod run_rs;
#[cfg(feature = "switch-ts-lang")]
mod run_ts;
mod template;
mod util;
mod verify;
const SCRIPT_TEMPLATE: &'static str = include_str!("script.template");
#[derive(FromArgs, PartialEq, Debug)]
/// Run script
struct RunScriptArgs {
/// help message
#[argh(switch, short = 'h')]
help_message: bool,
/// script template
#[argh(switch, short = 't')]
template: bool,
/// list scripts
#[argh(switch, short = 'l')]
list: bool,
/// install script
#[argh(switch, short = 'i')]
install: bool,
/// update listed scripts
#[argh(option)]
update_listed_scripts: Option<bool>,
/// script repo
#[argh(option, short = 'R')]
script_repo: Option<String>,
/// output
#[argh(option, short = 'o')]
output: Option<String>,
/// arguments
#[argh(positional, greedy)]
arguments: Vec<String>,
}
fn main() {
let user_home = get_user_home().unwrap_or_else(|| failure_and_exit!("$HOME not found!"));
let rust_script = get_run_script_bin_name(&user_home);
let rs_args: RunScriptArgs = argh::from_env();
let cmd_version = env!("CARGO_PKG_VERSION");
if env::args().len() == 1 {
let cmd_name = util::get_cmd_name();
failure_and_exit!(
"{cmd_name} v{cmd_version}, need arguments, `{cmd_name} -h` or `{cmd_name} --help-message` for help"
);
}
let args = env::args().skip(1).collect::<Vec<_>>();
if args.is_empty() {
failure_and_exit!("runrs v{}, need arguments, `runrs -h` or `runrs --help` for help", env!("CARGO_PKG_VERSION"));
}
let first_argument = args.get(0).unwrap_or_else(|| failure_and_exit!("Must assign a script file name"));
if first_argument == "--help" || first_argument == "-h" {
print_help();
if rs_args.help_message {
help::print_help();
return;
}
if first_argument == "--template" || first_argument == "-t" {
println!("{}", SCRIPT_TEMPLATE);
if rs_args.template {
template::print_template(&rs_args.output);
return;
}
if first_argument == "--install" || first_argument == "-i" {
install_script(args.iter().skip(1).collect());
if rs_args.list {
list::list_scripts(
&rs_args.script_repo,
rs_args.arguments.first(),
rs_args.update_listed_scripts.unwrap_or(false),
);
return;
}
if rs_args.install {
install::install_scripts(&rs_args.script_repo, &rs_args.arguments);
return;
}
let script_file = first_argument;
let (_, script_sha256) = read_file_and_digest(script_file);
debugging!("File {} -> sha256: {}", script_file, script_sha256);
let cache_script_bin_name = format!("{}/Library/Caches/rust-script/binaries/release/{}", user_home, script_sha256);
let mut run_script_cmd = build_script_command(rust_script, script_file, &script_sha256, &cache_script_bin_name);
for arg in args.iter().skip(1) {
run_script_cmd.arg(arg);
}
run_script_command(script_file, &cache_script_bin_name, &mut run_script_cmd)
do_run_script(&rs_args);
}
#[allow(unreachable_code)]
fn do_run_script(rs_args: &RunScriptArgs) {
#[cfg(feature = "switch-rust-lang")]
{
run_rs::do_run_script(rs_args);
return;
}
#[cfg(feature = "switch-ts-lang")]
{
run_ts::do_run_script(&rs_args);
return;
}
failure_and_exit!("Only rust script supported.");
}

43
src/run_rs.rs Normal file
View File

@@ -0,0 +1,43 @@
use crate::{util, verify, RunScriptArgs};
use rust_util::util_env::is_env_on;
use rust_util::util_os::get_user_home;
pub fn do_run_script(args: &RunScriptArgs) {
if args.arguments.is_empty() {
failure_and_exit!("Must assign a script file name");
}
let script_file = &args.arguments[0];
verify::verify_script(script_file, is_env_on("RUNRS_SKIP_VERIFY"));
let (_, script_sha256) = util::read_file_and_digest(script_file);
debugging!("File {} -> sha256: {}", script_file, script_sha256);
let user_home = get_user_home().unwrap_or_else(|| failure_and_exit!("$HOME not found!"));
let rust_script = util::get_run_script_bin_name(&user_home);
let cache_script_bin_name = get_cache_script_bin_name(&user_home, &script_sha256);
let mut run_script_cmd = util::build_script_command(
rust_script,
script_file,
&script_sha256,
&cache_script_bin_name,
);
for arg in args.arguments.iter().skip(1) {
run_script_cmd.arg(arg);
}
util::run_script_command(script_file, &cache_script_bin_name, &mut run_script_cmd)
}
fn get_cache_script_bin_name(user_home: &str, script_sha256: &str) -> String {
#[cfg(target_os = "macos")]
let cache_script_bin_name = format!(
"{}/Library/Caches/rust-script/binaries/release/{}",
user_home, script_sha256
);
// #[cfg(target_os = "linux")]
#[cfg(not(target_os = "macos"))]
let cache_script_bin_name = format!(
"{}/.cache/rust-script/binaries/release/{}",
user_home, script_sha256
);
cache_script_bin_name
}

136
src/run_ts.rs Normal file
View File

@@ -0,0 +1,136 @@
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 (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)
})();
verify::verify_script(script_file, is_env_on("RUNTS_SKIP_VERIFY"));
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;
}
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")
);
}

13
src/script.help.dart.txt Normal file
View File

@@ -0,0 +1,13 @@
rundart v{CARGO_PKG_VERSION} - A Tool for Run dart Scripts
Show help:
$ rundart -h|--help
Show template:
$ rundart -t|--template [--output script.dart]
Show scriptions:
$ rundart -l|--list [filter] [--update-listed-scripts]
Install script:
$ rundart -i|--install <script.dart>

15
src/script.help.go.txt Normal file
View File

@@ -0,0 +1,15 @@
rungo v{CARGO_PKG_VERSION} - A Tool for Run Go Scripts
Show help:
$ rungo -h|--help
Show template:
$ rungo -t|--template [--output script.go]
Show scriptions:
$ rungo -l|--list [filter] [--update-listed-scripts]
Install script:
$ rungo -i|--install <script.go>
Powered by gorun, know more reference: https://github.com/erning/gorun

33
src/script.help.rs.txt Normal file
View File

@@ -0,0 +1,33 @@
runrs v{CARGO_PKG_VERSION} - {CARGO_PKG_DESCRIPTION}
Show help:
$ runrs -h|--help
Show template:
$ runrs -t|--template [--output script.rs]
Show scriptions:
$ runrs [-R|--script-repo runrs] -l|--list [filter] [--update-listed-scripts]
Install script:
$ runrs [-R|--script-repo runrs] -i|--install <script.rs>
Run script:
$ runrs <script.rs> [arguments]
Binaries dir:
~/Library/Caches/rust-script/binaries/release/
Environment variables:
┌──────────────────────┬────────────────────────────────────────────────┐
│ Variable │ Description │
├──────────────────────┼────────────────────────────────────────────────┤
│ HOME │ User home, default from OS system │
│ RUNRS_SKIP_CACHE │ Skip compiled cached file, `bool` │
│ RUNRS_REBUILD │ Force rebuild, `bool` │
│ RUNRS_SILENT_BUILD │ Build new binary in silent mode, `bool` │
│ RUNRS_SKIP_VERIFY │ Skip script verification, `bool` │
│ RUNRS_RUST_SCRIPT │ `rust_script` command line bin file │
│ RUNRS_MAX_SCRIPT_LEN │ Max script length, default 1MB │
└──────────────────────┴────────────────────────────────────────────────┘
> Type `bool`: `true`, `yes`, `on` or `1` for true, otherwise false

20
src/script.help.ts.txt Normal file
View File

@@ -0,0 +1,20 @@
runts v{CARGO_PKG_VERSION} - A Tool for Run TS Scripts
Show help:
$ runts -h|--help
Show template:
$ runts -t|--template [--output script.ts]
Show scriptions:
$ runts -l|--list [filter] [--update-listed-scripts]
Install script:
$ runts -i|--install <script.ts>
Environment variables:
┌──────────────────────┬────────────────────────────────────────────────┐
│ Variable │ Description │
├──────────────────────┼────────────────────────────────────────────────┤
│ RUNTS_SKIP_VERIFY │ Skip script verification, `bool` │
└──────────────────────┴────────────────────────────────────────────────┘

5
src/script.template.dart Normal file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env dart
main(List<String> args) {
print("Hello world.");
}

40
src/script.template.go Normal file
View File

@@ -0,0 +1,40 @@
/// 2>/dev/null ; gorun "$0" "$@" ; exit $?
// OR: #!/usr/bin/env gorun
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
const GetIpUrl = "https://hatter.ink/ip/ip.jsonp"
type IpResponse struct {
Status int16 `json:"status"`
Message string `json:"message"`
IP string `json:"ip"`
UserAgent string `json:"userAgent"`
}
func main() {
response, err := http.Get(GetIpUrl)
if err != nil {
fmt.Printf("[ERROR] Get IP failed: %s\n", err)
os.Exit(1)
}
body, err := io.ReadAll(response.Body)
if err != nil {
fmt.Printf("[ERROR] Get IP failed: %s\n", err)
os.Exit(2)
}
var ipReponse IpResponse
if err := json.Unmarshal(body, &ipReponse); err != nil {
fmt.Printf("[ERROR] Get IP failed: %s\n", err)
os.Exit(3)
}
fmt.Printf("[INFO] Your IP address: %s\n", ipReponse.IP)
}

3
src/script.template.ts Normal file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env runts -- --allow-env
console.log("Hello world.");

33
src/template.rs Normal file
View File

@@ -0,0 +1,33 @@
use std::fs;
use std::os::unix::fs::PermissionsExt;
pub fn print_template(output: &Option<String>) {
let script = get_script_template();
if let Some(output_file) = output {
if fs::metadata(output_file).is_ok() {
failure!("Output script file exists: {}", output_file);
return;
}
if let Err(e) = fs::write(output_file, script) {
failure!("Write script file: {}, failed: {}", output_file, e);
} else {
success!("Write script file success: {}", output_file);
let _ = fs::set_permissions(output_file, PermissionsExt::from_mode(0o755));
}
} else {
println!("{}", script);
}
}
#[allow(unreachable_code)]
fn get_script_template() -> &'static str {
#[cfg(feature = "switch-rust-lang")]
return include_str!("script.template.rs");
#[cfg(feature = "switch-go-lang")]
return include_str!("script.template.go");
#[cfg(feature = "switch-ts-lang")]
return include_str!("script.template.ts");
#[cfg(feature = "switch-dart-lang")]
return include_str!("script.template.dart");
panic!("Unknown feature assigned.");
}

View File

@@ -1,18 +1,108 @@
use std::{env, fs, process};
use rust_util::util_cmd;
use rust_util::util_env::is_env_on;
use rust_util::util_os::get_user_home;
use serde::Deserialize;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::Command;
use std::time::SystemTime;
use rust_util::util_cmd;
use rust_util::util_env::is_env_on;
use std::{env, fs, process};
#[cfg(feature = "switch-rust-lang")]
const RS_SCRIPT_META_URL: &str =
"https://git.hatter.ink/rust-scripts/scriptbase/raw/branch/main/script-meta-v2.json";
#[cfg(feature = "switch-go-lang")]
const GO_SCRIPT_META_URL: &str =
"https://git.hatter.ink/hatter/go-scripts/raw/branch/main/script-meta-v2.json";
#[cfg(feature = "switch-ts-lang")]
const TS_SCRIPT_META_URL: &str =
"https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/script-meta-v2.json";
#[cfg(feature = "switch-dart-lang")]
const DART_SCRIPT_META_URL: &str =
"https://git.hatter.ink/hatter/dart-scripts/raw/branch/main/script-meta-v2.json";
pub fn build_script_command(rust_script: PathBuf, script_file: &str, script_sha256: &str, cache_script_bin_name: &str) -> Command {
#[allow(dead_code)]
#[derive(Deserialize)]
pub struct ScriptMeta {
pub script_name: String,
pub script_length: u64,
pub script_sha256: String,
pub script_full_url: String,
pub single_script_file: Option<bool>,
}
#[allow(unreachable_code)]
pub fn get_script_meta_url(script_repo: &Option<String>) -> String {
if let Some(script_repo) = script_repo {
return format!("https://hatter.ink/script/{script_repo}/script-meta-v2.action");
}
#[cfg(feature = "switch-rust-lang")]
return RS_SCRIPT_META_URL.to_string();
#[cfg(feature = "switch-go-lang")]
return GO_SCRIPT_META_URL.to_string();
#[cfg(feature = "switch-ts-lang")]
return TS_SCRIPT_META_URL.to_string();
#[cfg(feature = "switch-dart-lang")]
return DART_SCRIPT_META_URL.to_string();
panic!("Unknown feature assigned.");
}
#[allow(unreachable_code)]
pub fn get_cmd_name() -> &'static str {
#[cfg(feature = "switch-rust-lang")]
return "runrs";
#[cfg(feature = "switch-go-lang")]
return "rungo";
#[cfg(feature = "switch-ts-lang")]
return "runts";
#[cfg(feature = "switch-dart-lang")]
return "rundart";
panic!("Unknown feature assigned.");
}
pub fn fetch_script_meta_or_die(script_repo: &Option<String>) -> BTreeMap<String, ScriptMeta> {
let file_meta_url = get_script_meta_url(script_repo);
debugging!("Loading URL: {}", file_meta_url);
let response = reqwest::blocking::get(file_meta_url).unwrap_or_else(|e| {
failure_and_exit!("Get file-meta.json failed: {}", e);
});
debugging!("Load response: {}", response.status().as_u16());
if response.status().as_u16() != 200 {
failure_and_exit!(
"Get file-meta.json failed, status: {}",
response.status().as_u16()
);
}
let text = response.text().unwrap_or_else(|e| {
failure_and_exit!("Get file-meta.json failed: {}", e);
});
debugging!("Response text: {}", &text);
let script_meta_map: BTreeMap<String, ScriptMeta> =
serde_json::from_str(&text).expect("Parse script-meta.json failed.");
script_meta_map
}
pub fn get_user_home_or_die() -> String {
get_user_home().expect("Get user home failed!")
}
pub fn build_script_command(
rust_script: PathBuf,
script_file: &str,
script_sha256: &str,
cache_script_bin_name: &str,
) -> Command {
let skip_cache = is_env_on("RUNRS_SKIP_CACHE");
let rebuild = is_env_on("RUNRS_REBUILD");
let cache_script_bin_name_exists = fs::metadata(&cache_script_bin_name).is_ok();
debugging!("Bin name: {} {}exists", cache_script_bin_name, iff!(cache_script_bin_name_exists, "", "not "));
let cache_script_bin_name_exists = fs::metadata(cache_script_bin_name).is_ok();
debugging!(
"Bin name: {} {}exists",
cache_script_bin_name,
iff!(cache_script_bin_name_exists, "", "not ")
);
if !rebuild && !skip_cache && cache_script_bin_name_exists {
Command::new(&cache_script_bin_name)
Command::new(cache_script_bin_name)
} else {
let mut cmd = Command::new(rust_script);
if !is_env_on("RUNRS_SILENT_BUILD") {
@@ -22,37 +112,52 @@ pub fn build_script_command(rust_script: PathBuf, script_file: &str, script_sha2
if rebuild {
cmd.arg("--force");
}
cmd.args(&["--bin-name", &script_sha256, script_file]);
cmd.args(["--bin-name", script_sha256, script_file]);
cmd
}
}
pub fn run_script_command(script_file: &str, cache_script_bin_name: &str, mut run_script_cmd: &mut Command) -> ! {
pub fn run_script_command(
script_file: &str,
cache_script_bin_name: &str,
run_script_cmd: &mut Command,
) -> ! {
debugging!("Run command: {:?}", run_script_cmd);
let run_command_start = SystemTime::now();
match util_cmd::run_command_and_wait(&mut run_script_cmd) {
match util_cmd::run_command_and_wait(run_script_cmd) {
Err(e) => failure_and_exit!("Run rust-script failed: {}", e),
Ok(exit_status) => {
write_script_file_to_src(script_file, cache_script_bin_name);
if let Ok(run_command_cost) = SystemTime::now().duration_since(run_command_start) {
debugging!("Run command cost: {}ms", run_command_cost.as_millis());
}
process::exit(exit_status.code().unwrap_or_else(|| 0))
process::exit(exit_status.code().unwrap_or(0))
}
}
}
pub fn write_script_file_to_src(script_file: &str, cache_script_bin_name: &str) {
if let Ok(Some(canonicalized_script_file)) = PathBuf::from(script_file)
.canonicalize().map(|f| f.to_str().map(|f| f.to_string())) {
.canonicalize()
.map(|f| f.to_str().map(|f| f.to_string()))
{
let cache_script_bin_name_src = format!("{}.src", cache_script_bin_name);
let src_content = fs::read_to_string(&cache_script_bin_name_src).ok();
if src_content.as_ref().map(|c| c.contains(&canonicalized_script_file)).unwrap_or_else(|| false) {
if src_content
.as_ref()
.map(|c| c.contains(&canonicalized_script_file))
.unwrap_or_else(|| false)
{
return;
}
let new_src_content = src_content.unwrap_or_else(|| "".to_string()) + &format!("{}\n", canonicalized_script_file);
if let Ok(_) = fs::write(&cache_script_bin_name_src, &new_src_content) {
debugging!("Add {} to {}", canonicalized_script_file, cache_script_bin_name_src);
let new_src_content = src_content.unwrap_or_else(|| "".to_string())
+ &format!("{}\n", canonicalized_script_file);
if fs::write(&cache_script_bin_name_src, &new_src_content).is_ok() {
debugging!(
"Add {} to {}",
canonicalized_script_file,
cache_script_bin_name_src
);
}
}
}
@@ -69,13 +174,20 @@ pub fn get_run_script_bin_name(home: &str) -> PathBuf {
if !rust_script.exists() {
warning!("rust-script not found, install it...");
let mut cargo_install_rust_script = Command::new("cargo");
cargo_install_rust_script.args(&["install", "--git", "https://git.hatter.ink/hatter/runrs", "rust-script"]);
cargo_install_rust_script.args([
"install",
"--git",
"https://git.hatter.ink/hatter/runrs",
"rust-script",
]);
debugging!("Run command: {:?}", cargo_install_rust_script);
match util_cmd::run_command_and_wait(&mut cargo_install_rust_script) {
Err(e) => failure_and_exit!("Install rust-script failed: {}", e),
Ok(exist_status) => if !exist_status.success() {
failure!("Install rust-script not success: {}", exist_status);
},
Ok(exist_status) => {
if !exist_status.success() {
failure!("Install rust-script not success: {}", exist_status);
}
}
}
}
rust_script
@@ -84,19 +196,21 @@ pub fn get_run_script_bin_name(home: &str) -> PathBuf {
pub fn read_file_and_digest(script_file: &str) -> (String, String) {
let default_max_script_len = 1024 * 1024;
let max_script_len: u64 = env::var("RUNRS_MAX_SCRIPT_LEN")
.map(|len| len.parse().unwrap_or_else(|_| default_max_script_len)).unwrap_or_else(|_| default_max_script_len);
.map(|len| len.parse().unwrap_or(default_max_script_len))
.unwrap_or(default_max_script_len);
match fs::metadata(script_file) {
Err(_) => failure_and_exit!("Script file not exists: {}", script_file),
Ok(metadata) => if metadata.is_dir() {
failure_and_exit!("Assigned input is dir: {}", script_file);
} else if metadata.len() > max_script_len {
failure_and_exit!("Script file: {} too large: {}", script_file, metadata.len());
Ok(metadata) => {
if metadata.is_dir() {
failure_and_exit!("Assigned input is dir: {}", script_file);
} else if metadata.len() > max_script_len {
failure_and_exit!("Script file: {} too large: {}", script_file, metadata.len());
}
}
}
let script_content = fs::read_to_string(script_file).unwrap_or_else(|e|
failure_and_exit!("Read file: {}, failed: {}", script_file, e)
);
let script_content = fs::read_to_string(script_file)
.unwrap_or_else(|e| failure_and_exit!("Read file: {}, failed: {}", script_file, e));
let script_sha256 = sha256::digest(script_content.as_str());
(script_content, script_sha256)
}
}

20
src/verify.rs Normal file
View File

@@ -0,0 +1,20 @@
use script_sign::Script;
pub fn verify_script(file: &str, skip_verify: bool) {
if skip_verify {
debugging!("Script {file} verification skipped");
return;
}
match Script::verify_script_file_with_system_key_map(file) {
Ok(true) => {
// Verify file ok!
debugging!("Script {file} verification success");
}
Ok(false) => {
failure_and_exit!("Verify script {file} failed, no signature or bad signature");
}
Err(e) => {
failure_and_exit!("Verify script {file} failed, error: {e}");
}
}
}