This commit is contained in:
2025-04-04 21:21:50 +02:00
parent bf5eb2f6fc
commit 5b006ff328
33 changed files with 2406 additions and 201 deletions

30
src/docs/rhai/README.md Normal file
View File

@@ -0,0 +1,30 @@
# Rhai Script Commands Documentation
This documentation provides detailed information about the Rhai script commands available in the SAL library. The commands are organized by module for easy reference.
## Modules
- [OS Module](os.md) - File system operations, directory management, and download functions
- [Process Module](process.md) - Command execution and process management
- [Buildah Module](buildah.md) - Container and image management
## Overview
The SAL library provides integration with the Rhai scripting language, allowing you to use powerful system functions within your Rhai scripts. These functions are organized into modules that provide related functionality.
### Using Rhai in Your Projects
To use these commands in your Rhai scripts, you need to register the SAL modules with your Rhai engine:
```rust
use rhai::Engine;
use sal::rhai;
let mut engine = Engine::new();
rhai::register(&mut engine);
// Now you can use SAL functions in Rhai scripts
let result = engine.eval::<bool>("exist('some_file.txt')").unwrap();
```
This will register all available modules (OS, Process, and Buildah) with your Rhai engine.

343
src/docs/rhai/buildah.md Normal file
View File

@@ -0,0 +1,343 @@
# Buildah Module
The Buildah module provides functions for container and image management using the Buildah tool. Buildah is a tool for building OCI-compliant container images.
## Types
### `BuildahImage`
A type that represents a container image.
**Properties:**
- `id` (string): The image ID
- `names` (array): An array of names/tags for the image
- `name` (string): The first name of the image, or `<none>` if the image has no names
- `size` (string): The size of the image
- `created` (string): When the image was created
## Container Functions
### `bah_from(image)`
Creates a container from an image.
**Parameters:**
- `image` (string): The name or ID of the image to create the container from
**Returns:** A `CommandResult` object with the container ID in the stdout property, or throws an error if the operation fails.
**Example:**
```rhai
// Create a container from an image
let result = bah_from("alpine:latest");
let container_id = result.stdout;
print(`Created container: ${container_id}`);
```
### `bah_run(container, command)`
Runs a command in a container.
**Parameters:**
- `container` (string): The container ID or name
- `command` (string): The command to run
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Run a command in a container
let result = bah_run("my-container", "echo 'Hello from container'");
print(result.stdout);
```
### `bah_run_with_isolation(container, command, isolation)`
Runs a command in a container with specified isolation.
**Parameters:**
- `container` (string): The container ID or name
- `command` (string): The command to run
- `isolation` (string): The isolation type (e.g., "chroot", "rootless", "oci")
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Run a command with specific isolation
let result = bah_run_with_isolation("my-container", "ls -la", "chroot");
print(result.stdout);
```
### `bah_copy(container, source, dest)`
Copies files into a container.
**Parameters:**
- `container` (string): The container ID or name
- `source` (string): The source path on the host
- `dest` (string): The destination path in the container
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Copy a file into a container
bah_copy("my-container", "./app.js", "/app/app.js");
```
### `bah_add(container, source, dest)`
Adds files into a container. Similar to `bah_copy` but can also handle remote URLs.
**Parameters:**
- `container` (string): The container ID or name
- `source` (string): The source path on the host or a URL
- `dest` (string): The destination path in the container
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Add a file from a URL into a container
bah_add("my-container", "https://example.com/file.tar.gz", "/app/");
```
### `bah_commit(container, image_name)`
Commits a container to an image.
**Parameters:**
- `container` (string): The container ID or name
- `image_name` (string): The name to give the new image
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Commit a container to an image
bah_commit("my-container", "my-image:latest");
```
### `bah_remove(container)`
Removes a container.
**Parameters:**
- `container` (string): The container ID or name
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Remove a container
bah_remove("my-container");
```
### `bah_list()`
Lists containers.
**Returns:** A `CommandResult` object with the list of containers in the stdout property, or throws an error if the operation fails.
**Example:**
```rhai
// List containers
let result = bah_list();
print(result.stdout);
```
### `bah_new_build_options()`
Creates a new map with default build options.
**Returns:** A map with the following default options:
- `tag` (unit/null): The tag for the image (default: null)
- `context_dir` (string): The build context directory (default: ".")
- `file` (string): The Dockerfile path (default: "Dockerfile")
- `isolation` (unit/null): The isolation type (default: null)
**Example:**
```rhai
// Create build options
let options = bah_new_build_options();
```
### `bah_build(options)`
Builds an image with options specified in a map.
**Parameters:**
- `options` (map): A map of options created with `bah_new_build_options()`
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Create and customize build options
let options = bah_new_build_options();
options.tag = "my-image:latest";
options.context_dir = "./app";
options.file = "Dockerfile.prod";
options.isolation = "chroot";
// Build an image with options
let result = bah_build(options);
```
## Image Functions
### `bah_images()`
Lists images in local storage.
**Returns:** An array of `BuildahImage` objects or throws an error if the operation fails.
**Example:**
```rhai
// List images
let images = bah_images();
// Display image information
for image in images {
print(`ID: ${image.id}, Name: ${image.name}, Size: ${image.size}, Created: ${image.created}`);
}
```
### `bah_image_remove(image)`
Removes one or more images.
**Parameters:**
- `image` (string): The image ID or name
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Remove an image
bah_image_remove("my-image:latest");
```
### `bah_image_push(image, destination, tls_verify)`
Pushes an image to a registry.
**Parameters:**
- `image` (string): The image ID or name
- `destination` (string): The destination registry/repository
- `tls_verify` (boolean): Whether to verify TLS certificates
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Push an image to a registry
bah_image_push("my-image:latest", "registry.example.com/my-repo/my-image:latest", true);
```
### `bah_image_tag(image, new_name)`
Adds an additional name to a local image.
**Parameters:**
- `image` (string): The image ID or name
- `new_name` (string): The new name to add
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Tag an image with a new name
bah_image_tag("my-image:latest", "my-image:v1.0");
```
### `bah_image_pull(image, tls_verify)`
Pulls an image from a registry.
**Parameters:**
- `image` (string): The image to pull
- `tls_verify` (boolean): Whether to verify TLS certificates
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Pull an image from a registry
bah_image_pull("alpine:latest", true);
```
### `bah_new_commit_options()`
Creates a new map with default commit options.
**Returns:** A map with the following default options:
- `format` (unit/null): The format of the image (default: null)
- `squash` (boolean): Whether to squash layers (default: false)
- `rm` (boolean): Whether to remove the container after commit (default: false)
**Example:**
```rhai
// Create commit options
let options = bah_new_commit_options();
```
### `bah_image_commit(container, image_name, options)`
Commits a container to an image with options specified in a map.
**Parameters:**
- `container` (string): The container ID or name
- `image_name` (string): The name to give the new image
- `options` (map): A map of options created with `bah_new_commit_options()`
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Create and customize commit options
let options = bah_new_commit_options();
options.format = "docker";
options.squash = true;
options.rm = true;
// Commit a container to an image with options
let result = bah_image_commit("my-container", "my-image:latest", options);
```
### `bah_new_config_options()`
Creates a new map for config options.
**Returns:** An empty map to be filled with configuration options.
**Example:**
```rhai
// Create config options
let options = bah_new_config_options();
```
### `bah_config(container, options)`
Configures a container with options specified in a map.
**Parameters:**
- `container` (string): The container ID or name
- `options` (map): A map of options created with `bah_new_config_options()`
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Create and customize config options
let options = bah_new_config_options();
options.author = "John Doe";
options.cmd = "echo Hello";
options.entrypoint = "/bin/sh -c";
options.workingdir = "/app";
options.env = "NODE_ENV=production";
options.label = "version=1.0";
// Configure a container with options
let result = bah_config("my-container", options);

