//! 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; 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> { 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(); // 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 = 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::(&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); } } } 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) -> Result<(), Box> { 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(()) }