Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
- Add a new `sal-os` package containing OS interaction utilities. - Update workspace members to include the new package. - Add README and basic usage examples for the new package.
425 lines
13 KiB
Rust
425 lines
13 KiB
Rust
//! Rhai wrappers for OS module functions
|
|
//!
|
|
//! This module provides Rhai wrappers for the functions in the OS module.
|
|
|
|
use crate::package::PackHero;
|
|
use crate::{download as dl, fs, package};
|
|
use rhai::{Array, Engine, EvalAltResult, Position};
|
|
|
|
/// A trait for converting a Result to a Rhai-compatible error
|
|
pub trait ToRhaiError<T> {
|
|
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>>;
|
|
}
|
|
|
|
impl<T, E: std::error::Error> ToRhaiError<T> for Result<T, E> {
|
|
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
|
|
self.map_err(|e| {
|
|
Box::new(EvalAltResult::ErrorRuntime(
|
|
e.to_string().into(),
|
|
Position::NONE,
|
|
))
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Register OS module functions with the Rhai engine
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `engine` - The Rhai engine to register the functions with
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
|
|
pub fn register_os_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
|
// Register file system functions
|
|
engine.register_fn("copy", copy);
|
|
engine.register_fn("copy_bin", copy_bin);
|
|
engine.register_fn("exist", exist);
|
|
engine.register_fn("find_file", find_file);
|
|
engine.register_fn("find_files", find_files);
|
|
engine.register_fn("find_dir", find_dir);
|
|
engine.register_fn("find_dirs", find_dirs);
|
|
engine.register_fn("delete", delete);
|
|
engine.register_fn("mkdir", mkdir);
|
|
engine.register_fn("file_size", file_size);
|
|
engine.register_fn("rsync", rsync);
|
|
engine.register_fn("chdir", chdir);
|
|
engine.register_fn("file_read", file_read);
|
|
engine.register_fn("file_write", file_write);
|
|
engine.register_fn("file_write_append", file_write_append);
|
|
|
|
// Register command check functions
|
|
engine.register_fn("which", which);
|
|
engine.register_fn("cmd_ensure_exists", cmd_ensure_exists);
|
|
|
|
// Register download functions
|
|
engine.register_fn("download", download);
|
|
engine.register_fn("download_file", download_file);
|
|
engine.register_fn("download_install", download_install);
|
|
engine.register_fn("chmod_exec", chmod_exec);
|
|
|
|
// Register move function
|
|
engine.register_fn("mv", mv);
|
|
|
|
// Register package management functions
|
|
engine.register_fn("package_install", package_install);
|
|
engine.register_fn("package_remove", package_remove);
|
|
engine.register_fn("package_update", package_update);
|
|
engine.register_fn("package_upgrade", package_upgrade);
|
|
engine.register_fn("package_list", package_list);
|
|
engine.register_fn("package_search", package_search);
|
|
engine.register_fn("package_is_installed", package_is_installed);
|
|
engine.register_fn("package_set_debug", package_set_debug);
|
|
engine.register_fn("package_platform", package_platform);
|
|
|
|
// Register platform detection functions
|
|
engine.register_fn("platform_is_osx", platform_is_osx);
|
|
engine.register_fn("platform_is_linux", platform_is_linux);
|
|
engine.register_fn("platform_is_arm", platform_is_arm);
|
|
engine.register_fn("platform_is_x86", platform_is_x86);
|
|
engine.register_fn("platform_check_linux_x86", platform_check_linux_x86);
|
|
engine.register_fn("platform_check_macos_arm", platform_check_macos_arm);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
//
|
|
// File System Function Wrappers
|
|
//
|
|
|
|
/// Wrapper for fs::copy
|
|
///
|
|
/// Recursively copy a file or directory from source to destination.
|
|
pub fn copy(src: &str, dest: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::copy(src, dest).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::copy_bin
|
|
///
|
|
/// Copy a binary to the correct location based on OS and user privileges.
|
|
pub fn copy_bin(src: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::copy_bin(src).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::exist
|
|
///
|
|
/// Check if a file or directory exists.
|
|
pub fn exist(path: &str) -> bool {
|
|
fs::exist(path)
|
|
}
|
|
|
|
/// Wrapper for fs::find_file
|
|
///
|
|
/// Find a file in a directory (with support for wildcards).
|
|
pub fn find_file(dir: &str, filename: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::find_file(dir, filename).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::find_files
|
|
///
|
|
/// Find multiple files in a directory (recursive, with support for wildcards).
|
|
pub fn find_files(dir: &str, filename: &str) -> Result<Array, Box<EvalAltResult>> {
|
|
let files = fs::find_files(dir, filename).to_rhai_error()?;
|
|
|
|
// Convert Vec<String> to Rhai Array
|
|
let mut array = Array::new();
|
|
for file in files {
|
|
array.push(file.into());
|
|
}
|
|
|
|
Ok(array)
|
|
}
|
|
|
|
/// Wrapper for fs::find_dir
|
|
///
|
|
/// Find a directory in a parent directory (with support for wildcards).
|
|
pub fn find_dir(dir: &str, dirname: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::find_dir(dir, dirname).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::find_dirs
|
|
///
|
|
/// Find multiple directories in a parent directory (recursive, with support for wildcards).
|
|
pub fn find_dirs(dir: &str, dirname: &str) -> Result<Array, Box<EvalAltResult>> {
|
|
let dirs = fs::find_dirs(dir, dirname).to_rhai_error()?;
|
|
|
|
// Convert Vec<String> to Rhai Array
|
|
let mut array = Array::new();
|
|
for dir in dirs {
|
|
array.push(dir.into());
|
|
}
|
|
|
|
Ok(array)
|
|
}
|
|
|
|
/// Wrapper for fs::delete
|
|
///
|
|
/// Delete a file or directory (defensive - doesn't error if file doesn't exist).
|
|
pub fn delete(path: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::delete(path).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::mkdir
|
|
///
|
|
/// Create a directory and all parent directories (defensive - doesn't error if directory exists).
|
|
pub fn mkdir(path: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::mkdir(path).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::file_size
|
|
///
|
|
/// Get the size of a file in bytes.
|
|
pub fn file_size(path: &str) -> Result<i64, Box<EvalAltResult>> {
|
|
fs::file_size(path).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::rsync
|
|
///
|
|
/// Sync directories using rsync (or platform equivalent).
|
|
pub fn rsync(src: &str, dest: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::rsync(src, dest).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::chdir
|
|
///
|
|
/// Change the current working directory.
|
|
pub fn chdir(path: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::chdir(path).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::file_read
|
|
///
|
|
/// Read the contents of a file.
|
|
pub fn file_read(path: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::file_read(path).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::file_write
|
|
///
|
|
/// Write content to a file (creates the file if it doesn't exist, overwrites if it does).
|
|
pub fn file_write(path: &str, content: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::file_write(path, content).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::file_write_append
|
|
///
|
|
/// Append content to a file (creates the file if it doesn't exist).
|
|
pub fn file_write_append(path: &str, content: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::file_write_append(path, content).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for fs::mv
|
|
///
|
|
/// Move a file or directory from source to destination.
|
|
pub fn mv(src: &str, dest: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::mv(src, dest).to_rhai_error()
|
|
}
|
|
|
|
//
|
|
// Download Function Wrappers
|
|
//
|
|
|
|
/// Wrapper for os::download
|
|
///
|
|
/// Download a file from URL to destination using the curl command.
|
|
pub fn download(url: &str, dest: &str, min_size_kb: i64) -> Result<String, Box<EvalAltResult>> {
|
|
dl::download(url, dest, min_size_kb).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::download_file
|
|
///
|
|
/// Download a file from URL to a specific file destination using the curl command.
|
|
pub fn download_file(
|
|
url: &str,
|
|
dest: &str,
|
|
min_size_kb: i64,
|
|
) -> Result<String, Box<EvalAltResult>> {
|
|
dl::download_file(url, dest, min_size_kb).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::download_install
|
|
///
|
|
/// Download a file and install it if it's a supported package format.
|
|
pub fn download_install(url: &str, min_size_kb: i64) -> Result<String, Box<EvalAltResult>> {
|
|
dl::download_install(url, min_size_kb).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::chmod_exec
|
|
///
|
|
/// Make a file executable (equivalent to chmod +x).
|
|
pub fn chmod_exec(path: &str) -> Result<String, Box<EvalAltResult>> {
|
|
dl::chmod_exec(path).to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::which
|
|
///
|
|
/// Check if a command exists in the system PATH.
|
|
pub fn which(command: &str) -> String {
|
|
fs::which(command)
|
|
}
|
|
|
|
/// Wrapper for os::cmd_ensure_exists
|
|
///
|
|
/// Ensure that one or more commands exist in the system PATH.
|
|
/// If any command doesn't exist, an error is thrown.
|
|
pub fn cmd_ensure_exists(commands: &str) -> Result<String, Box<EvalAltResult>> {
|
|
fs::cmd_ensure_exists(commands).to_rhai_error()
|
|
}
|
|
|
|
//
|
|
// Package Management Function Wrappers
|
|
//
|
|
|
|
/// Wrapper for os::package::PackHero::install
|
|
///
|
|
/// Install a package using the system package manager.
|
|
pub fn package_install(package: &str) -> Result<String, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
hero.install(package)
|
|
.map(|_| format!("Package '{}' installed successfully", package))
|
|
.to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::package::PackHero::remove
|
|
///
|
|
/// Remove a package using the system package manager.
|
|
pub fn package_remove(package: &str) -> Result<String, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
hero.remove(package)
|
|
.map(|_| format!("Package '{}' removed successfully", package))
|
|
.to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::package::PackHero::update
|
|
///
|
|
/// Update package lists using the system package manager.
|
|
pub fn package_update() -> Result<String, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
hero.update()
|
|
.map(|_| "Package lists updated successfully".to_string())
|
|
.to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::package::PackHero::upgrade
|
|
///
|
|
/// Upgrade installed packages using the system package manager.
|
|
pub fn package_upgrade() -> Result<String, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
hero.upgrade()
|
|
.map(|_| "Packages upgraded successfully".to_string())
|
|
.to_rhai_error()
|
|
}
|
|
|
|
/// Wrapper for os::package::PackHero::list_installed
|
|
///
|
|
/// List installed packages using the system package manager.
|
|
pub fn package_list() -> Result<Array, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
let packages = hero.list_installed().to_rhai_error()?;
|
|
|
|
// Convert Vec<String> to Rhai Array
|
|
let mut array = Array::new();
|
|
for package in packages {
|
|
array.push(package.into());
|
|
}
|
|
|
|
Ok(array)
|
|
}
|
|
|
|
/// Wrapper for os::package::PackHero::search
|
|
///
|
|
/// Search for packages using the system package manager.
|
|
pub fn package_search(query: &str) -> Result<Array, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
let packages = hero.search(query).to_rhai_error()?;
|
|
|
|
// Convert Vec<String> to Rhai Array
|
|
let mut array = Array::new();
|
|
for package in packages {
|
|
array.push(package.into());
|
|
}
|
|
|
|
Ok(array)
|
|
}
|
|
|
|
/// Wrapper for os::package::PackHero::is_installed
|
|
///
|
|
/// Check if a package is installed using the system package manager.
|
|
pub fn package_is_installed(package: &str) -> Result<bool, Box<EvalAltResult>> {
|
|
let hero = PackHero::new();
|
|
hero.is_installed(package).to_rhai_error()
|
|
}
|
|
|
|
// Thread-local storage for package debug flag
|
|
thread_local! {
|
|
static PACKAGE_DEBUG: std::cell::RefCell<bool> = std::cell::RefCell::new(false);
|
|
}
|
|
|
|
/// Set the debug mode for package management operations
|
|
pub fn package_set_debug(debug: bool) -> bool {
|
|
let mut hero = PackHero::new();
|
|
hero.set_debug(debug);
|
|
|
|
// Also set the thread-local debug flag
|
|
PACKAGE_DEBUG.with(|cell| {
|
|
*cell.borrow_mut() = debug;
|
|
});
|
|
|
|
debug
|
|
}
|
|
|
|
/// Get the current platform name for package management
|
|
pub fn package_platform() -> String {
|
|
let hero = PackHero::new();
|
|
match hero.platform() {
|
|
package::Platform::Ubuntu => "Ubuntu".to_string(),
|
|
package::Platform::MacOS => "MacOS".to_string(),
|
|
package::Platform::Unknown => "Unknown".to_string(),
|
|
}
|
|
}
|
|
|
|
//
|
|
// Platform Detection Function Wrappers
|
|
//
|
|
|
|
/// Wrapper for platform::is_osx
|
|
pub fn platform_is_osx() -> bool {
|
|
crate::platform::is_osx()
|
|
}
|
|
|
|
/// Wrapper for platform::is_linux
|
|
pub fn platform_is_linux() -> bool {
|
|
crate::platform::is_linux()
|
|
}
|
|
|
|
/// Wrapper for platform::is_arm
|
|
pub fn platform_is_arm() -> bool {
|
|
crate::platform::is_arm()
|
|
}
|
|
|
|
/// Wrapper for platform::is_x86
|
|
pub fn platform_is_x86() -> bool {
|
|
crate::platform::is_x86()
|
|
}
|
|
|
|
/// Wrapper for platform::check_linux_x86
|
|
pub fn platform_check_linux_x86() -> Result<(), Box<EvalAltResult>> {
|
|
crate::platform::check_linux_x86().map_err(|e| {
|
|
Box::new(EvalAltResult::ErrorRuntime(
|
|
format!("Platform Check Error: {}", e).into(),
|
|
Position::NONE,
|
|
))
|
|
})
|
|
}
|
|
|
|
/// Wrapper for platform::check_macos_arm
|
|
pub fn platform_check_macos_arm() -> Result<(), Box<EvalAltResult>> {
|
|
crate::platform::check_macos_arm().map_err(|e| {
|
|
Box::new(EvalAltResult::ErrorRuntime(
|
|
format!("Platform Check Error: {}", e).into(),
|
|
Position::NONE,
|
|
))
|
|
})
|
|
}
|