use super::{
cmd::execute_rfs_command,
error::RfsError,
types::{Mount, MountType, StoreSpec},
};
use std::collections::HashMap;
#[derive(Clone)]
pub struct RfsBuilder {
source: String,
target: String,
mount_type: MountType,
options: HashMap<String, String>,
#[allow(dead_code)]
mount_id: Option<String>,
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 source(&self) -> &str {
&self.source
}
pub fn target(&self) -> &str {
&self.target
}
pub fn mount_type(&self) -> &MountType {
&self.mount_type
}
pub fn options(&self) -> &HashMap<String, String> {
&self.options
}
pub fn debug(&self) -> bool {
self.debug
}
pub fn mount(self) -> Result<Mount, RfsError> {
let mut cmd = String::from("mount -t ");
cmd.push_str(&self.mount_type.to_string());
if !self.options.is_empty() {
cmd.push_str(" -o ");
let mut first = true;
for (key, value) in &self.options {
if !first {
cmd.push_str(",");
}
cmd.push_str(key);
cmd.push_str("=");
cmd.push_str(value);
first = false;
}
}
cmd.push_str(" ");
cmd.push_str(&self.source);
cmd.push_str(" ");
cmd.push_str(&self.target);
let args: Vec<&str> = cmd.split_whitespace().collect();
let result = execute_rfs_command(&args)?;
let mount_id = result.stdout.trim().to_string();
if mount_id.is_empty() {
return Err(RfsError::MountFailed("Failed to get mount ID".to_string()));
}
Ok(Mount {
id: mount_id,
source: self.source,
target: self.target,
fs_type: self.mount_type.to_string(),
options: self
.options
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect(),
})
}
pub fn unmount(&self) -> Result<(), RfsError> {
let result = execute_rfs_command(&["unmount", &self.target])?;
if !result.success {
return Err(RfsError::UnmountFailed(format!(
"Failed to unmount {}: {}",
self.target, result.stderr
)));
}
Ok(())
}
}
#[derive(Clone)]
pub struct PackBuilder {
directory: String,
output: String,
store_specs: Vec<StoreSpec>,
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<StoreSpec>) -> Self {
self.store_specs.extend(store_specs);
self
}
pub fn with_debug(mut self, debug: bool) -> Self {
self.debug = debug;
self
}
pub fn directory(&self) -> &str {
&self.directory
}
pub fn output(&self) -> &str {
&self.output
}
pub fn store_specs(&self) -> &Vec<StoreSpec> {
&self.store_specs
}
pub fn debug(&self) -> bool {
self.debug
}
pub fn pack(self) -> Result<(), RfsError> {
let mut cmd = String::from("pack -m ");
cmd.push_str(&self.output);
if !self.store_specs.is_empty() {
cmd.push_str(" -s ");
let mut first = true;
for spec in &self.store_specs {
if !first {
cmd.push_str(",");
}
let spec_str = spec.to_string();
cmd.push_str(&spec_str);
first = false;
}
}
cmd.push_str(" ");
cmd.push_str(&self.directory);
let args: Vec<&str> = cmd.split_whitespace().collect();
let result = execute_rfs_command(&args)?;
if !result.success {
return Err(RfsError::PackFailed(format!(
"Failed to pack {}: {}",
self.directory, result.stderr
)));
}
Ok(())
}
}