151 lines
6.1 KiB
Markdown
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(())
|
|
}
|
|
```
|