# 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> { 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> { 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> { 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.