298
src/docs/rhai/os.md Normal file
View File

@@ -0,0 +1,298 @@
# OS Module
The OS module provides functions for file system operations, directory management, and downloading files.
## File System Functions
### `copy(src, dest)`
Recursively copies a file or directory from source to destination.
**Parameters:**
- `src` (string): The source file or directory path
- `dest` (string): The destination path
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Copy a file
copy("source.txt", "destination.txt");
// Copy a directory recursively
copy("source_dir", "destination_dir");
```
### `exist(path)`
Checks if a file or directory exists.
**Parameters:**
- `path` (string): The path to check
**Returns:** A boolean value - `true` if the file or directory exists, `false` otherwise.
**Example:**
```rhai
if exist("config.json") {
// File exists, do something
} else {
// File doesn't exist
}
```
### `find_file(dir, filename)`
Finds a file in a directory with support for wildcards.
**Parameters:**
- `dir` (string): The directory to search in
- `filename` (string): The filename pattern to search for (supports wildcards)
**Returns:** The path of the first matching file or throws an error if no file is found.
**Example:**
```rhai
// Find a specific file
let config_file = find_file("./config", "settings.json");
// Find using wildcards
let log_file = find_file("./logs", "*.log");
```
### `find_files(dir, filename)`
Finds multiple files in a directory recursively with support for wildcards.
**Parameters:**
- `dir` (string): The directory to search in
- `filename` (string): The filename pattern to search for (supports wildcards)
**Returns:** An array of matching file paths or throws an error if the operation fails.
**Example:**
```rhai
// Find all JSON files
let json_files = find_files("./data", "*.json");
// Process each file
for file in json_files {
print(`Found file: ${file}`);
}
```
### `find_dir(dir, dirname)`
Finds a directory in a parent directory with support for wildcards.
**Parameters:**
- `dir` (string): The parent directory to search in
- `dirname` (string): The directory name pattern to search for (supports wildcards)
**Returns:** The path of the first matching directory or throws an error if no directory is found.
**Example:**
```rhai
// Find a specific directory
let config_dir = find_dir("./", "config");
// Find using wildcards
let version_dir = find_dir("./releases", "v*");
```
### `find_dirs(dir, dirname)`
Finds multiple directories in a parent directory recursively with support for wildcards.
**Parameters:**
- `dir` (string): The parent directory to search in
- `dirname` (string): The directory name pattern to search for (supports wildcards)
**Returns:** An array of matching directory paths or throws an error if the operation fails.
**Example:**
```rhai
// Find all version directories
let version_dirs = find_dirs("./releases", "v*");
// Process each directory
for dir in version_dirs {
print(`Found directory: ${dir}`);
}
```
### `delete(path)`
Deletes a file or directory. This function is defensive and doesn't error if the file doesn't exist.
**Parameters:**
- `path` (string): The path of the file or directory to delete
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Delete a file
delete("temp.txt");
// Delete a directory
delete("temp_dir");
```
### `mkdir(path)`
Creates a directory and all parent directories. This function is defensive and doesn't error if the directory already exists.
**Parameters:**
- `path` (string): The path of the directory to create
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Create a directory
mkdir("new_dir");
// Create nested directories
mkdir("parent/child/grandchild");
```
### `file_size(path)`
Gets the size of a file in bytes.
**Parameters:**
- `path` (string): The path of the file
**Returns:** The size of the file in bytes (as an integer) or throws an error if the operation fails.
**Example:**
```rhai
// Get file size
let size = file_size("large_file.dat");
print(`File size: ${size} bytes`);
```
## File Content Functions
### `file_read(path)`
Reads the contents of a file.
**Parameters:**
- `path` (string): The path of the file to read
**Returns:** The content of the file as a string or throws an error if the operation fails.
**Example:**
```rhai
// Read a file
let content = file_read("config.json");
print(`File content: ${content}`);
```
### `file_write(path, content)`
Writes content to a file. Creates the file if it doesn't exist, overwrites if it does.
**Parameters:**
- `path` (string): The path of the file to write to
- `content` (string): The content to write to the file
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Write to a file
file_write("config.json", "{\n \"setting\": \"value\"\n}");
```
### `file_write_append(path, content)`
Appends content to a file. Creates the file if it doesn't exist.
**Parameters:**
- `path` (string): The path of the file to append to
- `content` (string): The content to append to the file
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Append to a log file
file_write_append("log.txt", "New log entry\n");
```
### `rsync(src, dest)`
Syncs directories using rsync (or platform equivalent).
**Parameters:**
- `src` (string): The source directory
- `dest` (string): The destination directory
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Sync directories
rsync("source_dir", "backup_dir");
```
### `chdir(path)`
Changes the current working directory.
**Parameters:**
- `path` (string): The path to change to
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Change directory
chdir("project/src");
```
## Download Functions
### `download(url, dest, min_size_kb)`
Downloads a file from a URL to a destination using the curl command. If the URL ends with a supported archive format, the file will be automatically extracted to the destination directory.
**Supported archive formats for automatic extraction:**
- `.tar.gz`
- `.tgz`
- `.tar`
- `.zip`
**Parameters:**
- `url` (string): The URL to download from
- `dest` (string): The destination path to save the file
- `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation)
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Download a file
download("https://example.com/file.zip", "downloads/file.zip", 10);
```
### `download_install(url, min_size_kb)`
Downloads a file and installs it if it's a supported package format.
**Supported package formats for automatic installation:**
- `.deb` packages on Debian-based systems
**Parameters:**
- `url` (string): The URL to download from
- `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation)
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Download and install a package
download_install("https://example.com/package.deb", 1000);

