# RFS Wrapper Implementation Plan ## Overview We'll create a Rust wrapper for the RFS (Remote File System) tool that follows the builder pattern, similar to the existing implementations for buildah and nerdctl in the codebase. This wrapper will provide a fluent API for mounting, unmounting, listing mounts, configuring mount options, and packing directories into filesystem layers. ## Module Structure ``` src/virt/rfs/ ├── mod.rs # Module exports and common types ├── cmd.rs # Command execution functions ├── mount.rs # Mount operations ├── pack.rs # Packing operations ├── builder.rs # Builder pattern implementation ├── types.rs # Type definitions └── error.rs # Error handling ``` ## Implementation Details ### 1. Error Handling ```rust // error.rs #[derive(Debug)] pub enum RfsError { CommandFailed(String), InvalidArgument(String), MountFailed(String), UnmountFailed(String), ListFailed(String), PackFailed(String), Other(String), } impl std::fmt::Display for RfsError { // Implementation } impl std::error::Error for RfsError { // Implementation } ``` ### 2. Command Execution ```rust // cmd.rs use crate::process::{run_command, CommandResult}; use super::error::RfsError; pub fn execute_rfs_command(args: &[&str]) -> Result { // Implementation similar to buildah and nerdctl } ``` ### 3. Types ```rust // types.rs #[derive(Debug, Clone)] pub struct Mount { pub id: String, pub source: String, pub target: String, pub fs_type: String, pub options: Vec, } #[derive(Debug, Clone)] pub enum MountType { Local, SSH, S3, WebDAV, // Other mount types } #[derive(Debug, Clone)] pub struct StoreSpec { pub spec_type: String, pub options: std::collections::HashMap, } impl StoreSpec { pub fn new(spec_type: &str) -> Self { Self { spec_type: spec_type.to_string(), options: std::collections::HashMap::new(), } } pub fn with_option(mut self, key: &str, value: &str) -> Self { self.options.insert(key.to_string(), value.to_string()); self } pub fn to_string(&self) -> String { let mut result = self.spec_type.clone(); if !self.options.is_empty() { result.push_str(":"); let options: Vec = self.options .iter() .map(|(k, v)| format!("{}={}", k, v)) .collect(); result.push_str(&options.join(",")); } result } } ``` ### 4. Builder Pattern ```rust // builder.rs use std::collections::HashMap; use super::{Mount, MountType, RfsError, execute_rfs_command, StoreSpec}; #[derive(Clone)] pub struct RfsBuilder { source: String, target: String, mount_type: MountType, options: HashMap, mount_id: Option, debug: bool, } impl RfsBuilder { pub fn new(source: &str, target: &str, mount_type: MountType) -> Self { Self { source: source.to_string(), target: target.to_string(), mount_type, options: HashMap::new(), mount_id: None, debug: false, } } pub fn with_option(mut self, key: &str, value: &str) -> Self { self.options.insert(key.to_string(), value.to_string()); self } pub fn with_options(mut self, options: HashMap<&str, &str>) -> Self { for (key, value) in options { self.options.insert(key.to_string(), value.to_string()); } self } pub fn with_debug(mut self, debug: bool) -> Self { self.debug = debug; self } pub fn mount(self) -> Result { // Implementation } pub fn unmount(&self) -> Result<(), RfsError> { // Implementation } // Other methods } // Packing functionality pub struct PackBuilder { directory: String, output: String, store_specs: Vec, debug: bool, } impl PackBuilder { pub fn new(directory: &str, output: &str) -> Self { Self { directory: directory.to_string(), output: output.to_string(), store_specs: Vec::new(), debug: false, } } pub fn with_store_spec(mut self, store_spec: StoreSpec) -> Self { self.store_specs.push(store_spec); self } pub fn with_store_specs(mut self, store_specs: Vec) -> Self { self.store_specs.extend(store_specs); self } pub fn with_debug(mut self, debug: bool) -> Self { self.debug = debug; self } pub fn pack(self) -> Result<(), RfsError> { // Implementation for packing a directory into a filesystem layer let mut args = vec!["pack"]; // Add output file args.push("-m"); args.push(&self.output); // Add store specs if !self.store_specs.is_empty() { args.push("-s"); let specs: Vec = self.store_specs .iter() .map(|spec| spec.to_string()) .collect(); args.push(&specs.join(",")); } // Add directory args.push(&self.directory); // Convert to string slices for the command let args_str: Vec<&str> = args.iter().map(|s| s.as_str()).collect(); // Execute the command let result = execute_rfs_command(&args_str)?; // Check for errors if !result.success { return Err(RfsError::PackFailed(result.stderr)); } Ok(()) } } ``` ### 5. Mount Operations ```rust // mount.rs use super::{RfsBuilder, Mount, RfsError, execute_rfs_command}; pub fn list_mounts() -> Result, RfsError> { // Implementation } pub fn unmount_all() -> Result<(), RfsError> { // Implementation } // Other mount-related functions ``` ### 6. Pack Operations ```rust // pack.rs use super::{PackBuilder, StoreSpec, RfsError, execute_rfs_command}; pub fn pack_directory(directory: &str, output: &str, store_specs: &[StoreSpec]) -> Result<(), RfsError> { PackBuilder::new(directory, output) .with_store_specs(store_specs.to_vec()) .pack() } // Other pack-related functions ``` ### 7. Module Exports ```rust // mod.rs mod cmd; mod error; mod mount; mod pack; mod builder; mod types; pub use error::RfsError; pub use builder::{RfsBuilder, PackBuilder}; pub use types::{Mount, MountType, StoreSpec}; pub use mount::{list_mounts, unmount_all}; pub use pack::pack_directory; // Re-export the execute_rfs_command function for use in other modules pub(crate) use cmd::execute_rfs_command; ``` ## Usage Examples ### Mounting Example ```rust use crate::virt::rfs::{RfsBuilder, MountType}; // Create a new RFS mount with builder pattern let mount = RfsBuilder::new("user@example.com:/remote/path", "/local/mount/point", MountType::SSH) .with_option("port", "2222") .with_option("identity_file", "/path/to/key") .with_debug(true) .mount()?; // List all mounts let mounts = list_mounts()?; for mount in mounts { println!("Mount ID: {}, Source: {}, Target: {}", mount.id, mount.source, mount.target); } // Unmount mount.unmount()?; ``` ### Packing Example ```rust use crate::virt::rfs::{PackBuilder, StoreSpec}; // Create store specifications let store_spec1 = StoreSpec::new("file") .with_option("path", "/path/to/store"); let store_spec2 = StoreSpec::new("s3") .with_option("bucket", "my-bucket") .with_option("region", "us-east-1"); // Pack a directory with builder pattern let result = PackBuilder::new("/path/to/directory", "output.fl") .with_store_spec(store_spec1) .with_store_spec(store_spec2) .with_debug(true) .pack()?; // Or use the convenience function pack_directory("/path/to/directory", "output.fl", &[store_spec1, store_spec2])?; ``` ## Rhai Integration We'll also need to create a Rhai module to expose the RFS functionality to Rhai scripts: ```rust // src/rhai/rfs.rs use rhai::{Engine, EvalAltResult, RegisterFn}; use crate::virt::rfs::{RfsBuilder, MountType, list_mounts, unmount_all, PackBuilder, StoreSpec}; pub fn register(engine: &mut Engine) -> Result<(), Box> { // Register RFS 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_pack", rfs_pack); Ok(()) } // Function implementations fn rfs_mount(source: &str, target: &str, mount_type: &str, options_map: rhai::Map) -> Result<(), Box> { // Implementation } fn rfs_unmount(target: &str) -> Result<(), Box> { // Implementation } fn rfs_list_mounts() -> Result> { // Implementation } fn rfs_unmount_all() -> Result<(), Box> { // Implementation } fn rfs_pack(directory: &str, output: &str, store_specs: &str) -> Result<(), Box> { // Implementation } ``` ## Implementation Flow Here's a diagram showing the flow of the implementation: ```mermaid classDiagram class RfsBuilder { +String source +String target +MountType mount_type +HashMap options +Option~String~ mount_id +bool debug +new(source, target, mount_type) +with_option(key, value) +with_options(options) +with_debug(debug) +mount() +unmount() } class PackBuilder { +String directory +String output +Vec~StoreSpec~ store_specs +bool debug +new(directory, output) +with_store_spec(store_spec) +with_store_specs(store_specs) +with_debug(debug) +pack() } class Mount { +String id +String source +String target +String fs_type +Vec~String~ options } class MountType { <> Local SSH S3 WebDAV } class StoreSpec { +String spec_type +HashMap options +new(spec_type) +with_option(key, value) +to_string() } class RfsError { <> CommandFailed InvalidArgument MountFailed UnmountFailed ListFailed PackFailed Other } RfsBuilder --> Mount : creates RfsBuilder --> RfsError : may throw RfsBuilder --> MountType : uses PackBuilder --> RfsError : may throw PackBuilder --> StoreSpec : uses Mount --> RfsError : may throw ``` ## Implementation Steps 1. Create the directory structure for the RFS module 2. Implement the error handling module 3. Implement the command execution module 4. Define the types for mounts, mount operations, and store specifications 5. Implement the builder pattern for RFS operations (mount and pack) 6. Implement the mount operations 7. Implement the pack operations 8. Create the module exports 9. Add Rhai integration 10. Write tests for the implementation 11. Update documentation