...
This commit is contained in:
391
src/rhai/buildah.rs
Normal file
391
src/rhai/buildah.rs
Normal file
@@ -0,0 +1,391 @@
|
||||
//! Rhai wrappers for Buildah module functions
|
||||
//!
|
||||
//! This module provides Rhai wrappers for the functions in the Buildah module.
|
||||
|
||||
use rhai::{Engine, EvalAltResult, Array, Dynamic, Map};
|
||||
use std::collections::HashMap;
|
||||
use crate::virt::buildah::{self, BuildahError, Image};
|
||||
use crate::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_buildah_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register types
|
||||
register_buildah_types(engine)?;
|
||||
|
||||
// Register container functions
|
||||
engine.register_fn("buildah_from", from);
|
||||
engine.register_fn("buildah_run", run);
|
||||
engine.register_fn("buildah_run_with_isolation", run_with_isolation);
|
||||
engine.register_fn("buildah_copy", copy);
|
||||
engine.register_fn("buildah_add", add);
|
||||
engine.register_fn("buildah_commit", commit);
|
||||
engine.register_fn("buildah_remove", remove);
|
||||
engine.register_fn("buildah_list", list);
|
||||
engine.register_fn("buildah_build", build_with_options);
|
||||
engine.register_fn("buildah_new_build_options", new_build_options);
|
||||
|
||||
// Register image functions
|
||||
engine.register_fn("buildah_images", images);
|
||||
engine.register_fn("buildah_image_remove", image_remove);
|
||||
engine.register_fn("buildah_image_push", image_push);
|
||||
engine.register_fn("buildah_image_tag", image_tag);
|
||||
engine.register_fn("buildah_image_pull", image_pull);
|
||||
engine.register_fn("buildah_image_commit", image_commit_with_options);
|
||||
engine.register_fn("buildah_new_commit_options", new_commit_options);
|
||||
engine.register_fn("buildah_config", config_with_options);
|
||||
engine.register_fn("buildah_new_config_options", new_config_options);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Register Buildah module types with the Rhai engine
|
||||
fn register_buildah_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register Image type and methods
|
||||
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
|
||||
});
|
||||
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
|
||||
fn buildah_error_to_rhai_error<T>(result: Result<T, BuildahError>) -> Result<T, Box<EvalAltResult>> {
|
||||
result.map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Buildah error: {}", e).into(),
|
||||
rhai::Position::NONE
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new Map with default build options
|
||||
pub fn new_build_options() -> Map {
|
||||
let mut map = Map::new();
|
||||
map.insert("tag".into(), Dynamic::UNIT);
|
||||
map.insert("context_dir".into(), Dynamic::from("."));
|
||||
map.insert("file".into(), Dynamic::from("Dockerfile"));
|
||||
map.insert("isolation".into(), Dynamic::UNIT);
|
||||
map
|
||||
}
|
||||
|
||||
/// Create a new Map with default commit options
|
||||
pub fn new_commit_options() -> Map {
|
||||
let mut map = Map::new();
|
||||
map.insert("format".into(), Dynamic::UNIT);
|
||||
map.insert("squash".into(), Dynamic::from(false));
|
||||
map.insert("rm".into(), Dynamic::from(false));
|
||||
map
|
||||
}
|
||||
|
||||
/// Create a new Map for config options
|
||||
pub fn new_config_options() -> Map {
|
||||
Map::new()
|
||||
}
|
||||
|
||||
//
|
||||
// Container Function Wrappers
|
||||
//
|
||||
|
||||
/// Wrapper for buildah::from
|
||||
///
|
||||
/// Create a container from an image.
|
||||
pub fn from(image: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::from(image))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::run
|
||||
///
|
||||
/// Run a command in a container.
|
||||
pub fn run(container: &str, command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::run(container, command))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::run_with_isolation
|
||||
///
|
||||
/// Run a command in a container with specified isolation.
|
||||
pub fn run_with_isolation(container: &str, command: &str, isolation: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::run_with_isolation(container, command, isolation))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::copy
|
||||
///
|
||||
/// Copy files into a container.
|
||||
pub fn copy(container: &str, source: &str, dest: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::copy(container, source, dest))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::add
|
||||
///
|
||||
/// Add files into a container.
|
||||
pub fn add(container: &str, source: &str, dest: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::add(container, source, dest))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::commit
|
||||
///
|
||||
/// Commit a container to an image.
|
||||
pub fn commit(container: &str, image_name: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::commit(container, image_name))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::remove
|
||||
///
|
||||
/// Remove a container.
|
||||
pub fn remove(container: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::remove(container))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::list
|
||||
///
|
||||
/// List containers.
|
||||
pub fn list() -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::list())
|
||||
}
|
||||
|
||||
/// Build an image with options specified in a Map
|
||||
///
|
||||
/// This provides a builder-style interface for Rhai scripts.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// let options = buildah_new_build_options();
|
||||
/// options.tag = "my-image:latest";
|
||||
/// options.context_dir = ".";
|
||||
/// options.file = "Dockerfile";
|
||||
/// options.isolation = "chroot";
|
||||
/// let result = buildah_build(options);
|
||||
/// ```
|
||||
pub fn build_with_options(options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
// Extract options from the map
|
||||
let tag_option = match options.get("tag") {
|
||||
Some(tag) => {
|
||||
if tag.is_unit() {
|
||||
None
|
||||
} else if let Ok(tag_str) = tag.clone().into_string() {
|
||||
Some(tag_str)
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"tag must be a string".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => None
|
||||
};
|
||||
|
||||
let context_dir = match options.get("context_dir") {
|
||||
Some(dir) => {
|
||||
if let Ok(dir_str) = dir.clone().into_string() {
|
||||
dir_str
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"context_dir must be a string".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => String::from(".")
|
||||
};
|
||||
|
||||
let file = match options.get("file") {
|
||||
Some(file) => {
|
||||
if let Ok(file_str) = file.clone().into_string() {
|
||||
file_str
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"file must be a string".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => String::from("Dockerfile")
|
||||
};
|
||||
|
||||
let isolation_option = match options.get("isolation") {
|
||||
Some(isolation) => {
|
||||
if isolation.is_unit() {
|
||||
None
|
||||
} else if let Ok(isolation_str) = isolation.clone().into_string() {
|
||||
Some(isolation_str)
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"isolation must be a string".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => None
|
||||
};
|
||||
|
||||
// Convert String to &str for the function call
|
||||
let tag_ref = tag_option.as_deref();
|
||||
let isolation_ref = isolation_option.as_deref();
|
||||
|
||||
// Call the buildah build function
|
||||
buildah_error_to_rhai_error(buildah::build(tag_ref, &context_dir, &file, isolation_ref))
|
||||
}
|
||||
|
||||
//
|
||||
// Image Function Wrappers
|
||||
//
|
||||
|
||||
/// Wrapper for buildah::images
|
||||
///
|
||||
/// List images in local storage.
|
||||
pub fn images() -> Result<Array, Box<EvalAltResult>> {
|
||||
let images = buildah_error_to_rhai_error(buildah::images())?;
|
||||
|
||||
// Convert Vec<Image> to Rhai Array
|
||||
let mut array = Array::new();
|
||||
for image in images {
|
||||
array.push(Dynamic::from(image));
|
||||
}
|
||||
|
||||
Ok(array)
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::image_remove
|
||||
///
|
||||
/// Remove one or more images.
|
||||
pub fn image_remove(image: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::image_remove(image))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::image_push
|
||||
///
|
||||
/// Push an image to a registry.
|
||||
pub fn image_push(image: &str, destination: &str, tls_verify: bool) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::image_push(image, destination, tls_verify))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::image_tag
|
||||
///
|
||||
/// Add an additional name to a local image.
|
||||
pub fn image_tag(image: &str, new_name: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::image_tag(image, new_name))
|
||||
}
|
||||
|
||||
/// Wrapper for buildah::image_pull
|
||||
///
|
||||
/// Pull an image from a registry.
|
||||
pub fn image_pull(image: &str, tls_verify: bool) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
buildah_error_to_rhai_error(buildah::image_pull(image, tls_verify))
|
||||
}
|
||||
|
||||
/// Commit a container to an image with options specified in a Map
|
||||
///
|
||||
/// This provides a builder-style interface for Rhai scripts.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// let options = buildah_new_commit_options();
|
||||
/// options.format = "docker";
|
||||
/// options.squash = true;
|
||||
/// options.rm = true;
|
||||
/// let result = buildah_image_commit("my-container", "my-image:latest", options);
|
||||
/// ```
|
||||
pub fn image_commit_with_options(container: &str, image_name: &str, options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
// Extract options from the map
|
||||
let format_option = match options.get("format") {
|
||||
Some(format) => {
|
||||
if format.is_unit() {
|
||||
None
|
||||
} else if let Ok(format_str) = format.clone().into_string() {
|
||||
Some(format_str)
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"format must be a string".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => None
|
||||
};
|
||||
|
||||
let squash = match options.get("squash") {
|
||||
Some(squash) => {
|
||||
if let Ok(squash_val) = squash.clone().as_bool() {
|
||||
squash_val
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"squash must be a boolean".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => false
|
||||
};
|
||||
|
||||
let rm = match options.get("rm") {
|
||||
Some(rm) => {
|
||||
if let Ok(rm_val) = rm.clone().as_bool() {
|
||||
rm_val
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
"rm must be a boolean".into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => false
|
||||
};
|
||||
|
||||
// Convert String to &str for the function call
|
||||
let format_ref = format_option.as_deref();
|
||||
|
||||
// Call the buildah image_commit function
|
||||
buildah_error_to_rhai_error(buildah::image_commit(container, image_name, format_ref, squash, rm))
|
||||
}
|
||||
|
||||
/// Configure a container with options specified in a Map
|
||||
///
|
||||
/// This provides a builder-style interface for Rhai scripts.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rhai
|
||||
/// let options = buildah_new_config_options();
|
||||
/// options.author = "John Doe";
|
||||
/// options.cmd = "echo Hello";
|
||||
/// options.entrypoint = "/bin/sh -c";
|
||||
/// let result = buildah_config("my-container", options);
|
||||
/// ```
|
||||
pub fn config_with_options(container: &str, options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||
// Convert Rhai Map to Rust HashMap
|
||||
let mut config_options = HashMap::<String, String>::new();
|
||||
|
||||
for (key, value) in options.iter() {
|
||||
if let Ok(value_str) = value.clone().into_string() {
|
||||
// Convert SmartString to String
|
||||
config_options.insert(key.to_string(), value_str);
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Option '{}' must be a string", key).into(),
|
||||
rhai::Position::NONE
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// Call the buildah config function
|
||||
buildah_error_to_rhai_error(buildah::config(container, config_options))
|
||||
}
|
Reference in New Issue
Block a user