195
src/docs/rhai/process.md Normal file
View File

@@ -0,0 +1,195 @@
# Process Module
The Process module provides functions for executing commands and managing processes on the system.
## Run Functions
### `run(command)`
Runs a command or multiline script with arguments.
**Parameters:**
- `command` (string): The command to run
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Run a simple command
let result = run("ls -la");
// Check if the command was successful
if result.success {
print(`Command output: ${result.stdout}`);
} else {
print(`Command failed with error: ${result.stderr}`);
}
```
## Types
### `CommandResult`
A type that represents the result of a command execution.
**Properties:**
- `stdout` (string): The standard output of the command
- `stderr` (string): The standard error output of the command
- `success` (boolean): Whether the command executed successfully
- `code` (integer): The exit code of the command
### `ProcessInfo`
A type that represents information about a running process.
**Properties:**
- `pid` (integer): The process ID
- `name` (string): The name of the process
- `memory` (integer): The memory usage of the process
- `cpu` (float): The CPU usage of the process
### `run_silent(command)`
Runs a command or multiline script with arguments silently (without displaying output).
**Parameters:**
- `command` (string): The command to run
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Run a command silently
let result = run_silent("git pull");
// Check the exit code
if result.code == 0 {
print("Git pull successful");
} else {
print(`Git pull failed with code ${result.code}`);
}
```
Note we have tools for git too, no reason to do this manual.
### `new_run_options()`
Creates a new map with default run options.
**Returns:** A map with the following default options:
- `die` (boolean): `true` - Whether to throw an error if the command fails
- `silent` (boolean): `false` - Whether to suppress command output
- `async_exec` (boolean): `false` - Whether to run the command asynchronously
- `log` (boolean): `false` - Whether to log the command execution
**Example:**
```rhai
// Create run options
let options = new_run_options();
```
### `run_with_options(command, options)`
Runs a command with options specified in a map.
**Parameters:**
- `command` (string): The command to run
- `options` (map): A map of options created with `new_run_options()`
**Returns:** A `CommandResult` object or throws an error if the operation fails.
**Example:**
```rhai
// Create and customize run options
let options = new_run_options();
options.die = false; // Don't throw an error if the command fails
options.silent = true; // Suppress command output
options.async_exec = false; // Run synchronously
options.log = true; // Log the command execution
// Run a command with options
let result = run_with_options("npm install", options);
```
## Process Management Functions
### `which(cmd)`
Checks if a command exists in the PATH.
**Parameters:**
- `cmd` (string): The command to check
**Returns:** The full path to the command if found, or `()` (unit/null) if not found.
**Example:**
```rhai
// Check if a command exists
let git_path = which("git");
if git_path != () {
print(`Git is installed at: ${git_path}`);
} else {
print("Git is not installed");
}
```
### `kill(pattern)`
Kills processes matching a pattern.
**Parameters:**
- `pattern` (string): The pattern to match process names against
**Returns:** A string with the result message or throws an error if the operation fails.
**Example:**
```rhai
// Kill all processes with "node" in their name
kill("node");
```
### `process_list(pattern)`
Lists processes matching a pattern (or all processes if the pattern is empty).
**Parameters:**
- `pattern` (string): The pattern to match process names against (can be empty to list all processes)
**Returns:** An array of `ProcessInfo` objects or throws an error if the operation fails.
**Example:**
```rhai
// List all processes
let all_processes = process_list("");
// List processes containing "node" in their name
let node_processes = process_list("node");
// Display process information
for process in node_processes {
print(`PID: ${process.pid}, Name: ${process.name}, Memory: ${process.memory}, CPU: ${process.cpu}`);
}
```
### `process_get(pattern)`
Gets a single process matching the pattern. Throws an error if zero or more than one process matches.
**Parameters:**
- `pattern` (string): The pattern to match process names against
**Returns:** A `ProcessInfo` object or throws an error if zero or multiple processes match.
**Example:**
```rhai
// Try to get a specific process
try {
let process = process_get("my_app");
print(`Found process: PID=${process.pid}, Name=${process.name}`);
} catch(err) {
print(`Error: ${err}`);
}

View File

@@ -21,6 +21,9 @@ pub enum FsError {
UnknownFileType(String),
MetadataError(io::Error),
ChangeDirFailed(io::Error),
ReadFailed(io::Error),
WriteFailed(io::Error),
AppendFailed(io::Error),
}
// Implement Display for FsError
@@ -40,6 +43,9 @@ impl fmt::Display for FsError {
FsError::UnknownFileType(path) => write!(f, "Unknown file type at '{}'", path),
FsError::MetadataError(e) => write!(f, "Failed to get file metadata: {}", e),
FsError::ChangeDirFailed(e) => write!(f, "Failed to change directory: {}", e),
FsError::ReadFailed(e) => write!(f, "Failed to read file: {}", e),
FsError::WriteFailed(e) => write!(f, "Failed to write to file: {}", e),
FsError::AppendFailed(e) => write!(f, "Failed to append to file: {}", e),
}
}
}
@@ -55,6 +61,9 @@ impl Error for FsError {
FsError::InvalidGlobPattern(e) => Some(e),
FsError::MetadataError(e) => Some(e),
FsError::ChangeDirFailed(e) => Some(e),
FsError::ReadFailed(e) => Some(e),
FsError::WriteFailed(e) => Some(e),
FsError::AppendFailed(e) => Some(e),
_ => None,
}
}
@@ -619,3 +628,115 @@ pub fn chdir(path: &str) -> Result<String, FsError> {
Ok(format!("Successfully changed directory to '{}'", path))
}
/**
* Read the contents of a file.
*
* # Arguments
*
* * `path` - The path of the file to read
*
* # Returns
*
* * `Ok(String)` - The contents of the file
* * `Err(FsError)` - An error if the file doesn't exist or can't be read
*
* # Examples
*
* ```
* let content = file_read("file.txt")?;
* println!("File content: {}", content);
* ```
*/
pub fn file_read(path: &str) -> Result<String, FsError> {
let path_obj = Path::new(path);
// Check if file exists
if !path_obj.exists() {
return Err(FsError::FileNotFound(path.to_string()));
}
// Check if it's a regular file
if !path_obj.is_file() {
return Err(FsError::NotAFile(path.to_string()));
}
// Read file content
fs::read_to_string(path_obj).map_err(FsError::ReadFailed)
}
/**
* Write content to a file (creates the file if it doesn't exist, overwrites if it does).
*
* # Arguments
*
* * `path` - The path of the file to write to
* * `content` - The content to write to the file
*
* # Returns
*
* * `Ok(String)` - A success message indicating the file was written
* * `Err(FsError)` - An error if the file can't be written
*
* # Examples
*
* ```
* let result = file_write("file.txt", "Hello, world!")?;
* println!("{}", result);
* ```
*/
pub fn file_write(path: &str, content: &str) -> Result<String, FsError> {
let path_obj = Path::new(path);
// Create parent directories if they don't exist
if let Some(parent) = path_obj.parent() {
fs::create_dir_all(parent).map_err(FsError::CreateDirectoryFailed)?;
}
// Write content to file
fs::write(path_obj, content).map_err(FsError::WriteFailed)?;
Ok(format!("Successfully wrote to file '{}'", path))
}
/**
* Append content to a file (creates the file if it doesn't exist).
*
* # Arguments
*
* * `path` - The path of the file to append to
* * `content` - The content to append to the file
*
* # Returns
*
* * `Ok(String)` - A success message indicating the content was appended
* * `Err(FsError)` - An error if the file can't be appended to
*
* # Examples
*
* ```
* let result = file_write_append("log.txt", "New log entry\n")?;
* println!("{}", result);
* ```
*/
pub fn file_write_append(path: &str, content: &str) -> Result<String, FsError> {
let path_obj = Path::new(path);
// Create parent directories if they don't exist
if let Some(parent) = path_obj.parent() {
fs::create_dir_all(parent).map_err(FsError::CreateDirectoryFailed)?;
}
// Open file in append mode (or create if it doesn't exist)
let mut file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(path_obj)
.map_err(FsError::AppendFailed)?;
// Append content to file
use std::io::Write;
file.write_all(content.as_bytes()).map_err(FsError::AppendFailed)?;
Ok(format!("Successfully appended to file '{}'", path))
}

View File

@@ -16,38 +16,38 @@ use crate::process::CommandResult;
/// # Returns
///
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
pub fn register_buildah_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
pub fn register_bah_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
// Register types
register_buildah_types(engine)?;
register_bah_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);
engine.register_fn("bah_from", bah_from);
engine.register_fn("bah_run", bah_run);
engine.register_fn("bah_run_with_isolation", bah_run_with_isolation);
engine.register_fn("bah_copy", bah_copy);
engine.register_fn("bah_add", bah_add);
engine.register_fn("bah_commit", bah_commit);
engine.register_fn("bah_remove", bah_remove);
engine.register_fn("bah_list", bah_list);
engine.register_fn("bah_build", bah_build_with_options);
engine.register_fn("bah_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);
engine.register_fn("bah_images", images);
engine.register_fn("bah_image_remove", image_remove);
engine.register_fn("bah_image_push", image_push);
engine.register_fn("bah_image_tag", image_tag);
engine.register_fn("bah_image_pull", image_pull);
engine.register_fn("bah_image_commit", image_commit_with_options);
engine.register_fn("bah_new_commit_options", new_commit_options);
engine.register_fn("bah_config", config_with_options);
engine.register_fn("bah_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>> {
fn register_bah_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
// Register Image type and methods
engine.register_type_with_name::<Image>("BuildahImage");
@@ -60,6 +60,14 @@ fn register_buildah_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>>
}
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());
@@ -67,7 +75,7 @@ fn register_buildah_types(engine: &mut Engine) -> Result<(), Box<EvalAltResult>>
}
// Helper functions for error conversion
fn buildah_error_to_rhai_error<T>(result: Result<T, BuildahError>) -> Result<T, Box<EvalAltResult>> {
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(),
@@ -107,57 +115,67 @@ pub fn new_config_options() -> Map {
/// 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))
pub fn bah_from(image: &str) -> Result<CommandResult, Box<EvalAltResult>> {
let result = bah_error_to_rhai_error(buildah::from(image))?;
// Create a new CommandResult with trimmed stdout
let trimmed_result = CommandResult {
stdout: result.stdout.trim().to_string(),
stderr: result.stderr.trim().to_string(),
success: result.success,
code: result.code,
};
Ok(trimmed_result)
}
/// 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))
pub fn bah_run(container: &str, command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
bah_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))
pub fn bah_run_with_isolation(container: &str, command: &str, isolation: &str) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(buildah::bah_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))
pub fn bah_copy(container: &str, source: &str, dest: &str) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(buildah::bah_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))
pub fn bah_add(container: &str, source: &str, dest: &str) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(buildah::bah_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))
pub fn bah_commit(container: &str, image_name: &str) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(buildah::bah_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))
pub fn bah_remove(container: &str) -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(buildah::bah_remove(container))
}
/// Wrapper for buildah::list
///
/// List containers.
pub fn list() -> Result<CommandResult, Box<EvalAltResult>> {
buildah_error_to_rhai_error(buildah::list())
pub fn bah_list() -> Result<CommandResult, Box<EvalAltResult>> {
bah_error_to_rhai_error(buildah::bah_list())
}
/// Build an image with options specified in a Map
@@ -167,14 +185,14 @@ pub fn list() -> Result<CommandResult, Box<EvalAltResult>> {
/// # Example
///
/// ```rhai
/// let options = buildah_new_build_options();
/// let options = bah_new_build_options();
/// options.tag = "my-image:latest";
/// options.context_dir = ".";
/// options.file = "Dockerfile";
/// options.isolation = "chroot";
/// let result = buildah_build(options);
/// let result = bah_build(options);
/// ```
pub fn build_with_options(options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
pub fn bah_build_with_options(options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
// Extract options from the map
let tag_option = match options.get("tag") {
Some(tag) => {
@@ -241,7 +259,7 @@ pub fn build_with_options(options: Map) -> Result<CommandResult, Box<EvalAltResu
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))
bah_error_to_rhai_error(buildah::bah_build(tag_ref, &context_dir, &file, isolation_ref))
}
//
@@ -252,7 +270,7 @@ pub fn build_with_options(options: Map) -> Result<CommandResult, Box<EvalAltResu
///
/// List images in local storage.
pub fn images() -> Result<Array, Box<EvalAltResult>> {
let images = buildah_error_to_rhai_error(buildah::images())?;
let images = bah_error_to_rhai_error(buildah::images())?;
// Convert Vec<Image> to Rhai Array
let mut array = Array::new();
@@ -267,28 +285,28 @@ pub fn images() -> Result<Array, Box<EvalAltResult>> {
///
/// Remove one or more images.
pub fn image_remove(image: &str) -> Result<CommandResult, Box<EvalAltResult>> {
buildah_error_to_rhai_error(buildah::image_remove(image))
bah_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))
bah_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))
bah_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))
bah_error_to_rhai_error(buildah::image_pull(image, tls_verify))
}
/// Commit a container to an image with options specified in a Map
@@ -298,11 +316,11 @@ pub fn image_pull(image: &str, tls_verify: bool) -> Result<CommandResult, Box<Ev
/// # Example
///
/// ```rhai
/// let options = buildah_new_commit_options();
/// let options = bah_new_commit_options();
/// options.format = "docker";
/// options.squash = true;
/// options.rm = true;
/// let result = buildah_image_commit("my-container", "my-image:latest", options);
/// let result = bah_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
@@ -354,7 +372,7 @@ pub fn image_commit_with_options(container: &str, image_name: &str, options: Map
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))
bah_error_to_rhai_error(buildah::image_commit(container, image_name, format_ref, squash, rm))
}
/// Configure a container with options specified in a Map
@@ -364,11 +382,11 @@ pub fn image_commit_with_options(container: &str, image_name: &str, options: Map
/// # Example
///
/// ```rhai
/// let options = buildah_new_config_options();
/// let options = bah_new_config_options();
/// options.author = "John Doe";
/// options.cmd = "echo Hello";
/// options.entrypoint = "/bin/sh -c";
/// let result = buildah_config("my-container", options);
/// let result = bah_config("my-container", options);
/// ```
pub fn config_with_options(container: &str, options: Map) -> Result<CommandResult, Box<EvalAltResult>> {
// Convert Rhai Map to Rust HashMap
@@ -387,5 +405,5 @@ pub fn config_with_options(container: &str, options: Map) -> Result<CommandResul
}
// Call the buildah config function
buildah_error_to_rhai_error(buildah::config(container, config_options))
bah_error_to_rhai_error(buildah::bah_config(container, config_options))
}

