sal/docs/process/process.md
2025-05-08 09:54:20 +03:00

224 lines
8.5 KiB
Markdown

# Process Module
The `process` module provides functions for running external commands and managing system processes using a builder pattern for command execution.
For running commands, you start with the `run()` function which returns a `CommandBuilder` object. You can then chain configuration methods like `silent()`, `ignore_error()`, and `log()` before finally calling the `do()` method to execute the command.
By default, command execution using the builder (`.do()`) will halt the script execution if the command itself fails (returns a non-zero exit code) or if there's an operating system error preventing the command from running. You can change this behavior with `ignore_error()`.
Other process management functions (`which`, `kill`, `process_list`, `process_get`) have specific error handling behaviors described below.
---
### `CommandResult`
An object returned by command execution functions (`.do()`) containing the result of the command.
- **Properties**:
- `stdout`: `String` - The standard output of the command.
- `stderr`: `String` - The standard error of the command.
- `success`: `Boolean` - `true` if the command exited with code 0, `false` otherwise.
- `code`: `Integer` - The exit code of the command.
```rhai
let result = run("echo hi").do();
print(`Success: ${result.success}, Output: ${result.stdout}`);
```
---
### `ProcessInfo`
An object found by process listing/getting functions (`process_list`, `process_get`) containing information about a running process.
- **Properties**:
- `pid`: `Integer` - The process ID.
- `name`: `String` - The name of the process executable.
- `memory`: `Integer` - The memory usage of the process (unit depends on the operating system, typically KB or bytes).
- `cpu`: `Float` - The CPU usage percentage (value and meaning may vary by operating system).
```rhai
let processes = process_list("my_service");
if (processes.len() > 0) {
let first_proc = processes[0];
print(`Process ${first_proc.name} (PID: ${first_proc.pid}) is running.`);
}
```
---
### `run(command)`
Start building a command execution.
- **Description**: Initializes a `CommandBuilder` for the given command string. This is the entry point to configure and run a process.
- **Returns**: `CommandBuilder` - A builder object for configuring the command.
- **Arguments**:
- `command`: `String` - The command string to execute. Can include arguments and be a simple multiline script.
```rhai
let cmd_builder = run("ls -l");
// Now you can chain methods like .silent(), .ignore_error(), .log()
```
---
### `CommandBuilder:silent()`
Configure the command to run silently.
- **Description**: Suppresses real-time standard output and standard error from being printed to the script's console during command execution. The output is still captured in the resulting `CommandResult`.
- **Returns**: `CommandBuilder` - Returns `self` for chaining.
- **Arguments**: None.
```rhai
print("Running silent command...");
run("echo This won\'t show directly").silent().do();
print("Silent command finished.");
```
---
### `CommandBuilder:ignore_error()`
Configure the command to ignore non-zero exit codes.
- **Description**: By default, the `do()` method halts script execution if the command returns a non-zero exit code. Calling `ignore_error()` prevents this. The `CommandResult` will still indicate `success: false` and contain the non-zero `code`, allowing the script to handle the command failure explicitly. OS errors preventing the command from running will still cause a halt.
- **Returns**: `CommandBuilder` - Returns `self` for chaining.
- **Arguments**: None.
```rhai
print("Running command that will fail but not halt...");
let result = run("exit 1").ignore_error().do(); // Will not halt
if (!result.success) {
print(`Command failed as expected with code: ${result.code}`);
}
```
---
### `CommandBuilder:log()`
Configure the command to log the execution details.
- **Description**: Enables logging of the command string before execution.
- **Returns**: `CommandBuilder` - Returns `self` for chaining.
- **Arguments**: None.
```rhai
print("Running command with logging...");
run("ls /tmp").log().do(); // Will print the "ls /tmp" command before running
print("Command finished.");
```
---
### `CommandBuilder:do()`
Execute the configured command.
- **Description**: Runs the command with the options set by the builder methods. Waits for the command to complete and returns the `CommandResult`. This method is the final step in the command execution builder chain. Halts based on the `ignore_error()` setting and OS errors.
- **Returns**: `CommandResult` - An object containing the output and status of the command.
- **Arguments**: None.
```rhai
print("Running command using builder...");
let command_result = run("pwd")
.log() // Log the command
.silent() // Don't print output live
.do(); // Execute and get result (halts on error by default)
print(`Command output: ${command_result.stdout}`);
// Example with multiple options
let fail_result = run("command_that_does_not_exist")
.ignore_error() // Don't halt on non-zero exit (though OS error might still halt)
.silent() // Don't print error live
.do();
if (!fail_result.success) {
print(`Failed command exited with code: ${fail_result.code} and stderr: ${fail_result.stderr}`);
}
```
---
### `which(cmd)`
Check if a command exists in the system PATH.
- **Description**: Searches the system's PATH environment variable for the executable `cmd`. This function does NOT halt if the command is not found; it returns an empty string.
- **Returns**: `String` - The full path to the command executable if found, otherwise an empty string (`""`).
- **Arguments**:
- `cmd`: `String` - The name of the command to search for (e.g., `"node"`).
```rhai
let node_path = which("node"); // Does not halt if node is not found
if (node_path != "") {
print(`Node executable found at: ${node_path}`);
} else {
print("Node executable not found in PATH.");
}
```
---
### `kill(pattern)`
Kill processes matching a pattern.
- **Description**: Terminates running processes whose names match the provided `pattern`. Uses platform-specific commands (like `pkill` or equivalent). Halts script execution on error interacting with the system process list or kill command.
- **Returns**: `String` - A success message indicating the kill attempt finished.
- **Arguments**:
- `pattern`: `String` - A pattern to match against process names (e.g., `"nginx"`).
```rhai
print("Attempting to kill processes matching 'my_service'...");
// Use with caution!
kill("my_service"); // Halts on OS error during kill attempt
print("Kill command sent.");
```
---
### `process_list(pattern)`
List processes matching a pattern (or all if pattern is empty).
- **Description**: Lists information about running processes whose names match the provided `pattern`. If `pattern` is an empty string `""`, lists all processes. Halts script execution on error interacting with the system process list. Returns an empty array if no processes match the pattern.
- **Returns**: `Array` of `ProcessInfo` - An array of objects, each containing `pid` (Integer), `name` (String), `memory` (Integer), and `cpu` (Float).
- **Arguments**:
- `pattern`: `String` - A pattern to match against process names, or `""` for all processes.
```rhai
print("Listing processes matching 'bash'...");
let bash_processes = process_list("bash"); // Halts on OS error
if (bash_processes.len() > 0) {
print("Found bash processes:");
for proc in bash_processes {
print(`- PID: ${proc.pid}, Name: ${proc.name}, CPU: ${proc.cpu}%, Memory: ${proc.memory}`);
}
} else {
print("No bash processes found.");
}
```
---
### `process_get(pattern)`
Get a single process matching the pattern (error if 0 or more than 1 match).
- **Description**: Finds exactly one running process whose name matches the provided `pattern`. Halts script execution if zero or more than one process matches the pattern, or on error interacting with the system process list.
- **Returns**: `ProcessInfo` - An object containing `pid` (Integer), `name` (String), `memory` (Integer), and `cpu` (Float).
- **Arguments**:
- `pattern`: `String` - A pattern to match against process names, expected to match exactly one process.
```rhai
let expected_service_name = "my_critical_service";
print(`Getting process info for '${expected_service_name}'...`);
// This will halt if the service isn't running, or if multiple services have this name
let service_proc_info = process_get(expected_service_name);
print(`Found process: PID ${service_proc_info.pid}, Name: ${service_proc_info.name}`);
```