Skip to main content

sal_virt/rhai/
buildah.rs

1//! Rhai wrappers for Buildah module functions
2//!
3//! This module provides Rhai wrappers for the functions in the Buildah module.
4
5use crate::buildah::{BuildahError, Builder, ContentOperations, Image};
6use rhai::{Array, Dynamic, Engine, EvalAltResult, Map};
7use sal_process::CommandResult;
8use std::collections::HashMap;
9
10/// Register Buildah module functions with the Rhai engine
11///
12/// # Arguments
13///
14/// * `engine` - The Rhai engine to register the functions with
15///
16/// # Returns
17///
18/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
19pub fn register_bah_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
20    // Register types
21    register_bah_types(engine)?;
22
23    // Register Builder constructor
24    engine.register_fn("bah_new", bah_new);
25
26    // Register Builder instance methods
27    engine.register_fn("run", builder_run);
28    engine.register_fn("run_with_isolation", builder_run_with_isolation);
29    engine.register_fn("copy", builder_copy);
30    engine.register_fn("add", builder_add);
31    engine.register_fn("commit", builder_commit);
32    engine.register_fn("remove", builder_remove);
33    engine.register_fn("reset", builder_reset);
34    engine.register_fn("config", builder_config);
35    // Register Builder instance methods for entrypoint, cmd, and content operations
36    engine.register_fn("set_entrypoint", builder_set_entrypoint);
37    engine.register_fn("set_cmd", builder_set_cmd);
38    engine.register_fn("write_content", builder_write_content);
39    engine.register_fn("read_content", builder_read_content);
40
41    // Register Builder static methods
42    engine.register_fn("images", builder_images);
43    engine.register_fn("image_remove", builder_image_remove);
44    engine.register_fn("image_pull", builder_image_pull);
45    engine.register_fn("image_push", builder_image_push);
46    engine.register_fn("image_tag", builder_image_tag);
47    engine.register_fn("build", builder_build);
48    engine.register_fn("read_content", builder_read_content);
49
50    Ok(())
51}
52
53/// Register Buildah module types with the Rhai engine
54fn register_bah_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
55    // Register Builder type
56    engine.register_type_with_name::<Builder>("BuildahBuilder");
57
58    // Register getters for Builder properties
59    engine.register_get("container_id", get_builder_container_id);
60    engine.register_get("name", get_builder_name);
61    engine.register_get("image", get_builder_image);
62    engine.register_get("debug_mode", get_builder_debug);
63    engine.register_set("debug_mode", set_builder_debug);
64
65    // Register Image type and methods (same as before)
66    engine.register_type_with_name::<Image>("BuildahImage");
67
68    // Register getters for Image properties
69    engine.register_get("id", |img: &mut Image| img.id.clone());
70    engine.register_get("names", |img: &mut Image| {
71        let mut array = Array::new();
72        for name in &img.names {
73            array.push(Dynamic::from(name.clone()));
74        }
75        array
76    });
77    // Add a 'name' getter that returns the first name or a default
78    engine.register_get("name", |img: &mut Image| {
79        if img.names.is_empty() {
80            "<none>".to_string()
81        } else {
82            img.names[0].clone()
83        }
84    });
85    engine.register_get("size", |img: &mut Image| img.size.clone());
86    engine.register_get("created", |img: &mut Image| img.created.clone());
87
88    Ok(())
89}
90
91// Helper functions for error conversion
92fn bah_error_to_rhai_error<T>(result: Result<T, BuildahError>) -> Result<T, Box<EvalAltResult>> {
93    result.map_err(|e| {
94        Box::new(EvalAltResult::ErrorRuntime(
95            format!("Buildah error: {}", e).into(),
96            rhai::Position::NONE,
97        ))
98    })
99}
100
101// Helper function to convert Rhai Map to Rust HashMap
102fn convert_map_to_hashmap(options: Map) -> Result<HashMap<String, String>, Box<EvalAltResult>> {
103    let mut config_options = HashMap::<String, String>::new();
104
105    for (key, value) in options.iter() {
106        if let Ok(value_str) = value.clone().into_string() {
107            // Convert SmartString to String
108            config_options.insert(key.to_string(), value_str);
109        } else {
110            return Err(Box::new(EvalAltResult::ErrorRuntime(
111                format!("Option '{}' must be a string", key).into(),
112                rhai::Position::NONE,
113            )));
114        }
115    }
116
117    Ok(config_options)
118}
119
120/// Create a new Builder
121pub fn bah_new(name: &str, image: &str) -> Result<Builder, Box<EvalAltResult>> {
122    bah_error_to_rhai_error(Builder::new(name, image))
123}
124
125// Builder instance methods
126pub fn builder_run(
127    builder: &mut Builder,
128    command: &str,
129) -> Result<CommandResult, Box<EvalAltResult>> {
130    bah_error_to_rhai_error(builder.run(command))
131}
132
133pub fn builder_run_with_isolation(
134    builder: &mut Builder,
135    command: &str,
136    isolation: &str,
137) -> Result<CommandResult, Box<EvalAltResult>> {
138    bah_error_to_rhai_error(builder.run_with_isolation(command, isolation))
139}
140
141pub fn builder_copy(
142    builder: &mut Builder,
143    source: &str,
144    dest: &str,
145) -> Result<CommandResult, Box<EvalAltResult>> {
146    bah_error_to_rhai_error(builder.copy(source, dest))
147}
148
149pub fn builder_add(
150    builder: &mut Builder,
151    source: &str,
152    dest: &str,
153) -> Result<CommandResult, Box<EvalAltResult>> {
154    bah_error_to_rhai_error(builder.add(source, dest))
155}
156
157pub fn builder_commit(
158    builder: &mut Builder,
159    image_name: &str,
160) -> Result<CommandResult, Box<EvalAltResult>> {
161    bah_error_to_rhai_error(builder.commit(image_name))
162}
163
164pub fn builder_remove(builder: &mut Builder) -> Result<CommandResult, Box<EvalAltResult>> {
165    bah_error_to_rhai_error(builder.remove())
166}
167
168pub fn builder_config(
169    builder: &mut Builder,
170    options: Map,
171) -> Result<CommandResult, Box<EvalAltResult>> {
172    // Convert Rhai Map to Rust HashMap
173    let config_options = convert_map_to_hashmap(options)?;
174    bah_error_to_rhai_error(builder.config(config_options))
175}
176
177/// Set the entrypoint for the container
178pub fn builder_set_entrypoint(
179    builder: &mut Builder,
180    entrypoint: &str,
181) -> Result<CommandResult, Box<EvalAltResult>> {
182    bah_error_to_rhai_error(builder.set_entrypoint(entrypoint))
183}
184
185/// Set the default command for the container
186pub fn builder_set_cmd(
187    builder: &mut Builder,
188    cmd: &str,
189) -> Result<CommandResult, Box<EvalAltResult>> {
190    bah_error_to_rhai_error(builder.set_cmd(cmd))
191}
192
193/// Write content to a file in the container
194pub fn builder_write_content(
195    builder: &mut Builder,
196    content: &str,
197    dest_path: &str,
198) -> Result<CommandResult, Box<EvalAltResult>> {
199    if let Some(container_id) = builder.container_id() {
200        bah_error_to_rhai_error(ContentOperations::write_content(
201            container_id,
202            content,
203            dest_path,
204        ))
205    } else {
206        Err(Box::new(EvalAltResult::ErrorRuntime(
207            "No container ID available".into(),
208            rhai::Position::NONE,
209        )))
210    }
211}
212
213/// Read content from a file in the container
214pub fn builder_read_content(
215    builder: &mut Builder,
216    source_path: &str,
217) -> Result<String, Box<EvalAltResult>> {
218    if let Some(container_id) = builder.container_id() {
219        bah_error_to_rhai_error(ContentOperations::read_content(container_id, source_path))
220    } else {
221        Err(Box::new(EvalAltResult::ErrorRuntime(
222            "No container ID available".into(),
223            rhai::Position::NONE,
224        )))
225    }
226}
227
228// Builder static methods
229pub fn builder_images(_builder: &mut Builder) -> Result<Array, Box<EvalAltResult>> {
230    let images = bah_error_to_rhai_error(Builder::images())?;
231
232    // Convert Vec<Image> to Rhai Array
233    let mut array = Array::new();
234    for image in images {
235        array.push(Dynamic::from(image));
236    }
237
238    Ok(array)
239}
240
241pub fn builder_image_remove(
242    _builder: &mut Builder,
243    image: &str,
244) -> Result<CommandResult, Box<EvalAltResult>> {
245    bah_error_to_rhai_error(Builder::image_remove(image))
246}
247
248pub fn builder_image_pull(
249    _builder: &mut Builder,
250    image: &str,
251    tls_verify: bool,
252) -> Result<CommandResult, Box<EvalAltResult>> {
253    bah_error_to_rhai_error(Builder::image_pull(image, tls_verify))
254}
255
256pub fn builder_image_push(
257    _builder: &mut Builder,
258    image: &str,
259    destination: &str,
260    tls_verify: bool,
261) -> Result<CommandResult, Box<EvalAltResult>> {
262    bah_error_to_rhai_error(Builder::image_push(image, destination, tls_verify))
263}
264
265pub fn builder_image_tag(
266    _builder: &mut Builder,
267    image: &str,
268    new_name: &str,
269) -> Result<CommandResult, Box<EvalAltResult>> {
270    bah_error_to_rhai_error(Builder::image_tag(image, new_name))
271}
272
273// Getter functions for Builder properties
274pub fn get_builder_container_id(builder: &mut Builder) -> String {
275    match builder.container_id() {
276        Some(id) => id.clone(),
277        None => "".to_string(),
278    }
279}
280
281pub fn get_builder_name(builder: &mut Builder) -> String {
282    builder.name().to_string()
283}
284
285pub fn get_builder_image(builder: &mut Builder) -> String {
286    builder.image().to_string()
287}
288
289/// Get the debug flag from a Builder
290pub fn get_builder_debug(builder: &mut Builder) -> bool {
291    builder.debug()
292}
293
294/// Set the debug flag on a Builder
295pub fn set_builder_debug(builder: &mut Builder, debug: bool) {
296    builder.set_debug(debug);
297}
298
299// Reset function for Builder
300pub fn builder_reset(builder: &mut Builder) -> Result<(), Box<EvalAltResult>> {
301    bah_error_to_rhai_error(builder.reset())
302}
303
304// Build function for Builder
305pub fn builder_build(
306    _builder: &mut Builder,
307    tag: &str,
308    context_dir: &str,
309    file: &str,
310    isolation: &str,
311) -> Result<CommandResult, Box<EvalAltResult>> {
312    bah_error_to_rhai_error(Builder::build(
313        Some(tag),
314        context_dir,
315        file,
316        Some(isolation),
317    ))
318}