View File

@@ -30,25 +30,14 @@ pub use os::{
pub use process::{
register_process_module,
// Run functions
run_command, run_silent, run_with_options, new_run_options,
run, 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
};
pub use buildah::*;
// 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
///
@@ -76,7 +65,7 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
process::register_process_module(engine)?;
// Register Buildah module functions
buildah::register_buildah_module(engine)?;
buildah::register_bah_module(engine)?;
// Future modules can be registered here

View File

@@ -31,6 +31,9 @@ pub fn register_os_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>>
engine.register_fn("file_size", file_size);
engine.register_fn("rsync", rsync);
engine.register_fn("chdir", chdir);
engine.register_fn("file_read", file_read);
engine.register_fn("file_write", file_write);
engine.register_fn("file_write_append", file_write_append);
// Register download functions
engine.register_fn("download", download);
@@ -136,6 +139,27 @@ pub fn chdir(path: &str) -> Result<String, Box<EvalAltResult>> {
os::chdir(path).to_rhai_error()
}
/// Wrapper for os::file_read
///
/// Read the contents of a file.
pub fn file_read(path: &str) -> Result<String, Box<EvalAltResult>> {
os::file_read(path).to_rhai_error()
}
/// Wrapper for os::file_write
///
/// Write content to a file (creates the file if it doesn't exist, overwrites if it does).
pub fn file_write(path: &str, content: &str) -> Result<String, Box<EvalAltResult>> {
os::file_write(path, content).to_rhai_error()
}
/// Wrapper for os::file_write_append
///
/// Append content to a file (creates the file if it doesn't exist).
pub fn file_write_append(path: &str, content: &str) -> Result<String, Box<EvalAltResult>> {
os::file_write_append(path, content).to_rhai_error()
}
//
// Download Function Wrappers
//

View File

@@ -19,9 +19,9 @@ pub fn register_process_module(engine: &mut Engine) -> Result<(), Box<EvalAltRes
register_process_types(engine)?;
// Register run functions
engine.register_fn("run_command", run_command);
engine.register_fn("run", run);
engine.register_fn("run_silent", run_silent);
engine.register_fn("run", run_with_options);
engine.register_fn("run_with_options", run_with_options);
engine.register_fn("new_run_options", new_run_options);
// Register process management functions
@@ -92,7 +92,7 @@ pub fn new_run_options() -> Map {
/// Wrapper for process::run_command
///
/// Run a command or multiline script with arguments.
pub fn run_command(command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
pub fn run(command: &str) -> Result<CommandResult, Box<EvalAltResult>> {
run_error_to_rhai_error(process::run_command(command))
}

View File

@@ -24,32 +24,32 @@ pub fn run(container: &str, command: &str) -> Result<CommandResult, BuildahError
/// * `container` - The container ID or name
/// * `command` - The command to run
/// * `isolation` - Isolation method (e.g., "chroot", "rootless", "oci")
pub fn run_with_isolation(container: &str, command: &str, isolation: &str) -> Result<CommandResult, BuildahError> {
pub fn bah_run_with_isolation(container: &str, command: &str, isolation: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["run", "--isolation", isolation, container, "sh", "-c", command])
}
/// Copy files into a container
pub fn copy(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
pub fn bah_copy(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["copy", container, source, dest])
}
pub fn add(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
pub fn bah_add(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["add", container, source, dest])
}
/// Commit a container to an image
pub fn commit(container: &str, image_name: &str) -> Result<CommandResult, BuildahError> {
pub fn bah_commit(container: &str, image_name: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["commit", container, image_name])
}
/// Remove a container
pub fn remove(container: &str) -> Result<CommandResult, BuildahError> {
pub fn bah_remove(container: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["rm", container])
}
/// List containers
pub fn list() -> Result<CommandResult, BuildahError> {
pub fn bah_list() -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["containers"])
}
@@ -61,7 +61,7 @@ pub fn list() -> Result<CommandResult, BuildahError> {
/// * `context_dir` - The directory containing the Containerfile/Dockerfile (usually ".")
/// * `file` - Optional path to a specific Containerfile/Dockerfile
/// * `isolation` - Optional isolation method (e.g., "chroot", "rootless", "oci")
pub fn build(tag: Option<&str>, context_dir: &str, file: &str, isolation: Option<&str>) -> Result<CommandResult, BuildahError> {
pub fn bah_build(tag: Option<&str>, context_dir: &str, file: &str, isolation: Option<&str>) -> Result<CommandResult, BuildahError> {
let mut args = Vec::new();
args.push("build");

View File

@@ -64,34 +64,35 @@ mod tests {
test_execute_buildah_command(&["from", image])
}
fn test_run(container: &str, command: &str, isolation: Option<&str>) -> Result<CommandResult, BuildahError> {
match isolation {
Some(iso) => test_execute_buildah_command(&["run", "--isolation", iso, container, "sh", "-c", command]),
None => test_execute_buildah_command(&["run", container, "sh", "-c", command])
}
fn test_run(container: &str, command: &str) -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["run", container, "sh", "-c", command])
}
fn test_copy(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
fn test_bah_run_with_isolation(container: &str, command: &str, isolation: &str) -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["run", "--isolation", isolation, container, "sh", "-c", command])
}
fn test_bah_copy(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["copy", container, source, dest])
}
fn test_add(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
fn test_bah_add(container: &str, source: &str, dest: &str) -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["add", container, source, dest])
}
fn test_commit(container: &str, image_name: &str) -> Result<CommandResult, BuildahError> {
fn test_bah_commit(container: &str, image_name: &str) -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["commit", container, image_name])
}
fn test_remove(container: &str) -> Result<CommandResult, BuildahError> {
fn test_bah_remove(container: &str) -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["rm", container])
}
fn test_list() -> Result<CommandResult, BuildahError> {
fn test_bah_list() -> Result<CommandResult, BuildahError> {
test_execute_buildah_command(&["containers"])
}
fn test_build(tag: Option<&str>, context_dir: &str, file: Option<&str>) -> Result<CommandResult, BuildahError> {
fn test_bah_build(tag: Option<&str>, context_dir: &str, file: &str, isolation: Option<&str>) -> Result<CommandResult, BuildahError> {
let mut args = Vec::new();
args.push("build");
@@ -100,11 +101,14 @@ mod tests {
args.push(tag_value);
}
if let Some(file_path) = file {
args.push("-f");
args.push(file_path);
if let Some(isolation_value) = isolation {
args.push("--isolation");
args.push(isolation_value);
}
args.push("-f");
args.push(file);
args.push(context_dir);
test_execute_buildah_command(&args)
@@ -131,26 +135,34 @@ mod tests {
let command = "echo hello";
// Test without isolation
let result = test_run(container, command, None);
let result = test_run(container, command);
assert!(result.is_ok());
let cmd = get_last_command();
assert_eq!(cmd, vec!["run", "my-container", "sh", "-c", "echo hello"]);
}
#[test]
fn test_bah_run_with_isolation_function() {
reset_test_state();
// Test with isolation
let result = test_run(container, command, Some("chroot"));
let container = "my-container";
let command = "echo hello";
let isolation = "chroot";
let result = test_bah_run_with_isolation(container, command, isolation);
assert!(result.is_ok());
let cmd = get_last_command();
assert_eq!(cmd, vec!["run", "--isolation", "chroot", "my-container", "sh", "-c", "echo hello"]);
}
#[test]
fn test_copy_function() {
fn test_bah_copy_function() {
reset_test_state();
let container = "my-container";
let source = "/local/path";
let dest = "/container/path";
let result = test_copy(container, source, dest);
let result = test_bah_copy(container, source, dest);
assert!(result.is_ok());
let cmd = get_last_command();
@@ -158,13 +170,13 @@ mod tests {
}
#[test]
fn test_add_function() {
fn test_bah_add_function() {
reset_test_state();
let container = "my-container";
let source = "/local/path";
let dest = "/container/path";
let result = test_add(container, source, dest);
let result = test_bah_add(container, source, dest);
assert!(result.is_ok());
let cmd = get_last_command();
@@ -172,12 +184,12 @@ mod tests {
}
#[test]
fn test_commit_function() {
fn test_bah_commit_function() {
reset_test_state();
let container = "my-container";
let image_name = "my-image:latest";
let result = test_commit(container, image_name);
let result = test_bah_commit(container, image_name);
assert!(result.is_ok());
let cmd = get_last_command();
@@ -185,11 +197,11 @@ mod tests {
}
#[test]
fn test_remove_function() {
fn test_bah_remove_function() {
reset_test_state();
let container = "my-container";
let result = test_remove(container);
let result = test_bah_remove(container);
assert!(result.is_ok());
let cmd = get_last_command();
@@ -197,10 +209,10 @@ mod tests {
}
#[test]
fn test_list_function() {
fn test_bah_list_function() {
reset_test_state();
let result = test_list();
let result = test_bah_list();
assert!(result.is_ok());
let cmd = get_last_command();
@@ -208,26 +220,26 @@ mod tests {
}
#[test]
fn test_build_function() {
fn test_bah_build_function() {
reset_test_state();
// Test with tag and context directory
let result = test_build(Some("my-app:latest"), ".", None);
// Test with tag, context directory, file, and no isolation
let result = test_bah_build(Some("my-app:latest"), ".", "Dockerfile", None);
assert!(result.is_ok());
let cmd = get_last_command();
assert_eq!(cmd, vec!["build", "-t", "my-app:latest", "."]);
assert_eq!(cmd, vec!["build", "-t", "my-app:latest", "-f", "Dockerfile", "."]);
// Test with tag, context directory, and file
let result = test_build(Some("my-app:latest"), ".", Some("Dockerfile.custom"));
// Test with tag, context directory, file, and isolation
let result = test_bah_build(Some("my-app:latest"), ".", "Dockerfile.custom", Some("chroot"));
assert!(result.is_ok());
let cmd = get_last_command();
assert_eq!(cmd, vec!["build", "-t", "my-app:latest", "-f", "Dockerfile.custom", "."]);
assert_eq!(cmd, vec!["build", "-t", "my-app:latest", "--isolation", "chroot", "-f", "Dockerfile.custom", "."]);
// Test with just context directory
let result = test_build(None, ".", None);
// Test with just context directory and file
let result = test_bah_build(None, ".", "Dockerfile", None);
assert!(result.is_ok());
let cmd = get_last_command();
assert_eq!(cmd, vec!["build", "."]);
assert_eq!(cmd, vec!["build", "-f", "Dockerfile", "."]);
}
#[test]

View File

@@ -190,7 +190,7 @@ pub fn image_commit(container: &str, image_name: &str, format: Option<&str>, squ
///
/// # Returns
/// * Result with command output or error
pub fn config(container: &str, options: HashMap<String, String>) -> Result<CommandResult, BuildahError> {
pub fn bah_config(container: &str, options: HashMap<String, String>) -> Result<CommandResult, BuildahError> {
let mut args_owned: Vec<String> = Vec::new();
args_owned.push("config".to_string());