142 lines
4.5 KiB
Rust
142 lines
4.5 KiB
Rust
//! Herodo - A Rhai script executor for SAL
|
|
//!
|
|
//! This library loads the Rhai engine, registers all SAL modules,
|
|
//! and executes Rhai scripts from a specified directory in sorted order.
|
|
|
|
use rhai::{Engine, Scope};
|
|
use std::error::Error;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process;
|
|
|
|
/// Run the herodo script executor with the given script path
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `script_path` - Path to a Rhai script file or directory containing Rhai scripts
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// Result indicating success or failure
|
|
pub fn run(script_path: &str) -> Result<(), Box<dyn Error>> {
|
|
let path = Path::new(script_path);
|
|
|
|
// Check if the path exists
|
|
if !path.exists() {
|
|
eprintln!("Error: '{}' does not exist", script_path);
|
|
process::exit(1);
|
|
}
|
|
|
|
// Create a new Rhai engine
|
|
let mut engine = Engine::new();
|
|
|
|
// TODO: if we create a scope here we could clean up all the different functionsand types regsitered wit the engine
|
|
// We should generalize the way we add things to the scope for each module sepeartely
|
|
let mut scope = Scope::new();
|
|
// TODO: this should be done for the other clients as well (but not here of course, in each module)
|
|
let hetzner_client = sal::hetzner::api::Client::new(sal::hetzner::config::Config::from_env().unwrap());
|
|
scope.push("hetzner", hetzner_client);
|
|
// This makes it easy to call e.g. `hetzner.get_server()` or `mycelium.get_connected_peers()`
|
|
// --> without the need of manually created a client for each one first
|
|
// --> could be conditionally compiled to only use those who we need (we only push the things to the scope that we actually need to run the script)
|
|
|
|
|
|
// Register println function for output
|
|
engine.register_fn("println", |s: &str| println!("{}", s));
|
|
|
|
// Register all SAL modules with the engine
|
|
sal::rhai::register(&mut engine)?;
|
|
|
|
// Collect script files to execute
|
|
let script_files: Vec<PathBuf> = if path.is_file() {
|
|
// Single file
|
|
if let Some(extension) = path.extension() {
|
|
if extension != "rhai" {
|
|
eprintln!("Warning: '{}' does not have a .rhai extension", script_path);
|
|
}
|
|
}
|
|
vec![path.to_path_buf()]
|
|
} else if path.is_dir() {
|
|
// Directory - collect all .rhai files recursively and sort them
|
|
let mut files = Vec::new();
|
|
collect_rhai_files(path, &mut files)?;
|
|
|
|
if files.is_empty() {
|
|
eprintln!("No .rhai files found in directory: {}", script_path);
|
|
process::exit(1);
|
|
}
|
|
|
|
// Sort files for consistent execution order
|
|
files.sort();
|
|
|
|
files
|
|
} else {
|
|
eprintln!("Error: '{}' is neither a file nor a directory", script_path);
|
|
process::exit(1);
|
|
};
|
|
|
|
println!(
|
|
"Found {} Rhai script{} to execute:",
|
|
script_files.len(),
|
|
if script_files.len() == 1 { "" } else { "s" }
|
|
);
|
|
|
|
// Execute each script in sorted order
|
|
for script_file in script_files {
|
|
println!("\nExecuting: {}", script_file.display());
|
|
|
|
// Read the script content
|
|
let script = fs::read_to_string(&script_file)?;
|
|
|
|
// Execute the script
|
|
// match engine.eval::<rhai::Dynamic>(&script) {
|
|
// Ok(result) => {
|
|
// println!("Script executed successfully");
|
|
// if !result.is_unit() {
|
|
// println!("Result: {}", result);
|
|
// }
|
|
// }
|
|
// Err(err) => {
|
|
// eprintln!("Error executing script: {}", err);
|
|
// // Exit with error code when a script fails
|
|
// process::exit(1);
|
|
// }
|
|
// }
|
|
engine.run_with_scope(&mut scope, &script)?;
|
|
}
|
|
|
|
println!("\nAll scripts executed successfully!");
|
|
Ok(())
|
|
}
|
|
|
|
/// Recursively collect all .rhai files from a directory
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `dir` - Directory to search
|
|
/// * `files` - Vector to collect files into
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// Result indicating success or failure
|
|
fn collect_rhai_files(dir: &Path, files: &mut Vec<PathBuf>) -> Result<(), Box<dyn Error>> {
|
|
for entry in fs::read_dir(dir)? {
|
|
let entry = entry?;
|
|
let path = entry.path();
|
|
|
|
if path.is_dir() {
|
|
// Recursively search subdirectories
|
|
collect_rhai_files(&path, files)?;
|
|
} else if path.is_file() {
|
|
// Check if it's a .rhai file
|
|
if let Some(extension) = path.extension() {
|
|
if extension == "rhai" {
|
|
files.push(path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|