use crate::buildah::{BuildahError, Builder, ContentOperations, Image, RemoteExecutor};
use rhai::{Array, Dynamic, Engine, EvalAltResult, Map};
use crate::process::CommandResult;
use std::collections::HashMap;
#[derive(Clone)]
pub struct Bah {
builder: Builder,
last_result: Option<CommandResult>,
}
impl Bah {
pub fn new(builder: Builder) -> Self {
Self {
builder,
last_result: None,
}
}
fn with_result(mut self, result: CommandResult) -> Self {
self.last_result = Some(result);
self
}
}
pub fn bah_fluent_new(name: &str, image: &str) -> Result<Bah, Box<EvalAltResult>> {
let builder = bah_error_to_rhai_error(Builder::new(name, image))?;
Ok(Bah::new(builder))
}
pub fn bah_fluent_new_with_executor<E: RemoteExecutor + 'static>(
name: &str,
image: &str,
executor: E,
) -> Result<Bah, Box<EvalAltResult>> {
let builder = bah_error_to_rhai_error(Builder::with_executor(name, image, executor))?;
Ok(Bah::new(builder))
}
pub fn bah_run(bah: Bah, command: &str) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.run(command))?;
Ok(bah.with_result(result))
}
pub fn bah_run_with_isolation(
bah: Bah,
command: &str,
isolation: &str,
) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.run_with_isolation(command, isolation))?;
Ok(bah.with_result(result))
}
pub fn bah_copy(bah: Bah, source: &str, dest: &str) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.copy(source, dest))?;
Ok(bah.with_result(result))
}
pub fn bah_add(bah: Bah, source: &str, dest: &str) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.add(source, dest))?;
Ok(bah.with_result(result))
}
pub fn bah_config(bah: Bah, options: Map) -> Result<Bah, Box<EvalAltResult>> {
let config_options = convert_map_to_hashmap(options)?;
let result = bah_error_to_rhai_error(bah.builder.config(config_options))?;
Ok(bah.with_result(result))
}
pub fn bah_set_entrypoint(bah: Bah, entrypoint: &str) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.set_entrypoint(entrypoint))?;
Ok(bah.with_result(result))
}
pub fn bah_set_cmd(bah: Bah, cmd: &str) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.set_cmd(cmd))?;
Ok(bah.with_result(result))
}
pub fn bah_write_content(bah: Bah, content: &str, dest_path: &str) -> Result<Bah, Box<EvalAltResult>> {
if let Some(container_id) = bah.builder.container_id() {
let result = bah_error_to_rhai_error(ContentOperations::write_content(
container_id,
content,
dest_path,
))?;
Ok(bah.with_result(result))
} else {
Err(Box::new(EvalAltResult::ErrorRuntime(
"No container ID available".into(),
rhai::Position::NONE,
)))
}
}
pub fn bah_commit(bah: Bah, image_name: &str) -> Result<Bah, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(bah.builder.commit(image_name))?;
Ok(bah.with_result(result))
}
pub fn bah_remove(bah: &mut Bah) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(bah.builder.remove())
}
pub fn bah_reset(bah: &mut Bah) -> Result<(), Box<EvalAltResult>> {
bah_error_to_rhai_error(bah.builder.reset())
}
pub fn bah_read_content(bah: &mut Bah, source_path: &str) -> Result<String, Box<EvalAltResult>> {
if let Some(container_id) = bah.builder.container_id() {
bah_error_to_rhai_error(ContentOperations::read_content(container_id, source_path))
} else {
Err(Box::new(EvalAltResult::ErrorRuntime(
"No container ID available".into(),
rhai::Position::NONE,
)))
}
}
pub fn bah_get_container_id(bah: &mut Bah) -> String {
bah.builder.container_id().cloned().unwrap_or_default()
}
pub fn bah_get_name(bah: &mut Bah) -> String {
bah.builder.name().to_string()
}
pub fn bah_get_image(bah: &mut Bah) -> String {
bah.builder.image().to_string()
}
pub fn bah_get_result(bah: &mut Bah) -> Dynamic {
match &bah.last_result {
Some(result) => Dynamic::from(result.clone()),
None => Dynamic::UNIT,
}
}
pub fn bah_get_stdout(bah: &mut Bah) -> String {
bah.last_result
.as_ref()
.map(|r| r.stdout.clone())
.unwrap_or_default()
}
pub fn bah_get_stderr(bah: &mut Bah) -> String {
bah.last_result
.as_ref()
.map(|r| r.stderr.clone())
.unwrap_or_default()
}
pub fn bah_get_success(bah: &mut Bah) -> bool {
bah.last_result.as_ref().map(|r| r.success).unwrap_or(true)
}
pub fn bah_get_code(bah: &mut Bah) -> i32 {
bah.last_result.as_ref().map(|r| r.code).unwrap_or(0)
}
pub fn bah_get_debug(bah: &mut Bah) -> bool {
bah.builder.debug()
}
pub fn bah_set_debug(bah: &mut Bah, debug: bool) {
bah.builder.set_debug(debug);
}
pub fn register_bah_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
register_bah_types(engine)?;
register_bah_fluent_api(engine)?;
engine.register_fn("bah_new", bah_new);
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);
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);
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);
engine.register_fn("read_content", builder_read_content);
Ok(())
}
fn register_bah_fluent_api(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
engine.register_type_with_name::<Bah>("Bah");
engine.register_fn("bah", bah_fluent_new);
engine.register_fn("run", bah_run);
engine.register_fn("sh", bah_run); engine.register_fn("run_with_isolation", bah_run_with_isolation);
engine.register_fn("copy", bah_copy);
engine.register_fn("add", bah_add);
engine.register_fn("config", bah_config);
engine.register_fn("set_entrypoint", bah_set_entrypoint);
engine.register_fn("entrypoint", bah_set_entrypoint); engine.register_fn("set_cmd", bah_set_cmd);
engine.register_fn("cmd", bah_set_cmd); engine.register_fn("write_content", bah_write_content);
engine.register_fn("write", bah_write_content); engine.register_fn("commit", bah_commit);
engine.register_fn("remove", bah_remove);
engine.register_fn("reset", bah_reset);
engine.register_fn("read_content", bah_read_content);
engine.register_fn("read", bah_read_content);
engine.register_get("container_id", bah_get_container_id);
engine.register_get("name", bah_get_name);
engine.register_get("image", bah_get_image);
engine.register_get("result", bah_get_result);
engine.register_get("stdout", bah_get_stdout);
engine.register_get("stderr", bah_get_stderr);
engine.register_get("success", bah_get_success);
engine.register_get("code", bah_get_code);
engine.register_get("debug", bah_get_debug);
engine.register_set("debug", bah_set_debug);
engine.register_get("debug_mode", bah_get_debug); engine.register_set("debug_mode", bah_set_debug);
Ok(())
}
fn register_bah_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
engine.register_type_with_name::<Builder>("BuildahBuilder");
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);
engine.register_type_with_name::<Image>("BuildahImage");
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("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(())
}
fn bah_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,
))
})
}
fn convert_map_to_hashmap(options: Map) -> Result<HashMap<String, String>, Box<EvalAltResult>> {
let mut config_options = HashMap::<String, String>::new();
for (key, value) in options.iter() {
if let Ok(value_str) = value.clone().into_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,
)));
}
}
Ok(config_options)
}
pub fn bah_new(name: &str, image: &str) -> Result<Builder, Box<EvalAltResult>> {
bah_error_to_rhai_error(Builder::new(name, image))
}
pub fn builder_run(
builder: &mut Builder,
command: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.run(command))
}
pub fn builder_run_with_isolation(
builder: &mut Builder,
command: &str,
isolation: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.run_with_isolation(command, isolation))
}
pub fn builder_copy(
builder: &mut Builder,
source: &str,
dest: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.copy(source, dest))
}
pub fn builder_add(
builder: &mut Builder,
source: &str,
dest: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.add(source, dest))
}
pub fn builder_commit(
builder: &mut Builder,
image_name: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.commit(image_name))
}
pub fn builder_remove(builder: &mut Builder) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.remove())
}
pub fn builder_config(
builder: &mut Builder,
options: Map,
) -> Result<CommandResult, Box<EvalAltResult>> {
let config_options = convert_map_to_hashmap(options)?;
bah_error_to_rhai_error(builder.config(config_options))
}
pub fn builder_set_entrypoint(
builder: &mut Builder,
entrypoint: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.set_entrypoint(entrypoint))
}
pub fn builder_set_cmd(
builder: &mut Builder,
cmd: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.set_cmd(cmd))
}
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() {
bah_error_to_rhai_error(ContentOperations::write_content(
container_id,
content,
dest_path,
))
} else {
Err(Box::new(EvalAltResult::ErrorRuntime(
"No container ID available".into(),
rhai::Position::NONE,
)))
}
}
pub fn builder_read_content(
builder: &mut Builder,
source_path: &str,
) -> Result<String, Box<EvalAltResult>> {
if let Some(container_id) = builder.container_id() {
bah_error_to_rhai_error(ContentOperations::read_content(container_id, source_path))
} else {
Err(Box::new(EvalAltResult::ErrorRuntime(
"No container ID available".into(),
rhai::Position::NONE,
)))
}
}
pub fn builder_images(_builder: &mut Builder) -> Result<Array, Box<EvalAltResult>> {
let images = bah_error_to_rhai_error(Builder::images())?;
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>> {
bah_error_to_rhai_error(Builder::image_remove(image))
}
pub fn builder_image_pull(
_builder: &mut Builder,
image: &str,
tls_verify: bool,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(Builder::image_pull(image, tls_verify))
}
pub fn builder_image_push(
_builder: &mut Builder,
image: &str,
destination: &str,
tls_verify: bool,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(Builder::image_push(image, destination, tls_verify))
}
pub fn builder_image_tag(
_builder: &mut Builder,
image: &str,
new_name: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(Builder::image_tag(image, new_name))
}
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()
}
pub fn get_builder_debug(builder: &mut Builder) -> bool {
builder.debug()
}
pub fn set_builder_debug(builder: &mut Builder, debug: bool) {
builder.set_debug(debug);
}
pub fn builder_reset(builder: &mut Builder) -> Result<(), Box<EvalAltResult>> {
bah_error_to_rhai_error(builder.reset())
}
pub fn builder_build(
_builder: &mut Builder,
tag: &str,
context_dir: &str,
file: &str,
isolation: &str,
) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(Builder::build(
Some(tag),
context_dir,
file,
Some(isolation),
))
}