herolib_rust/virt/src/rhai/buildah.rs

343 lines
10 KiB
Rust

//! 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<EvalAltResult>>` - Ok if registration was successful, Err otherwise
pub fn register_bah_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
// 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<EvalAltResult>> {
// Register Builder type
engine.register_type_with_name::<Builder>("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::<Image>("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() {
"<none>".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<BuildahError> for Box<EvalAltResult> {
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<Vec<(String, String)>, Box<EvalAltResult>> {
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, Box<EvalAltResult>> {
Builder::new(name, image).map_err(Into::into)
}
// Builder instance methods
pub fn builder_run(
builder: &mut Builder,
command: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
builder.run(command).map_err(Into::into)
}
pub fn builder_run_with_isolation(
builder: &mut Builder,
command: &str,
isolation: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
builder
.run_with_isolation(command, isolation)
.map_err(Into::into)
}
pub fn builder_copy(
builder: &mut Builder,
source: &str,
dest: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
builder.copy(source, dest).map_err(Into::into)
}
pub fn builder_add(
builder: &mut Builder,
source: &str,
dest: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
builder.add(source, dest).map_err(Into::into)
}
pub fn builder_commit(
builder: &mut Builder,
image_name: &str,
options: Array,
) -> Result<CommandResult, Box<EvalAltResult>> {
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<CommandResult, Box<EvalAltResult>> {
builder.remove().map_err(Into::into)
}
pub fn builder_config(
builder: &mut Builder,
options: Array,
) -> Result<CommandResult, Box<EvalAltResult>> {
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<CommandResult, Box<EvalAltResult>> {
let entrypoint_vec: Vec<String> = 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<CommandResult, Box<EvalAltResult>> {
let cmd_vec: Vec<String> = 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<CommandResult, Box<EvalAltResult>> {
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<String, Box<EvalAltResult>> {
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<Array, Box<EvalAltResult>> {
let images = Builder::images()?;
// Convert Vec<Image> 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<CommandResult, Box<EvalAltResult>> {
Builder::image_remove(image).map_err(Into::into)
}
pub fn builder_image_pull(
_builder: &mut Builder,
image: &str,
tls_verify: bool,
) -> Result<CommandResult, Box<EvalAltResult>> {
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<CommandResult, Box<EvalAltResult>> {
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<CommandResult, Box<EvalAltResult>> {
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<EvalAltResult>> {
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<CommandResult, Box<EvalAltResult>> {
Builder::build(Some(tag), context_dir, file, Some(isolation)).map_err(Into::into)
}