//! Rhai wrappers for Process module functions //! //! This module provides Rhai wrappers for the functions in the Process module. use crate::process::{self, CommandResult, ProcessError, ProcessInfo, RunError}; use rhai::{Array, Dynamic, Engine, EvalAltResult, Map}; use std::clone::Clone; /// Register Process module functions with the Rhai engine /// /// # Arguments /// /// * `engine` - The Rhai engine to register the functions with /// /// # Returns /// /// * `Result<(), Box>` - Ok if registration was successful, Err otherwise pub fn register_process_module(engine: &mut Engine) -> Result<(), Box> { // Register types // register_process_types(engine)?; // Removed // Register CommandResult type and its methods engine.register_type_with_name::("CommandResult"); engine.register_get("stdout", |r: &mut CommandResult| r.stdout.clone()); engine.register_get("stderr", |r: &mut CommandResult| r.stderr.clone()); engine.register_get("success", |r: &mut CommandResult| r.success); engine.register_get("code", |r: &mut CommandResult| r.code); // Register ProcessInfo type and its methods engine.register_type_with_name::("ProcessInfo"); engine.register_get("pid", |p: &mut ProcessInfo| p.pid); engine.register_get("name", |p: &mut ProcessInfo| p.name.clone()); engine.register_get("memory", |p: &mut ProcessInfo| p.memory); engine.register_get("cpu", |p: &mut ProcessInfo| p.cpu); // Register CommandBuilder type and its methods engine.register_type_with_name::("CommandBuilder"); engine.register_fn("run", RhaiCommandBuilder::new_rhai); // This is the builder entry point engine.register_fn("silent", RhaiCommandBuilder::silent); // Method on CommandBuilder engine.register_fn("ignore_error", RhaiCommandBuilder::ignore_error); // Method on CommandBuilder engine.register_fn("log", RhaiCommandBuilder::log); // Method on CommandBuilder engine.register_fn("execute", RhaiCommandBuilder::execute_command); // Method on CommandBuilder // Register other process management functions engine.register_fn("which", which); engine.register_fn("kill", kill); engine.register_fn("process_list", process_list); engine.register_fn("process_get", process_get); // Register legacy functions for backward compatibility engine.register_fn("run_command", run_command); engine.register_fn("run_silent", run_silent); engine.register_fn("run", run_with_options); Ok(()) } // Helper functions for error conversion fn run_error_to_rhai_error(result: Result) -> Result> { result.map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Run error: {}", e).into(), rhai::Position::NONE, )) }) } // Define a Rhai-facing builder struct #[derive(Clone)] struct RhaiCommandBuilder { command: String, die_on_error: bool, is_silent: bool, enable_log: bool, } impl RhaiCommandBuilder { // Constructor function for Rhai (registered as `run`) pub fn new_rhai(command: &str) -> Self { Self { command: command.to_string(), die_on_error: true, // Default: die on error is_silent: false, enable_log: false, } } // Rhai method: .silent() pub fn silent(mut self) -> Self { self.is_silent = true; self } // Rhai method: .ignore_error() pub fn ignore_error(mut self) -> Self { self.die_on_error = false; self } // Rhai method: .log() pub fn log(mut self) -> Self { self.enable_log = true; self } // Rhai method: .execute() - Execute the command pub fn execute_command(self) -> Result> { let builder = process::run(&self.command) .die(self.die_on_error) .silent(self.is_silent) .log(self.enable_log); // Execute the command run_error_to_rhai_error(builder.execute()) } } fn process_error_to_rhai_error( result: Result, ) -> Result> { result.map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Process error: {}", e).into(), rhai::Position::NONE, )) }) } // // Process Management Function Wrappers // /// Wrapper for process::which /// /// Check if a command exists in PATH. pub fn which(cmd: &str) -> Dynamic { match process::which(cmd) { Some(path) => path.into(), None => Dynamic::UNIT, } } /// Wrapper for process::kill /// /// Kill processes matching a pattern. pub fn kill(pattern: &str) -> Result> { process_error_to_rhai_error(process::kill(pattern)) } /// Wrapper for process::process_list /// /// List processes matching a pattern (or all if pattern is empty). pub fn process_list(pattern: &str) -> Result> { let processes = process_error_to_rhai_error(process::process_list(pattern))?; // Convert Vec to Rhai Array let mut array = Array::new(); for process in processes { array.push(Dynamic::from(process)); } Ok(array) } /// Wrapper for process::process_get /// /// Get a single process matching the pattern (error if 0 or more than 1 match). pub fn process_get(pattern: &str) -> Result> { process_error_to_rhai_error(process::process_get(pattern)) } /// Legacy wrapper for process::run /// /// Run a command and return the result. pub fn run_command(cmd: &str) -> Result> { run_error_to_rhai_error(process::run(cmd).execute()) } /// Legacy wrapper for process::run with silent option /// /// Run a command silently and return the result. pub fn run_silent(cmd: &str) -> Result> { run_error_to_rhai_error(process::run(cmd).silent(true).execute()) } /// Legacy wrapper for process::run with options /// /// Run a command with options and return the result. pub fn run_with_options(cmd: &str, options: Map) -> Result> { let mut builder = process::run(cmd); // Apply options if let Some(silent) = options.get("silent") { if let Ok(silent_bool) = silent.as_bool() { builder = builder.silent(silent_bool); } } if let Some(die) = options.get("die") { if let Ok(die_bool) = die.as_bool() { builder = builder.die(die_bool); } } if let Some(log) = options.get("log") { if let Ok(log_bool) = log.as_bool() { builder = builder.log(log_bool); } } run_error_to_rhai_error(builder.execute()) }