//! Rhai wrappers for Buildah module functions //! //! This module provides Rhai wrappers for the functions in the Buildah module. use crate::buildah::{BuildahError, Builder, ContentOperations, Image}; use rhai::{Array, Dynamic, Engine, EvalAltResult}; use sal_process::CommandResult; /// Register Buildah module functions with the Rhai engine /// /// # Arguments /// /// * `engine` - The Rhai engine to register the functions with /// /// # Returns /// /// * `Result<(), Box>` - Ok if registration was successful, Err otherwise pub fn register_bah_module(engine: &mut Engine) -> Result<(), Box> { // Register types register_bah_types(engine)?; // Register Builder constructor engine.register_fn("bah_new", bah_new); // Register Builder instance methods engine.register_fn("run", builder_run); engine.register_fn("run_with_isolation", builder_run_with_isolation); engine.register_fn("copy", builder_copy); engine.register_fn("add", builder_add); engine.register_fn("commit", builder_commit); engine.register_fn("remove", builder_remove); engine.register_fn("reset", builder_reset); engine.register_fn("config", builder_config); // Register Builder instance methods for entrypoint, cmd, and content operations engine.register_fn("set_entrypoint", builder_set_entrypoint); engine.register_fn("set_cmd", builder_set_cmd); engine.register_fn("write_content", builder_write_content); engine.register_fn("read_content", builder_read_content); // Register Builder static methods engine.register_fn("images", builder_images); engine.register_fn("image_remove", builder_image_remove); engine.register_fn("image_pull", builder_image_pull); engine.register_fn("image_push", builder_image_push); engine.register_fn("image_tag", builder_image_tag); engine.register_fn("build", builder_build); Ok(()) } /// Register Buildah module types with the Rhai engine fn register_bah_types(engine: &mut Engine) -> Result<(), Box> { // Register Builder type engine.register_type_with_name::("BuildahBuilder"); // Register getters for Builder properties engine.register_get("container_id", get_builder_container_id); engine.register_get("name", get_builder_name); engine.register_get("image", get_builder_image); engine.register_get("debug_mode", get_builder_debug); engine.register_set("debug_mode", set_builder_debug); // Register Image type and methods (same as before) engine.register_type_with_name::("BuildahImage"); // Register getters for Image properties engine.register_get("id", |img: &mut Image| img.id.clone()); engine.register_get("names", |img: &mut Image| { let mut array = Array::new(); for name in &img.names { array.push(Dynamic::from(name.clone())); } array }); // Add a 'name' getter that returns the first name or a default engine.register_get("name", |img: &mut Image| { if img.names.is_empty() { "".to_string() } else { img.names[0].clone() } }); engine.register_get("size", |img: &mut Image| img.size.clone()); engine.register_get("created", |img: &mut Image| img.created.clone()); Ok(()) } // Helper functions for error conversion impl From for Box { fn from(err: BuildahError) -> Self { Box::new(EvalAltResult::ErrorRuntime( format!("Buildah error: {}", err).into(), rhai::Position::NONE, )) } } // Helper function to convert Rhai Array of pairs to a Vec of tuples fn convert_array_to_vec( options: Array, ) -> Result, Box> { let mut config_options: Vec<(String, String)> = Vec::new(); for option_pair_dynamic in options { let pair = option_pair_dynamic.into_array().map_err(|_e| { Box::new(EvalAltResult::ErrorRuntime( "Each option must be an array of [key, value]".into(), rhai::Position::NONE, )) })?; if pair.len() != 2 { return Err(Box::new(EvalAltResult::ErrorRuntime( "Each option must be an array of [key, value] with 2 elements".into(), rhai::Position::NONE, ))); } let key = pair[0].clone().into_string().map_err(|_e| { Box::new(EvalAltResult::ErrorRuntime( "Option key must be a string".into(), rhai::Position::NONE, )) })?; let value = pair[1].clone().into_string().map_err(|_e| { Box::new(EvalAltResult::ErrorRuntime( "Option value must be a string".into(), rhai::Position::NONE, )) })?; config_options.push((key, value)); } Ok(config_options) } /// Create a new Builder pub fn bah_new(name: &str, image: &str) -> Result> { Builder::new(name, image).map_err(Into::into) } // Builder instance methods pub fn builder_run( builder: &mut Builder, command: &str, ) -> Result> { builder.run(command).map_err(Into::into) } pub fn builder_run_with_isolation( builder: &mut Builder, command: &str, isolation: &str, ) -> Result> { builder .run_with_isolation(command, isolation) .map_err(Into::into) } pub fn builder_copy( builder: &mut Builder, source: &str, dest: &str, ) -> Result> { builder.copy(source, dest).map_err(Into::into) } pub fn builder_add( builder: &mut Builder, source: &str, dest: &str, ) -> Result> { builder.add(source, dest).map_err(Into::into) } pub fn builder_commit( builder: &mut Builder, image_name: &str, options: Array, ) -> Result> { let commit_options = convert_array_to_vec(options)?; builder .commit(image_name, Some(commit_options)) .map_err(Into::into) } pub fn builder_remove(builder: &mut Builder) -> Result> { builder.remove().map_err(Into::into) } pub fn builder_config( builder: &mut Builder, options: Array, ) -> Result> { let config_options = convert_array_to_vec(options)?; builder.config(config_options).map_err(Into::into) } /// Set the entrypoint for the container pub fn builder_set_entrypoint( builder: &mut Builder, entrypoint: Array, ) -> Result> { let entrypoint_vec: Vec = entrypoint .into_iter() .map(|item| item.into_string().unwrap_or_default()) .collect(); builder.set_entrypoint(entrypoint_vec).map_err(Into::into) } /// Set the default command for the container pub fn builder_set_cmd( builder: &mut Builder, cmd: Array, ) -> Result> { let cmd_vec: Vec = cmd .into_iter() .map(|item| item.into_string().unwrap_or_default()) .collect(); builder.set_cmd(cmd_vec).map_err(Into::into) } /// Write content to a file in the container pub fn builder_write_content( builder: &mut Builder, content: &str, dest_path: &str, ) -> Result> { if let Some(container_id) = builder.container_id() { ContentOperations::write_content(container_id, content, dest_path).map_err(Into::into) } else { Err(Box::new(EvalAltResult::ErrorRuntime( "No container ID available".into(), rhai::Position::NONE, ))) } } /// Read content from a file in the container pub fn builder_read_content( builder: &mut Builder, source_path: &str, ) -> Result> { if let Some(container_id) = builder.container_id() { ContentOperations::read_content(container_id, source_path).map_err(Into::into) } else { Err(Box::new(EvalAltResult::ErrorRuntime( "No container ID available".into(), rhai::Position::NONE, ))) } } // Builder static methods pub fn builder_images(_builder: &mut Builder) -> Result> { let images = Builder::images()?; // Convert Vec to Rhai Array let mut array = Array::new(); for image in images { array.push(Dynamic::from(image)); } Ok(array) } pub fn builder_image_remove( _builder: &mut Builder, image: &str, ) -> Result> { Builder::image_remove(image).map_err(Into::into) } pub fn builder_image_pull( _builder: &mut Builder, image: &str, tls_verify: bool, ) -> Result> { Builder::image_pull(image, tls_verify).map_err(Into::into) } pub fn builder_image_push( _builder: &mut Builder, image: &str, destination: &str, tls_verify: bool, ) -> Result> { Builder::image_push(image, destination, tls_verify).map_err(Into::into) } pub fn builder_image_tag( _builder: &mut Builder, image: &str, new_name: &str, ) -> Result> { Builder::image_tag(image, new_name).map_err(Into::into) } // Getter functions for Builder properties pub fn get_builder_container_id(builder: &mut Builder) -> String { match builder.container_id() { Some(id) => id.clone(), None => "".to_string(), } } pub fn get_builder_name(builder: &mut Builder) -> String { builder.name().to_string() } pub fn get_builder_image(builder: &mut Builder) -> String { builder.image().to_string() } /// Get the debug flag from a Builder pub fn get_builder_debug(builder: &mut Builder) -> bool { builder.debug() } /// Set the debug flag on a Builder pub fn set_builder_debug(builder: &mut Builder, debug: bool) { builder.set_debug(debug); } // Reset function for Builder pub fn builder_reset(builder: &mut Builder) -> Result<(), Box> { builder.reset().map_err(Into::into) } // Build function for Builder pub fn builder_build( _builder: &mut Builder, tag: &str, context_dir: &str, file: &str, isolation: &str, ) -> Result> { Builder::build(Some(tag), context_dir, file, Some(isolation)).map_err(Into::into) }