sal/src/os/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

246 lines
12 KiB
Markdown

# SAL OS Module (`sal::os`)
The `sal::os` module provides a comprehensive suite of operating system interaction utilities. It aims to offer a cross-platform abstraction layer for common OS-level tasks, simplifying system programming in Rust.
This module is composed of three main sub-modules:
- [`fs`](#fs): File system operations.
- [`download`](#download): File downloading and basic installation.
- [`package`](#package): System package management.
## Key Design Points
The `sal::os` module is engineered with several core principles to provide a robust and developer-friendly interface for OS interactions:
- **Cross-Platform Abstraction**: A primary goal is to offer a unified API for common OS tasks, smoothing over differences between operating systems (primarily Linux and macOS). While it strives for abstraction, it leverages platform-specific tools (e.g., `rsync` on Linux, `robocopy` on Windows for `fs::copy` or `fs::rsync`; `apt` on Debian-based systems, `brew` on macOS for `package` management) for optimal performance and behavior when necessary.
- **Modular Structure**: Functionality is organized into logical sub-modules:
- `fs`: For comprehensive file and directory manipulation.
- `download`: For retrieving files from URLs, with support for extraction and basic installation.
- `package`: For interacting with system package managers.
- **Granular Error Handling**: Each sub-module features custom error enums (`FsError`, `DownloadError`, `PackageError`) to provide specific and actionable feedback, aiding in debugging and robust error management.
- **Sensible Defaults and Defensive Operations**: Many functions are designed to be "defensive," e.g., `mkdir` creates parent directories if they don't exist and doesn't fail if the directory already exists. `delete` doesn't error if the target is already gone.
- **Facade for Simplicity**: The `package` sub-module uses a `PackHero` facade to provide a simple entry point for common package operations, automatically detecting the underlying OS and package manager.
- **Rhai Scriptability**: A significant portion of the `sal::os` module's functionality is exposed to Rhai scripts via `herodo`, enabling powerful automation of OS-level tasks.
## `fs` - File System Operations
The `fs` sub-module (`sal::os::fs`) offers a robust set of functions for interacting with the file system.
**Key Features:**
* **Error Handling**: A custom `FsError` enum for detailed error reporting on file system operations.
* **File Operations**:
* `copy(src, dest)`: Copies files and directories, with support for wildcards and recursive copying. Uses platform-specific commands (`cp -R`, `robocopy /MIR`).
* `exist(path)`: Checks if a file or directory exists.
* `find_file(dir, filename_pattern)`: Finds a single file in a directory, supporting wildcards.
* `find_files(dir, filename_pattern)`: Finds multiple files in a directory, supporting wildcards.
* `file_size(path)`: Returns the size of a file in bytes.
* `file_read(path)`: Reads the entire content of a file into a string.
* `file_write(path, content)`: Writes content to a file, overwriting if it exists, and creating parent directories if needed.
* `file_write_append(path, content)`: Appends content to a file, creating it and parent directories if needed.
* **Directory Operations**:
* `find_dir(parent_dir, dirname_pattern)`: Finds a single directory within a parent directory, supporting wildcards.
* `find_dirs(parent_dir, dirname_pattern)`: Finds multiple directories recursively within a parent directory, supporting wildcards.
* `delete(path)`: Deletes files or directories.
* `mkdir(path)`: Creates a directory, including parent directories if necessary.
* `rsync(src, dest)`: Synchronizes directories using platform-specific commands (`rsync -a --delete`, `robocopy /MIR`).
* `chdir(path)`: Changes the current working directory.
* **Path Operations**:
* `mv(src, dest)`: Moves or renames files and directories. Handles cross-device moves by falling back to copy-then-delete.
* **Command Utilities**:
* `which(command_name)`: Checks if a command exists in the system's PATH and returns its path.
**Usage Example (fs):**
```rust
use sal::os::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
if !fs::exist("my_dir") {
fs::mkdir("my_dir")?;
println!("Created directory 'my_dir'");
}
fs::file_write("my_dir/example.txt", "Hello from SAL!")?;
let content = fs::file_read("my_dir/example.txt")?;
println!("File content: {}", content);
Ok(())
}
```
## `download` - File Downloading and Installation
The `download` sub-module (`sal::os::download`) provides utilities for downloading files from URLs and performing basic installation tasks.
**Key Features:**
* **Error Handling**: A custom `DownloadError` enum for download-specific errors.
* **File Downloading**:
* `download(url, dest_dir, min_size_kb)`: Downloads a file to a specified directory.
* Uses `curl` with progress display.
* Supports minimum file size checks.
* Automatically extracts common archive formats (`.tar.gz`, `.tgz`, `.tar`, `.zip`) into `dest_dir`.
* `download_file(url, dest_file_path, min_size_kb)`: Downloads a file to a specific file path without automatic extraction.
* **File Permissions**:
* `chmod_exec(path)`: Makes a file executable (equivalent to `chmod +x` on Unix-like systems).
* **Download and Install**:
* `download_install(url, min_size_kb)`: Downloads a file (to `/tmp/`) and attempts to install it if it's a supported package format.
* Currently supports `.deb` packages on Debian-based systems.
* For `.deb` files, it uses `sudo dpkg --install` and attempts `sudo apt-get install -f -y` to fix dependencies if needed.
* Handles archives by extracting them to `/tmp/` first.
**Usage Example (download):**
```rust
use sal::os::download;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let archive_url = "https://example.com/my_archive.tar.gz";
let output_dir = "/tmp/my_app";
// Download and extract an archive
let extracted_path = download::download(archive_url, output_dir, 1024)?; // Min 1MB
println!("Archive extracted to: {}", extracted_path);
// Download a script and make it executable
let script_url = "https://example.com/my_script.sh";
let script_path = "/tmp/my_script.sh";
download::download_file(script_url, script_path, 0)?;
download::chmod_exec(script_path)?;
println!("Script downloaded and made executable at: {}", script_path);
Ok(())
}
```
## `package` - System Package Management
The `package` sub-module (`sal::os::package`) offers an abstraction layer for interacting with system package managers like APT (for Debian/Ubuntu) and Homebrew (for macOS).
**Key Features:**
* **Error Handling**: A custom `PackageError` enum.
* **Platform Detection**: Identifies the current OS (Ubuntu, macOS, or Unknown) to use the appropriate package manager.
* **`PackageManager` Trait**: Defines a common interface for package operations:
* `install(package_name)`
* `remove(package_name)`
* `update()` (updates package lists)
* `upgrade()` (upgrades all installed packages)
* `list_installed()`
* `search(query)`
* `is_installed(package_name)`
* **Implementations**:
* `AptPackageManager`: For Debian/Ubuntu systems (uses `apt-get`, `dpkg`).
* `BrewPackageManager`: For macOS systems (uses `brew`).
* **`PackHero` Facade**: A simple entry point to access package management functions in a platform-agnostic way.
* `PackHero::new().install("nginx")?`
**Usage Example (package):**
```rust
use sal::os::package::PackHero;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let pack_hero = PackHero::new();
// Check if a package is installed
if !pack_hero.is_installed("htop")? {
println!("htop is not installed. Attempting to install...");
pack_hero.install("htop")?;
println!("htop installed successfully.");
} else {
println!("htop is already installed.");
}
// Update package lists
println!("Updating package lists...");
pack_hero.update()?;
println!("Package lists updated.");
Ok(())
}
```
## Rhai Scripting with `herodo`
The `sal::os` module is extensively scriptable via `herodo`, allowing for automation of various operating system tasks directly from Rhai scripts. The `sal::rhai::os` module registers the necessary functions.
### File System (`fs`) Functions
- `copy(src: String, dest: String) -> String`: Copies files/directories (supports wildcards).
- `exist(path: String) -> bool`: Checks if a file or directory exists.
- `find_file(dir: String, filename_pattern: String) -> String`: Finds a single file in `dir` matching `filename_pattern`.
- `find_files(dir: String, filename_pattern: String) -> Array`: Finds multiple files in `dir` (recursive).
- `find_dir(parent_dir: String, dirname_pattern: String) -> String`: Finds a single directory in `parent_dir`.
- `find_dirs(parent_dir: String, dirname_pattern: String) -> Array`: Finds multiple directories in `parent_dir` (recursive).
- `delete(path: String) -> String`: Deletes a file or directory.
- `mkdir(path: String) -> String`: Creates a directory (and parents if needed).
- `file_size(path: String) -> Int`: Returns file size in bytes.
- `rsync(src: String, dest: String) -> String`: Synchronizes directories.
- `chdir(path: String) -> String`: Changes the current working directory.
- `file_read(path: String) -> String`: Reads entire file content.
- `file_write(path: String, content: String) -> String`: Writes content to a file (overwrites).
- `file_write_append(path: String, content: String) -> String`: Appends content to a file.
- `mv(src: String, dest: String) -> String`: Moves/renames a file or directory.
- `which(command_name: String) -> String`: Checks if a command exists in PATH and returns its path.
- `cmd_ensure_exists(commands: String) -> String`: Ensures one or more commands (comma-separated) exist in PATH; throws an error if any are missing.
### Download Functions
- `download(url: String, dest_dir: String, min_size_kb: Int) -> String`: Downloads from `url` to `dest_dir`, extracts common archives.
- `download_file(url: String, dest_file_path: String, min_size_kb: Int) -> String`: Downloads from `url` to `dest_file_path` (no extraction).
- `download_install(url: String, min_size_kb: Int) -> String`: Downloads and attempts to install (e.g., `.deb` packages).
- `chmod_exec(path: String) -> String`: Makes a file executable (`chmod +x`).
### Package Management Functions
- `package_install(package_name: String) -> String`: Installs a package.
- `package_remove(package_name: String) -> String`: Removes a package.
- `package_update() -> String`: Updates package lists.
- `package_upgrade() -> String`: Upgrades all installed packages.
- `package_list() -> Array`: Lists all installed packages.
- `package_search(query: String) -> Array`: Searches for packages.
- `package_is_installed(package_name: String) -> bool`: Checks if a package is installed.
- `package_set_debug(debug: bool) -> bool`: Enables/disables debug logging for package operations.
- `package_platform() -> String`: Returns the detected package platform (e.g., "Ubuntu", "MacOS").
### Rhai Example
```rhai
// File system operations
let test_dir = "/tmp/sal_os_rhai_test";
if exist(test_dir) {
delete(test_dir);
}
mkdir(test_dir);
print(`Created directory: ${test_dir}`);
file_write(`${test_dir}/message.txt`, "Hello from Rhai OS module!");
let content = file_read(`${test_dir}/message.txt`);
print(`File content: ${content}`);
// Download operation (example URL, may not be active)
// let script_url = "https://raw.githubusercontent.com/someuser/somescript/main/script.sh";
// let script_path = `${test_dir}/downloaded_script.sh`;
// try {
// download_file(script_url, script_path, 0);
// chmod_exec(script_path);
// print(`Downloaded and made executable: ${script_path}`);
// } catch (e) {
// print(`Download example failed (this is okay for a test): ${e}`);
// }
// Package management (illustrative, requires sudo for install/remove/update)
print(`Package platform: ${package_platform()}`);
if !package_is_installed("htop") {
print("htop is not installed.");
// package_install("htop"); // Would require sudo
} else {
print("htop is already installed.");
}
print("OS module Rhai script finished.");
```
This module provides a powerful and convenient way to handle common OS-level tasks within your Rust applications.