# SAL Process Module (`sal::process`) The `process` module in the SAL (System Abstraction Layer) library provides a robust and cross-platform interface for creating, managing, and interacting with system processes. It is divided into two main sub-modules: `run` for command and script execution, and `mgmt` for process management tasks like listing, finding, and terminating processes. ## Core Functionalities ### 1. Command and Script Execution (`run.rs`) The `run.rs` sub-module offers flexible ways to execute external commands and multi-line scripts. #### `RunBuilder` The primary interface for execution is the `RunBuilder`, obtained via `sal::process::run("your_command_or_script")`. It allows for fluent configuration: - `.die(bool)`: If `true` (default), an error is returned if the command fails. If `false`, a `CommandResult` with `success: false` is returned instead. - `.silent(bool)`: If `true` (default is `false`), suppresses `stdout` and `stderr` from being printed to the console during execution. Output is still captured in `CommandResult`. - `.async_exec(bool)`: If `true` (default is `false`), executes the command or script in a separate thread, returning an immediate placeholder `CommandResult`. - `.log(bool)`: If `true` (default is `false`), prints a log message before executing the command. - `.execute() -> Result`: Executes the configured command or script. **Input Handling**: - **Single-line commands**: Treated as a command and its arguments (e.g., `"ls -la"`). - **Multi-line scripts**: If the input string contains newline characters (`\n`), it's treated as a script. - The script content is automatically dedented. - On Unix-like systems, `#!/bin/bash -e` is prepended (if no shebang exists) to ensure the script exits on error. - A temporary script file is created, made executable, and then run. #### `CommandResult` All execution functions return a `Result`. The `CommandResult` struct contains: - `stdout: String`: Captured standard output. - `stderr: String`: Captured standard error. - `success: bool`: `true` if the command exited with a zero status code. - `code: i32`: The exit code of the command. #### Convenience Functions: - `sal::process::run_command("cmd_or_script")`: Equivalent to `run("cmd_or_script").execute()`. - `sal::process::run_silent("cmd_or_script")`: Equivalent to `run("cmd_or_script").silent(true).execute()`. #### Error Handling: - `RunError`: Enum for errors specific to command/script execution (e.g., `EmptyCommand`, `CommandExecutionFailed`, `ScriptPreparationFailed`). ### 2. Process Management (`mgmt.rs`) The `mgmt.rs` sub-module provides tools for querying and managing system processes. #### `ProcessInfo` A struct holding basic process information: - `pid: i64` - `name: String` - `memory: f64` (currently a placeholder) - `cpu: f64` (currently a placeholder) #### Functions: - `sal::process::which(command_name: &str) -> Option`: Checks if a command exists in the system's `PATH`. Returns the full path if found. ```rust if let Some(path) = sal::process::which("git") { println!("Git found at: {}", path); } ``` - `sal::process::kill(pattern: &str) -> Result`: Kills processes matching the given `pattern` (name or part of the command line). Uses `taskkill` on Windows and `pkill -f` on Unix-like systems. ```rust match sal::process::kill("my-server-proc") { Ok(msg) => println!("{}", msg), // "Successfully killed processes" or "No matching processes found" Err(e) => eprintln!("Error killing process: {}", e), } ``` - `sal::process::process_list(pattern: &str) -> Result, ProcessError>`: Lists running processes, optionally filtering by a `pattern` (substring match on name). If `pattern` is empty, lists all accessible processes. Uses `wmic` on Windows and `ps` on Unix-like systems. ```rust match sal::process::process_list("nginx") { Ok(procs) => { for p in procs { println!("PID: {}, Name: {}", p.pid, p.name); } }, Err(e) => eprintln!("Error listing processes: {}", e), } ``` - `sal::process::process_get(pattern: &str) -> Result`: Retrieves a single `ProcessInfo` for a process matching `pattern`. Returns an error if zero or multiple processes match. ```rust match sal::process::process_get("unique_process_name") { Ok(p) => println!("Found: PID {}, Name {}", p.pid, p.name), Err(sal::process::ProcessError::NoProcessFound(patt)) => eprintln!("No process like '{}'", patt), Err(sal::process::ProcessError::MultipleProcessesFound(patt, count)) => { eprintln!("Found {} processes like '{}'", count, patt); } Err(e) => eprintln!("Error: {}", e), } ``` #### Error Handling: - `ProcessError`: Enum for errors specific to process management (e.g., `CommandExecutionFailed`, `NoProcessFound`, `MultipleProcessesFound`). ## Examples ### Running a simple command ```rust use sal::process; fn main() -> Result<(), Box> { let result = process::run("echo 'Hello from SAL!'").execute()?; println!("Output: {}", result.stdout); Ok(()) } ``` ### Running a multi-line script silently ```rust use sal::process; fn main() -> Result<(), Box> { let script = r#" echo "Starting script..." date echo "Script finished." "#; let result = process::run(script).silent(true).execute()?; if result.success { println!("Script executed successfully. Output:\n{}", result.stdout); } else { eprintln!("Script failed. Error:\n{}", result.stderr); } Ok(()) } ``` ### Checking if a command exists and then running it ```rust use sal::process; fn main() -> Result<(), Box> { if process::which("figlet").is_some() { process::run("figlet 'SAL Process'").execute()?; } else { println!("Figlet not found, using echo instead:"); process::run("echo 'SAL Process'").execute()?; } Ok(()) } ```