...
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use rhai::{EvalAltResult, Position};
|
||||
use crate::os::{FsError, DownloadError};
|
||||
use crate::os::package::PackageError;
|
||||
|
||||
/// Convert a FsError to a Rhai EvalAltResult
|
||||
pub fn fs_error_to_rhai_error(err: FsError) -> Box<EvalAltResult> {
|
||||
@@ -23,6 +24,15 @@ pub fn download_error_to_rhai_error(err: DownloadError) -> Box<EvalAltResult> {
|
||||
))
|
||||
}
|
||||
|
||||
/// Convert a PackageError to a Rhai EvalAltResult
|
||||
pub fn package_error_to_rhai_error(err: PackageError) -> Box<EvalAltResult> {
|
||||
let err_msg = err.to_string();
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
err_msg.into(),
|
||||
Position::NONE
|
||||
))
|
||||
}
|
||||
|
||||
/// Register error types with the Rhai engine
|
||||
pub fn register_error_types(engine: &mut rhai::Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register helper functions for error handling
|
||||
@@ -38,6 +48,10 @@ pub fn register_error_types(engine: &mut rhai::Engine) -> Result<(), Box<EvalAlt
|
||||
format!("Download error: {}", err_msg)
|
||||
});
|
||||
|
||||
engine.register_fn("package_error_message", |err_msg: &str| -> String {
|
||||
format!("Package management error: {}", err_msg)
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -57,4 +71,10 @@ impl<T> ToRhaiError<T> for Result<T, DownloadError> {
|
||||
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
|
||||
self.map_err(download_error_to_rhai_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToRhaiError<T> for Result<T, PackageError> {
|
||||
fn to_rhai_error(self) -> Result<T, Box<EvalAltResult>> {
|
||||
self.map_err(package_error_to_rhai_error)
|
||||
}
|
||||
}
|
@@ -10,6 +10,7 @@ mod buildah;
|
||||
mod nerdctl;
|
||||
mod git;
|
||||
mod text;
|
||||
mod rfs;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -53,6 +54,9 @@ pub use nerdctl::{
|
||||
nerdctl_image_pull, nerdctl_image_commit, nerdctl_image_build
|
||||
};
|
||||
|
||||
// Re-export RFS module
|
||||
pub use rfs::register as register_rfs_module;
|
||||
|
||||
// Re-export git module
|
||||
pub use git::register_git_module;
|
||||
pub use crate::git::{GitTree, GitRepo};
|
||||
@@ -103,12 +107,16 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
|
||||
// Register Nerdctl module functions
|
||||
nerdctl::register_nerdctl_module(engine)?;
|
||||
|
||||
// Register Git module functions
|
||||
git::register_git_module(engine)?;
|
||||
|
||||
// Register Text module functions
|
||||
text::register_text_module(engine)?;
|
||||
|
||||
// Register RFS module functions
|
||||
rfs::register(engine)?;
|
||||
|
||||
// Future modules can be registered here
|
||||
|
||||
|
||||
|
292
src/rhai/rfs.rs
Normal file
292
src/rhai/rfs.rs
Normal file
@@ -0,0 +1,292 @@
|
||||
use rhai::{Engine, EvalAltResult, Map, Array};
|
||||
use crate::virt::rfs::{
|
||||
RfsBuilder, MountType, StoreSpec,
|
||||
list_mounts, unmount_all, unmount, get_mount_info,
|
||||
pack_directory, unpack, list_contents, verify
|
||||
};
|
||||
|
||||
/// Register RFS functions with the Rhai engine
|
||||
pub fn register(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register mount functions
|
||||
engine.register_fn("rfs_mount", rfs_mount);
|
||||
engine.register_fn("rfs_unmount", rfs_unmount);
|
||||
engine.register_fn("rfs_list_mounts", rfs_list_mounts);
|
||||
engine.register_fn("rfs_unmount_all", rfs_unmount_all);
|
||||
engine.register_fn("rfs_get_mount_info", rfs_get_mount_info);
|
||||
|
||||
// Register pack functions
|
||||
engine.register_fn("rfs_pack", rfs_pack);
|
||||
engine.register_fn("rfs_unpack", rfs_unpack);
|
||||
engine.register_fn("rfs_list_contents", rfs_list_contents);
|
||||
engine.register_fn("rfs_verify", rfs_verify);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mount a filesystem
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `source` - Source path or URL
|
||||
/// * `target` - Target mount point
|
||||
/// * `mount_type` - Mount type (e.g., "local", "ssh", "s3", "webdav")
|
||||
/// * `options` - Mount options as a map
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Map, Box<EvalAltResult>>` - Mount information or error
|
||||
fn rfs_mount(source: &str, target: &str, mount_type: &str, options: Map) -> Result<Map, Box<EvalAltResult>> {
|
||||
// Convert mount type string to MountType enum
|
||||
let mount_type_enum = MountType::from_string(mount_type);
|
||||
|
||||
// Create a builder
|
||||
let mut builder = RfsBuilder::new(source, target, mount_type_enum);
|
||||
|
||||
// Add options
|
||||
for (key, value) in options.iter() {
|
||||
if let Ok(value_str) = value.clone().into_string() {
|
||||
builder = builder.with_option(key, &value_str);
|
||||
}
|
||||
}
|
||||
|
||||
// Mount the filesystem
|
||||
let mount = builder.mount()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to mount filesystem: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))?;
|
||||
|
||||
// Convert Mount to Map
|
||||
let mut result = Map::new();
|
||||
result.insert("id".into(), mount.id.into());
|
||||
result.insert("source".into(), mount.source.into());
|
||||
result.insert("target".into(), mount.target.into());
|
||||
result.insert("fs_type".into(), mount.fs_type.into());
|
||||
|
||||
let options_array: Array = mount.options.iter()
|
||||
.map(|opt| opt.clone().into())
|
||||
.collect();
|
||||
result.insert("options".into(), options_array.into());
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Unmount a filesystem
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `target` - Target mount point
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<(), Box<EvalAltResult>>` - Success or error
|
||||
fn rfs_unmount(target: &str) -> Result<(), Box<EvalAltResult>> {
|
||||
unmount(target)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to unmount filesystem: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))
|
||||
}
|
||||
|
||||
/// List all mounted filesystems
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Array, Box<EvalAltResult>>` - List of mounts or error
|
||||
fn rfs_list_mounts() -> Result<Array, Box<EvalAltResult>> {
|
||||
let mounts = list_mounts()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to list mounts: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))?;
|
||||
|
||||
let mut result = Array::new();
|
||||
|
||||
for mount in mounts {
|
||||
let mut mount_map = Map::new();
|
||||
mount_map.insert("id".into(), mount.id.into());
|
||||
mount_map.insert("source".into(), mount.source.into());
|
||||
mount_map.insert("target".into(), mount.target.into());
|
||||
mount_map.insert("fs_type".into(), mount.fs_type.into());
|
||||
|
||||
let options_array: Array = mount.options.iter()
|
||||
.map(|opt| opt.clone().into())
|
||||
.collect();
|
||||
mount_map.insert("options".into(), options_array.into());
|
||||
|
||||
result.push(mount_map.into());
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Unmount all filesystems
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<(), Box<EvalAltResult>>` - Success or error
|
||||
fn rfs_unmount_all() -> Result<(), Box<EvalAltResult>> {
|
||||
unmount_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to unmount all filesystems: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))
|
||||
}
|
||||
|
||||
/// Get information about a mounted filesystem
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `target` - Target mount point
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Map, Box<EvalAltResult>>` - Mount information or error
|
||||
fn rfs_get_mount_info(target: &str) -> Result<Map, Box<EvalAltResult>> {
|
||||
let mount = get_mount_info(target)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get mount info: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))?;
|
||||
|
||||
let mut result = Map::new();
|
||||
result.insert("id".into(), mount.id.into());
|
||||
result.insert("source".into(), mount.source.into());
|
||||
result.insert("target".into(), mount.target.into());
|
||||
result.insert("fs_type".into(), mount.fs_type.into());
|
||||
|
||||
let options_array: Array = mount.options.iter()
|
||||
.map(|opt| opt.clone().into())
|
||||
.collect();
|
||||
result.insert("options".into(), options_array.into());
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Pack a directory into a filesystem layer
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `directory` - Directory to pack
|
||||
/// * `output` - Output file
|
||||
/// * `store_specs` - Store specifications as a string (e.g., "file:path=/path/to/store,s3:bucket=my-bucket")
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<(), Box<EvalAltResult>>` - Success or error
|
||||
fn rfs_pack(directory: &str, output: &str, store_specs: &str) -> Result<(), Box<EvalAltResult>> {
|
||||
// Parse store specs
|
||||
let specs = parse_store_specs(store_specs);
|
||||
|
||||
// Pack the directory
|
||||
pack_directory(directory, output, &specs)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to pack directory: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))
|
||||
}
|
||||
|
||||
/// Unpack a filesystem layer
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `input` - Input file
|
||||
/// * `directory` - Directory to unpack to
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<(), Box<EvalAltResult>>` - Success or error
|
||||
fn rfs_unpack(input: &str, directory: &str) -> Result<(), Box<EvalAltResult>> {
|
||||
unpack(input, directory)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to unpack filesystem layer: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))
|
||||
}
|
||||
|
||||
/// List the contents of a filesystem layer
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `input` - Input file
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String, Box<EvalAltResult>>` - File listing or error
|
||||
fn rfs_list_contents(input: &str) -> Result<String, Box<EvalAltResult>> {
|
||||
list_contents(input)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to list contents: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))
|
||||
}
|
||||
|
||||
/// Verify a filesystem layer
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `input` - Input file
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<bool, Box<EvalAltResult>>` - Whether the layer is valid or error
|
||||
fn rfs_verify(input: &str) -> Result<bool, Box<EvalAltResult>> {
|
||||
verify(input)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to verify filesystem layer: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
)))
|
||||
}
|
||||
|
||||
/// Parse store specifications from a string
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `specs_str` - Store specifications as a string
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Vec<StoreSpec>` - Store specifications
|
||||
fn parse_store_specs(specs_str: &str) -> Vec<StoreSpec> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Split by comma
|
||||
for spec_str in specs_str.split(',') {
|
||||
// Skip empty specs
|
||||
if spec_str.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split by colon to get type and options
|
||||
let parts: Vec<&str> = spec_str.split(':').collect();
|
||||
|
||||
if parts.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get spec type
|
||||
let spec_type = parts[0].trim();
|
||||
|
||||
// Create store spec
|
||||
let mut store_spec = StoreSpec::new(spec_type);
|
||||
|
||||
// Add options if any
|
||||
if parts.len() > 1 {
|
||||
let options_str = parts[1];
|
||||
|
||||
// Split options by comma
|
||||
for option in options_str.split(',') {
|
||||
// Split option by equals sign
|
||||
let option_parts: Vec<&str> = option.split('=').collect();
|
||||
|
||||
if option_parts.len() == 2 {
|
||||
store_spec = store_spec.with_option(option_parts[0].trim(), option_parts[1].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.push(store_spec);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
Reference in New Issue
Block a user