sal/src/process/README.md
timurgordon 65e404e517
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
merge branches and document
2025-05-23 21:12:17 +03:00

151 lines
6.1 KiB
Markdown

# 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<CommandResult, RunError>`: 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<CommandResult, RunError>`. 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<String>`:
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<String, ProcessError>`:
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<Vec<ProcessInfo>, 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<ProcessInfo, ProcessError>`:
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
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(())
}
```