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

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 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):

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):

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):

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

// 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.