...
This commit is contained in:
parent
eca7e6f552
commit
c9b4010089
@ -24,6 +24,7 @@ glob = "0.3.1" # For file pattern matching
|
|||||||
tempfile = "3.5" # For temporary file operations
|
tempfile = "3.5" # For temporary file operations
|
||||||
log = "0.4" # Logging facade
|
log = "0.4" # Logging facade
|
||||||
rhai = { version = "1.12.0", features = ["sync"] } # Embedded scripting language
|
rhai = { version = "1.12.0", features = ["sync"] } # Embedded scripting language
|
||||||
|
clap = "2.33" # Command-line argument parsing
|
||||||
|
|
||||||
# Optional features for specific OS functionality
|
# Optional features for specific OS functionality
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
@ -34,3 +35,7 @@ windows = { version = "0.48", features = ["Win32_Foundation", "Win32_System_Thre
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.5" # For tests that need temporary files/directories
|
tempfile = "3.5" # For tests that need temporary files/directories
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "herodo"
|
||||||
|
path = "src/bin/herodo.rs"
|
||||||
|
74
examples/rhai_buildah_example.rs
Normal file
74
examples/rhai_buildah_example.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//! Example of using the Rhai integration with SAL Buildah module
|
||||||
|
//!
|
||||||
|
//! This example demonstrates how to use the Rhai scripting language
|
||||||
|
//! with the System Abstraction Layer (SAL) Buildah module.
|
||||||
|
|
||||||
|
use rhai::Engine;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
// Create a new Rhai engine
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
// Register println function
|
||||||
|
engine.register_fn("println", |s: &str| println!("{}", s));
|
||||||
|
|
||||||
|
// Register SAL functions with the engine
|
||||||
|
sal::rhai::register(&mut engine)?;
|
||||||
|
|
||||||
|
// Run a Rhai script that uses SAL Buildah functions
|
||||||
|
let script = r#"
|
||||||
|
// List available images
|
||||||
|
println("Listing available images:");
|
||||||
|
let images = buildah_images();
|
||||||
|
println("Found " + images.len() + " images");
|
||||||
|
|
||||||
|
// Create a container from an image (uncomment if you have a valid image)
|
||||||
|
// let container = buildah_from("alpine:latest");
|
||||||
|
// println("Created container: " + container.stdout.trim());
|
||||||
|
|
||||||
|
// Build an image using options
|
||||||
|
let build_options = buildah_new_build_options();
|
||||||
|
build_options.tag = "example-image:latest";
|
||||||
|
build_options.context_dir = ".";
|
||||||
|
build_options.file = "example_Dockerfile";
|
||||||
|
|
||||||
|
println("Building image with options:");
|
||||||
|
println(" Tag: " + build_options.tag);
|
||||||
|
println(" Context: " + build_options.context_dir);
|
||||||
|
println(" Dockerfile: " + build_options.file);
|
||||||
|
|
||||||
|
// Uncomment to actually build the image
|
||||||
|
// let build_result = buildah_build(build_options);
|
||||||
|
// println("Build result: " + build_result.success);
|
||||||
|
|
||||||
|
// Create a container configuration
|
||||||
|
let config_options = buildah_new_config_options();
|
||||||
|
config_options.author = "Rhai Example";
|
||||||
|
config_options.cmd = "/bin/sh -c 'echo Hello from Buildah'";
|
||||||
|
|
||||||
|
println("Container config options:");
|
||||||
|
println(" Author: " + config_options.author);
|
||||||
|
println(" Command: " + config_options.cmd);
|
||||||
|
|
||||||
|
// Commit options
|
||||||
|
let commit_options = buildah_new_commit_options();
|
||||||
|
commit_options.format = "docker";
|
||||||
|
commit_options.squash = true;
|
||||||
|
commit_options.rm = true;
|
||||||
|
|
||||||
|
println("Commit options:");
|
||||||
|
println(" Format: " + commit_options.format);
|
||||||
|
println(" Squash: " + commit_options.squash);
|
||||||
|
println(" Remove container: " + commit_options.rm);
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
true
|
||||||
|
"#;
|
||||||
|
|
||||||
|
// Evaluate the script
|
||||||
|
let result = engine.eval::<bool>(script)?;
|
||||||
|
println!("Script execution successful: {}", result);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -2,9 +2,9 @@
|
|||||||
//!
|
//!
|
||||||
//! This example demonstrates how to use the Rhai scripting language
|
//! This example demonstrates how to use the Rhai scripting language
|
||||||
//! with the System Abstraction Layer (SAL) library.
|
//! with the System Abstraction Layer (SAL) library.
|
||||||
|
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
use sal::rhai;
|
use sal::rhai;
|
||||||
|
use sal::rhai::{self, Engine};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -3,65 +3,52 @@
|
|||||||
//! This example demonstrates how to use the Rhai scripting language
|
//! This example demonstrates how to use the Rhai scripting language
|
||||||
//! with the System Abstraction Layer (SAL) Process module.
|
//! with the System Abstraction Layer (SAL) Process module.
|
||||||
|
|
||||||
use rhai::{Engine, Map, Dynamic};
|
use rhai::Engine;
|
||||||
use sal::rhai;
|
use std::error::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// Create a new Rhai engine
|
// Create a new Rhai engine
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// Register SAL functions with the engine
|
// Register SAL functions with the engine
|
||||||
rhai::register(&mut engine)?;
|
sal::rhai::register(&mut engine)?;
|
||||||
|
|
||||||
// Run a Rhai script that uses SAL Process functions
|
// Run a Rhai script that uses SAL Process functions
|
||||||
let script = r#"
|
let script = r#"
|
||||||
// Check if a command exists
|
// Check if a command exists
|
||||||
let ls_exists = which("ls");
|
let ls_exists = which("ls");
|
||||||
|
println("ls command exists: " + ls_exists);
|
||||||
|
|
||||||
// Run a simple command
|
// Run a simple command
|
||||||
let echo_result = run_command("echo 'Hello from Rhai!'");
|
let echo_result = run_command("echo 'Hello from Rhai!'");
|
||||||
|
println("Echo command output: " + echo_result.stdout);
|
||||||
|
println("Echo command success: " + echo_result.success);
|
||||||
|
|
||||||
// Run a command silently
|
// Run a command silently
|
||||||
let silent_result = run_silent("ls -la");
|
let silent_result = run_silent("ls -la");
|
||||||
|
println("Silent command success: " + silent_result.success);
|
||||||
|
|
||||||
|
// Run a command with custom options using a Map
|
||||||
|
let options = new_run_options();
|
||||||
|
options["die"] = false; // Don't return error if command fails
|
||||||
|
options["silent"] = true; // Suppress output to stdout/stderr
|
||||||
|
options["async_exec"] = false; // Run synchronously
|
||||||
|
options["log"] = true; // Log command execution
|
||||||
|
|
||||||
|
let custom_result = run("echo 'Custom options'", options);
|
||||||
|
println("Custom command success: " + custom_result.success);
|
||||||
|
|
||||||
// List processes
|
// List processes
|
||||||
let processes = process_list("");
|
let processes = process_list("");
|
||||||
|
println("Number of processes: " + processes.len());
|
||||||
|
|
||||||
// Return a map with all the results
|
// Return success
|
||||||
{
|
true
|
||||||
ls_exists: ls_exists,
|
|
||||||
echo_stdout: echo_result.stdout,
|
|
||||||
echo_success: echo_result.success,
|
|
||||||
silent_success: silent_result.success,
|
|
||||||
process_count: processes.len()
|
|
||||||
}
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
// Evaluate the script and get the results
|
// Evaluate the script
|
||||||
let result = engine.eval::<Map>(script)?;
|
let result = engine.eval::<bool>(script)?;
|
||||||
|
println!("Script execution successful: {}", result);
|
||||||
// Print the results
|
|
||||||
println!("Script results:");
|
|
||||||
|
|
||||||
if let Some(ls_exists) = result.get("ls_exists") {
|
|
||||||
println!(" ls command exists: {}", ls_exists);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(echo_stdout) = result.get("echo_stdout") {
|
|
||||||
println!(" Echo command output: {}", echo_stdout.clone().into_string().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(echo_success) = result.get("echo_success") {
|
|
||||||
println!(" Echo command success: {}", echo_success.clone().as_bool().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(silent_success) = result.get("silent_success") {
|
|
||||||
println!(" Silent command success: {}", silent_success.clone().as_bool().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(process_count) = result.get("process_count") {
|
|
||||||
println!(" Number of processes: {}", process_count.clone().as_int().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
39
rhaiexamples/01_hello_world.rhai
Normal file
39
rhaiexamples/01_hello_world.rhai
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// 01_hello_world.rhai
|
||||||
|
// A simple hello world script to demonstrate basic Rhai functionality
|
||||||
|
|
||||||
|
// Print a message
|
||||||
|
println("Hello from Rhai!");
|
||||||
|
|
||||||
|
// Define a function
|
||||||
|
fn greet(name) {
|
||||||
|
"Hello, " + name + "!"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the function and print the result
|
||||||
|
let greeting = greet("SAL User");
|
||||||
|
println(greeting);
|
||||||
|
|
||||||
|
// Do some basic calculations
|
||||||
|
let a = 5;
|
||||||
|
let b = 7;
|
||||||
|
println(`${a} + ${b} = ${a + b}`);
|
||||||
|
println(`${a} * ${b} = ${a * b}`);
|
||||||
|
|
||||||
|
// Create and use an array
|
||||||
|
let numbers = [1, 2, 3, 4, 5];
|
||||||
|
println("Numbers: " + numbers);
|
||||||
|
println("Sum of numbers: " + numbers.reduce(|sum, n| sum + n, 0));
|
||||||
|
|
||||||
|
// Create and use a map
|
||||||
|
let person = #{
|
||||||
|
name: "John Doe",
|
||||||
|
age: 30,
|
||||||
|
occupation: "Developer"
|
||||||
|
};
|
||||||
|
|
||||||
|
println("Person: " + person);
|
||||||
|
println("Name: " + person.name);
|
||||||
|
println("Age: " + person.age);
|
||||||
|
|
||||||
|
// Return a success message
|
||||||
|
"Hello world script completed successfully!"
|
61
rhaiexamples/02_file_operations.rhai
Normal file
61
rhaiexamples/02_file_operations.rhai
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 02_file_operations.rhai
|
||||||
|
// Demonstrates file system operations using SAL
|
||||||
|
|
||||||
|
// Create a test directory
|
||||||
|
let test_dir = "rhai_test_dir";
|
||||||
|
println(`Creating directory: ${test_dir}`);
|
||||||
|
let mkdir_result = mkdir(test_dir);
|
||||||
|
println(`Directory creation result: ${mkdir_result}`);
|
||||||
|
|
||||||
|
// Check if the directory exists
|
||||||
|
let dir_exists = exist(test_dir);
|
||||||
|
println(`Directory exists: ${dir_exists}`);
|
||||||
|
|
||||||
|
// Create a test file
|
||||||
|
let test_file = test_dir + "/test_file.txt";
|
||||||
|
let file_content = "This is a test file created by Rhai script.";
|
||||||
|
|
||||||
|
// Create the file using a different approach
|
||||||
|
println(`Creating file: ${test_file}`);
|
||||||
|
// First ensure the directory exists
|
||||||
|
run_command(`mkdir -p ${test_dir}`);
|
||||||
|
// Then create the file using a different approach
|
||||||
|
// Use run_command with sh -c to properly handle shell features
|
||||||
|
let write_cmd = `sh -c 'touch ${test_file} && echo "${file_content}" > ${test_file}'`;
|
||||||
|
let write_result = run_command(write_cmd);
|
||||||
|
println(`File creation result: ${write_result.success}`);
|
||||||
|
|
||||||
|
// Wait a moment to ensure the file is created
|
||||||
|
run_command("sleep 1");
|
||||||
|
|
||||||
|
// Check if the file exists
|
||||||
|
let file_exists = exist(test_file);
|
||||||
|
println(`File exists: ${file_exists}`);
|
||||||
|
|
||||||
|
// Get file size
|
||||||
|
if file_exists {
|
||||||
|
let size = file_size(test_file);
|
||||||
|
println(`File size: ${size} bytes`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the file
|
||||||
|
let copied_file = test_dir + "/copied_file.txt";
|
||||||
|
println(`Copying file to: ${copied_file}`);
|
||||||
|
let copy_result = copy(test_file, copied_file);
|
||||||
|
println(`File copy result: ${copy_result}`);
|
||||||
|
|
||||||
|
// Find files in the directory
|
||||||
|
println("Finding files in the test directory:");
|
||||||
|
let files = find_files(test_dir, "*.txt");
|
||||||
|
for file in files {
|
||||||
|
println(` - ${file}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up (uncomment to actually delete the files)
|
||||||
|
// println("Cleaning up...");
|
||||||
|
// delete(copied_file);
|
||||||
|
// delete(test_file);
|
||||||
|
// delete(test_dir);
|
||||||
|
// println("Cleanup complete");
|
||||||
|
|
||||||
|
"File operations script completed successfully!"
|
64
rhaiexamples/03_process_management.rhai
Normal file
64
rhaiexamples/03_process_management.rhai
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// 03_process_management.rhai
|
||||||
|
// Demonstrates process management operations using SAL
|
||||||
|
|
||||||
|
// Check if common commands exist
|
||||||
|
println("Checking if common commands exist:");
|
||||||
|
let commands = ["ls", "echo", "cat", "grep"];
|
||||||
|
for cmd in commands {
|
||||||
|
let exists = which(cmd);
|
||||||
|
println(` - ${cmd}: ${exists}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a simple command
|
||||||
|
println("\nRunning a simple echo command:");
|
||||||
|
let echo_result = run_command("echo 'Hello from Rhai process management!'");
|
||||||
|
println(`Command output: ${echo_result.stdout}`);
|
||||||
|
// The CommandResult type doesn't have an exit_code property
|
||||||
|
println(`Success: ${echo_result.success}`);
|
||||||
|
|
||||||
|
// Run a command silently (no output to console)
|
||||||
|
println("\nRunning a command silently:");
|
||||||
|
let silent_result = run_silent("ls -la");
|
||||||
|
println(`Command success: ${silent_result.success}`);
|
||||||
|
println(`Command output length: ${silent_result.stdout.len()} characters`);
|
||||||
|
|
||||||
|
// Create custom run options
|
||||||
|
println("\nRunning a command with custom options:");
|
||||||
|
let options = new_run_options();
|
||||||
|
options["die"] = false; // Don't return error if command fails
|
||||||
|
options["silent"] = true; // Suppress output to stdout/stderr
|
||||||
|
options["async_exec"] = false; // Run synchronously
|
||||||
|
options["log"] = true; // Log command execution
|
||||||
|
|
||||||
|
let custom_result = run("echo 'Custom options test'", options);
|
||||||
|
println(`Command success: ${custom_result.success}`);
|
||||||
|
println(`Command output: ${custom_result.stdout}`);
|
||||||
|
|
||||||
|
// List processes
|
||||||
|
println("\nListing processes (limited to 5):");
|
||||||
|
let processes = process_list("");
|
||||||
|
let count = 0;
|
||||||
|
for proc in processes {
|
||||||
|
if count >= 5 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Just print the PID since we're not sure what other properties are available
|
||||||
|
println(` - PID: ${proc.pid}`);
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
println(`Total processes: ${processes.len()}`);
|
||||||
|
|
||||||
|
// Run a command that will create a background process
|
||||||
|
// Note: This is just for demonstration, the process will be short-lived
|
||||||
|
println("\nRunning a background process:");
|
||||||
|
let bg_options = new_run_options();
|
||||||
|
bg_options["async_exec"] = true;
|
||||||
|
// Fix the command to avoid issues with shell interpretation
|
||||||
|
let bg_result = run("sleep 1", bg_options);
|
||||||
|
println("Background process started");
|
||||||
|
|
||||||
|
// Wait a moment to let the background process run
|
||||||
|
run_command("sleep 0.5");
|
||||||
|
println("Main script continuing while background process runs");
|
||||||
|
|
||||||
|
"Process management script completed successfully!"
|
112
rhaiexamples/04_buildah_operations.rhai
Normal file
112
rhaiexamples/04_buildah_operations.rhai
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 04_buildah_operations.rhai
|
||||||
|
// Demonstrates container operations using SAL's buildah integration
|
||||||
|
// Note: This script requires buildah to be installed and may need root privileges
|
||||||
|
|
||||||
|
// Check if buildah is installed
|
||||||
|
let buildah_exists = which("buildah");
|
||||||
|
println(`Buildah exists: ${buildah_exists}`);
|
||||||
|
|
||||||
|
// List available images (only if buildah is installed)
|
||||||
|
println("Listing available container images:");
|
||||||
|
if buildah_exists != "" {
|
||||||
|
// This try/catch block will handle any errors that might occur
|
||||||
|
// when trying to use buildah functions
|
||||||
|
try {
|
||||||
|
let images = buildah_images();
|
||||||
|
println(`Found ${images.len()} images`);
|
||||||
|
|
||||||
|
// Print image details (limited to 3)
|
||||||
|
let count = 0;
|
||||||
|
for img in images {
|
||||||
|
if count >= 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
println(` - ID: ${img.id}, Name: ${img.name}, Created: ${img.created}`);
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
println(`Error accessing buildah: ${err}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("Buildah is not installed. Skipping container image operations.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the duplicate code that was causing the error
|
||||||
|
|
||||||
|
// The following operations are commented out as they require buildah to be installed
|
||||||
|
// and may need root privileges. Uncomment them if you want to try them out.
|
||||||
|
|
||||||
|
// Create a container from an image
|
||||||
|
// println("\nCreating a container from alpine image:");
|
||||||
|
// let container = from("alpine:latest");
|
||||||
|
// println(`Container ID: ${container.stdout.trim()}`);
|
||||||
|
|
||||||
|
// Run a command in the container
|
||||||
|
// println("\nRunning a command in the container:");
|
||||||
|
// let run_result = run(container.stdout.trim(), "echo 'Hello from container'");
|
||||||
|
// println(`Command output: ${run_result.stdout}`);
|
||||||
|
|
||||||
|
// Add a file to the container
|
||||||
|
// println("\nAdding a file to the container:");
|
||||||
|
// let test_file = "test_file.txt";
|
||||||
|
// run_command(`echo "Test content" > ${test_file}`);
|
||||||
|
// let add_result = add(container.stdout.trim(), test_file, "/");
|
||||||
|
// println(`Add result: ${add_result.success}`);
|
||||||
|
|
||||||
|
// Commit the container to create a new image
|
||||||
|
// println("\nCommitting the container to create a new image:");
|
||||||
|
// let commit_result = commit(container.stdout.trim(), "my-custom-image:latest");
|
||||||
|
// println(`Commit result: ${commit_result.success}`);
|
||||||
|
|
||||||
|
// Remove the container
|
||||||
|
// println("\nRemoving the container:");
|
||||||
|
// let remove_result = remove(container.stdout.trim());
|
||||||
|
// println(`Remove result: ${remove_result.success}`);
|
||||||
|
|
||||||
|
// Clean up the test file
|
||||||
|
// delete(test_file);
|
||||||
|
|
||||||
|
// Only demonstrate buildah options if buildah is installed
|
||||||
|
if buildah_exists != "" {
|
||||||
|
try {
|
||||||
|
// Demonstrate build options
|
||||||
|
println("\nDemonstrating build options:");
|
||||||
|
let build_options = buildah_new_build_options();
|
||||||
|
build_options.tag = "example-image:latest";
|
||||||
|
build_options.context_dir = ".";
|
||||||
|
build_options.file = "example_Dockerfile";
|
||||||
|
|
||||||
|
println("Build options configured:");
|
||||||
|
println(` - Tag: ${build_options.tag}`);
|
||||||
|
println(` - Context: ${build_options.context_dir}`);
|
||||||
|
println(` - Dockerfile: ${build_options.file}`);
|
||||||
|
|
||||||
|
// Demonstrate commit options
|
||||||
|
println("\nDemonstrating commit options:");
|
||||||
|
let commit_options = buildah_new_commit_options();
|
||||||
|
commit_options.format = "docker";
|
||||||
|
commit_options.squash = true;
|
||||||
|
commit_options.rm = true;
|
||||||
|
|
||||||
|
println("Commit options configured:");
|
||||||
|
println(` - Format: ${commit_options.format}`);
|
||||||
|
println(` - Squash: ${commit_options.squash}`);
|
||||||
|
println(` - Remove container: ${commit_options.rm}`);
|
||||||
|
|
||||||
|
// Demonstrate config options
|
||||||
|
println("\nDemonstrating config options:");
|
||||||
|
let config_options = buildah_new_config_options();
|
||||||
|
config_options.author = "Rhai Example";
|
||||||
|
config_options.cmd = "/bin/sh -c 'echo Hello from Buildah'";
|
||||||
|
|
||||||
|
println("Config options configured:");
|
||||||
|
println(` - Author: ${config_options.author}`);
|
||||||
|
println(` - Command: ${config_options.cmd}`);
|
||||||
|
} catch(err) {
|
||||||
|
println(`Error accessing buildah options: ${err}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println("\nSkipping buildah options demonstration since buildah is not installed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
"Buildah operations script completed successfully!"
|
30
src/bin/herodo.rs
Normal file
30
src/bin/herodo.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//! Herodo binary entry point
|
||||||
|
//!
|
||||||
|
//! This is the main entry point for the herodo binary.
|
||||||
|
//! It parses command line arguments and calls into the implementation in the cmd module.
|
||||||
|
|
||||||
|
use clap::{App, Arg};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Parse command line arguments
|
||||||
|
let matches = App::new("herodo")
|
||||||
|
.version("0.1.0")
|
||||||
|
.author("SAL Team")
|
||||||
|
.about("Executes Rhai scripts for SAL")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("path")
|
||||||
|
.short("p")
|
||||||
|
.long("path")
|
||||||
|
.value_name("PATH")
|
||||||
|
.help("Path to directory containing Rhai scripts")
|
||||||
|
.required(true)
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
// Get the script path from arguments
|
||||||
|
let script_path = matches.value_of("path").unwrap();
|
||||||
|
|
||||||
|
// Call the run function from the cmd module
|
||||||
|
sal::cmd::herodo::run(script_path)
|
||||||
|
}
|
84
src/cmd/herodo.rs
Normal file
84
src/cmd/herodo.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//! Herodo - A Rhai script executor for SAL
|
||||||
|
//!
|
||||||
|
//! This binary loads the Rhai engine, registers all SAL modules,
|
||||||
|
//! and executes Rhai scripts from a specified directory in sorted order.
|
||||||
|
|
||||||
|
// Removed unused imports
|
||||||
|
use rhai::Engine;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
/// Run the herodo script executor with the given script path
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `script_path` - Path to the directory containing Rhai scripts
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// Result indicating success or failure
|
||||||
|
pub fn run(script_path: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let script_dir = Path::new(script_path);
|
||||||
|
|
||||||
|
// Check if the directory exists
|
||||||
|
if !script_dir.exists() || !script_dir.is_dir() {
|
||||||
|
eprintln!("Error: '{}' is not a valid directory", script_path);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new Rhai engine
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
// Register println function for output
|
||||||
|
engine.register_fn("println", |s: &str| println!("{}", s));
|
||||||
|
|
||||||
|
// Register all SAL modules with the engine
|
||||||
|
crate::rhai::register(&mut engine)?;
|
||||||
|
|
||||||
|
// Find all .rhai files in the directory
|
||||||
|
let mut script_files: Vec<PathBuf> = fs::read_dir(script_dir)?
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.filter(|entry| {
|
||||||
|
entry.path().is_file() &&
|
||||||
|
entry.path().extension().map_or(false, |ext| ext == "rhai")
|
||||||
|
})
|
||||||
|
.map(|entry| entry.path())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Sort the script files by name
|
||||||
|
script_files.sort();
|
||||||
|
|
||||||
|
if script_files.is_empty() {
|
||||||
|
println!("No Rhai scripts found in '{}'", script_path);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Found {} Rhai scripts to execute:", script_files.len());
|
||||||
|
|
||||||
|
// Execute each script in sorted order
|
||||||
|
for script_file in script_files {
|
||||||
|
println!("\nExecuting: {}", script_file.display());
|
||||||
|
|
||||||
|
// Read the script content
|
||||||
|
let script = fs::read_to_string(&script_file)?;
|
||||||
|
|
||||||
|
// Execute the script
|
||||||
|
match engine.eval::<rhai::Dynamic>(&script) {
|
||||||
|
Ok(result) => {
|
||||||
|
println!("Script executed successfully");
|
||||||
|
if !result.is_unit() {
|
||||||
|
println!("Result: {}", result);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Error executing script: {}", err);
|
||||||
|
// Continue with the next script instead of stopping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("\nAll scripts executed");
|
||||||
|
Ok(())
|
||||||
|
}
|
5
src/cmd/mod.rs
Normal file
5
src/cmd/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//! Command-line tools for SAL
|
||||||
|
//!
|
||||||
|
//! This module contains command-line tools built on top of the SAL library.
|
||||||
|
|
||||||
|
pub mod herodo;
|
@ -43,6 +43,7 @@ pub mod redisclient;
|
|||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod virt;
|
pub mod virt;
|
||||||
pub mod rhai;
|
pub mod rhai;
|
||||||
|
pub mod cmd;
|
||||||
|
|
||||||
// Version information
|
// Version information
|
||||||
/// Returns the version of the SAL library
|
/// Returns the version of the SAL library
|
||||||
|
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))
|
||||||
|
}
|
@ -6,15 +6,49 @@
|
|||||||
mod error;
|
mod error;
|
||||||
mod os;
|
mod os;
|
||||||
mod process;
|
mod process;
|
||||||
|
mod buildah;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use rhai::Engine;
|
// Re-export common Rhai types for convenience
|
||||||
|
pub use rhai::{Array, Dynamic, Map, EvalAltResult, Engine};
|
||||||
|
|
||||||
|
// Re-export error module
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use os::*;
|
|
||||||
pub use process::*;
|
// Re-export specific functions from modules to avoid name conflicts
|
||||||
|
pub use os::{
|
||||||
|
register_os_module,
|
||||||
|
// File system functions
|
||||||
|
exist, find_file, find_files, find_dir, find_dirs,
|
||||||
|
delete, mkdir, file_size, rsync,
|
||||||
|
// Download functions
|
||||||
|
download, download_install
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use process::{
|
||||||
|
register_process_module,
|
||||||
|
// Run functions
|
||||||
|
run_command, run_silent, run_with_options, new_run_options,
|
||||||
|
// Process management functions
|
||||||
|
which, kill, process_list, process_get
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use buildah::{
|
||||||
|
register_buildah_module,
|
||||||
|
// Container functions
|
||||||
|
from, run, run_with_isolation, add, commit, remove, list,
|
||||||
|
build_with_options, new_build_options,
|
||||||
|
// Image functions
|
||||||
|
images, image_remove, image_push, image_tag, image_pull,
|
||||||
|
image_commit_with_options, new_commit_options,
|
||||||
|
config_with_options, new_config_options
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rename copy functions to avoid conflicts
|
||||||
|
pub use os::copy as os_copy;
|
||||||
|
pub use buildah::copy as buildah_copy;
|
||||||
|
|
||||||
/// Register all SAL modules with the Rhai engine
|
/// Register all SAL modules with the Rhai engine
|
||||||
///
|
///
|
||||||
@ -41,6 +75,9 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
|
|||||||
// Register Process module functions
|
// Register Process module functions
|
||||||
process::register_process_module(engine)?;
|
process::register_process_module(engine)?;
|
||||||
|
|
||||||
|
// Register Buildah module functions
|
||||||
|
buildah::register_buildah_module(engine)?;
|
||||||
|
|
||||||
// Future modules can be registered here
|
// Future modules can be registered here
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! This module provides Rhai wrappers for the functions in the Process module.
|
//! This module provides Rhai wrappers for the functions in the Process module.
|
||||||
|
|
||||||
use rhai::{Engine, EvalAltResult, Array, Dynamic};
|
use rhai::{Engine, EvalAltResult, Array, Dynamic, Map};
|
||||||
use crate::process::{self, CommandResult, ProcessInfo, RunError, ProcessError};
|
use crate::process::{self, CommandResult, ProcessInfo, RunError, ProcessError};
|
||||||
|
|
||||||
/// Register Process module functions with the Rhai engine
|
/// Register Process module functions with the Rhai engine
|
||||||
@ -21,6 +21,8 @@ pub fn register_process_module(engine: &mut Engine) -> Result<(), Box<EvalAltRes
|
|||||||
// Register run functions
|
// Register run functions
|
||||||
engine.register_fn("run_command", run_command);
|
engine.register_fn("run_command", run_command);
|
||||||
engine.register_fn("run_silent", run_silent);
|
engine.register_fn("run_silent", run_silent);
|
||||||
|
engine.register_fn("run", run_with_options);
|
||||||
|
engine.register_fn("new_run_options", new_run_options);
|
||||||
|
|
||||||
// Register process management functions
|
// Register process management functions
|
||||||
engine.register_fn("which", which);
|
engine.register_fn("which", which);
|
||||||
@ -51,9 +53,6 @@ fn register_process_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>>
|
|||||||
engine.register_get("memory", |p: &mut ProcessInfo| p.memory);
|
engine.register_get("memory", |p: &mut ProcessInfo| p.memory);
|
||||||
engine.register_get("cpu", |p: &mut ProcessInfo| p.cpu);
|
engine.register_get("cpu", |p: &mut ProcessInfo| p.cpu);
|
||||||
|
|
||||||
// Register error conversion functions
|
|
||||||
engine.register_fn("to_string", |err: &str| err.to_string());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +75,16 @@ fn process_error_to_rhai_error<T>(result: Result<T, ProcessError>) -> Result<T,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new Map with default run options
|
||||||
|
pub fn new_run_options() -> Map {
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("die".into(), Dynamic::from(true));
|
||||||
|
map.insert("silent".into(), Dynamic::from(false));
|
||||||
|
map.insert("async_exec".into(), Dynamic::from(false));
|
||||||
|
map.insert("log".into(), Dynamic::from(false));
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Run Function Wrappers
|
// Run Function Wrappers
|
||||||
//
|
//
|
||||||
@ -94,6 +103,50 @@ pub fn run_silent(command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
|
|||||||
run_error_to_rhai_error(process::run_silent(command))
|
run_error_to_rhai_error(process::run_silent(command))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run a command with options specified in a Map
|
||||||
|
///
|
||||||
|
/// This provides a builder-style interface for Rhai scripts.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let options = new_run_options();
|
||||||
|
/// options.die = false;
|
||||||
|
/// options.silent = true;
|
||||||
|
/// let result = run("echo Hello", options);
|
||||||
|
/// ```
|
||||||
|
pub fn run_with_options(command: &str, options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
|
||||||
|
let mut builder = process::run(command);
|
||||||
|
|
||||||
|
// Apply options from the map
|
||||||
|
if let Some(die) = options.get("die") {
|
||||||
|
if let Ok(die_val) = die.clone().as_bool() {
|
||||||
|
builder = builder.die(die_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(silent) = options.get("silent") {
|
||||||
|
if let Ok(silent_val) = silent.clone().as_bool() {
|
||||||
|
builder = builder.silent(silent_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(async_exec) = options.get("async_exec") {
|
||||||
|
if let Ok(async_val) = async_exec.clone().as_bool() {
|
||||||
|
builder = builder.async_exec(async_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(log) = options.get("log") {
|
||||||
|
if let Ok(log_val) = log.clone().as_bool() {
|
||||||
|
builder = builder.log(log_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command
|
||||||
|
run_error_to_rhai_error(builder.execute())
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Process Management Function Wrappers
|
// Process Management Function Wrappers
|
||||||
//
|
//
|
||||||
|
@ -117,6 +117,36 @@ mod tests {
|
|||||||
assert_eq!(result, ());
|
assert_eq!(result, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_run_with_options() {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
register(&mut engine).unwrap();
|
||||||
|
|
||||||
|
// Test running a command with custom options
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let script = r#"
|
||||||
|
let options = new_run_options();
|
||||||
|
options["die"] = true;
|
||||||
|
options["silent"] = false;
|
||||||
|
options["log"] = true;
|
||||||
|
let result = run("echo Hello World", options);
|
||||||
|
result.success && result.stdout.contains("Hello World")
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
||||||
|
let script = r#"
|
||||||
|
let options = new_run_options();
|
||||||
|
options["die"] = true;
|
||||||
|
options["silent"] = false;
|
||||||
|
options["log"] = true;
|
||||||
|
let result = run("echo 'Hello World'", options);
|
||||||
|
result.success && result.stdout.contains("Hello World")
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = engine.eval::<bool>(script).unwrap();
|
||||||
|
assert!(result);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_run_command() {
|
fn test_run_command() {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user