12 KiB
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
: File system operations.download
: File downloading and basic installation.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 forfs::copy
orfs::rsync
;apt
on Debian-based systems,brew
on macOS forpackage
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 aPackHero
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 viaherodo
, 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):
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
) intodest_dir
.
- Uses
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 tochmod +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 usessudo dpkg --install
and attemptssudo apt-get install -f -y
to fix dependencies if needed. - Handles archives by extracting them to
/tmp/
first.
- Currently supports
Usage Example (download):
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 (usesapt-get
,dpkg
).BrewPackageManager
: For macOS systems (usesbrew
).
PackHero
Facade: A simple entry point to access package management functions in a platform-agnostic way.PackHero::new().install("nginx")?
Usage Example (package):
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 indir
matchingfilename_pattern
.find_files(dir: String, filename_pattern: String) -> Array
: Finds multiple files indir
(recursive).find_dir(parent_dir: String, dirname_pattern: String) -> String
: Finds a single directory inparent_dir
.find_dirs(parent_dir: String, dirname_pattern: String) -> Array
: Finds multiple directories inparent_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 fromurl
todest_dir
, extracts common archives.download_file(url: String, dest_file_path: String, min_size_kb: Int) -> String
: Downloads fromurl
todest_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
// 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.