git working
This commit is contained in:
@@ -197,40 +197,41 @@ impl GitTree {
|
||||
/// * `Ok(Vec<String>)` - A vector of paths to matching repositories
|
||||
/// * `Err(GitError)` - If no matching repositories are found,
|
||||
/// or if multiple repositories match a non-wildcard pattern
|
||||
pub fn find(&self, pattern: &str) -> Result<Vec<String>, GitError> {
|
||||
// Get all repos
|
||||
let repos = self.list()?;
|
||||
|
||||
if repos.is_empty() {
|
||||
return Err(GitError::NoRepositoriesFound);
|
||||
pub fn find(&self, pattern: &str) -> Result<Vec<GitRepo>, GitError> {
|
||||
let repo_names = self.list()?; // list() already ensures these are git repo names
|
||||
|
||||
if repo_names.is_empty() {
|
||||
return Ok(Vec::new()); // If no repos listed, find results in an empty list
|
||||
}
|
||||
|
||||
// Check if pattern ends with wildcard
|
||||
if pattern.ends_with('*') {
|
||||
let search_pattern = &pattern[0..pattern.len()-1]; // Remove the *
|
||||
let matching: Vec<String> = repos.iter()
|
||||
.filter(|repo| repo.contains(search_pattern))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if matching.is_empty() {
|
||||
return Err(GitError::RepositoryNotFound(pattern.to_string()));
|
||||
|
||||
let mut matched_repos: Vec<GitRepo> = Vec::new();
|
||||
|
||||
if pattern == "*" {
|
||||
for name in repo_names {
|
||||
let full_path = format!("{}/{}", self.base_path, name);
|
||||
matched_repos.push(GitRepo::new(full_path));
|
||||
}
|
||||
} else if pattern.ends_with('*') {
|
||||
let prefix = &pattern[0..pattern.len()-1];
|
||||
for name in repo_names {
|
||||
if name.starts_with(prefix) {
|
||||
let full_path = format!("{}/{}", self.base_path, name);
|
||||
matched_repos.push(GitRepo::new(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(matching)
|
||||
} else {
|
||||
// No wildcard, need to find exactly one match
|
||||
let matching: Vec<String> = repos.iter()
|
||||
.filter(|repo| repo.contains(pattern))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
match matching.len() {
|
||||
0 => Err(GitError::RepositoryNotFound(pattern.to_string())),
|
||||
1 => Ok(matching),
|
||||
_ => Err(GitError::MultipleRepositoriesFound(pattern.to_string(), matching.len())),
|
||||
// Exact match for the name
|
||||
for name in repo_names {
|
||||
if name == pattern {
|
||||
let full_path = format!("{}/{}", self.base_path, name);
|
||||
matched_repos.push(GitRepo::new(full_path));
|
||||
// `find` returns all exact matches. If names aren't unique (unlikely from `list`),
|
||||
// it could return more than one. For an exact name, typically one is expected.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(matched_repos)
|
||||
}
|
||||
|
||||
/// Gets one or more GitRepo objects based on a path pattern or URL.
|
||||
@@ -281,14 +282,9 @@ impl GitTree {
|
||||
Err(GitError::GitCommandFailed(format!("Git clone error: {}", error)))
|
||||
}
|
||||
} else {
|
||||
// It's a path pattern, find matching repositories
|
||||
let repo_paths = self.find(path_or_url)?;
|
||||
|
||||
// Convert paths to GitRepo objects
|
||||
let repos: Vec<GitRepo> = repo_paths.into_iter()
|
||||
.map(GitRepo::new)
|
||||
.collect();
|
||||
|
||||
// It's a path pattern, find matching repositories using the updated self.find()
|
||||
// which now directly returns Result<Vec<GitRepo>, GitError>.
|
||||
let repos = self.find(path_or_url)?;
|
||||
Ok(repos)
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,8 @@ use crate::git::{GitTree, GitRepo, GitError};
|
||||
/// * `Result<(), Box<EvalAltResult>>` - Ok if registration was successful, Err otherwise
|
||||
pub fn register_git_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register GitTree constructor
|
||||
engine.register_fn("gittree_new", git_tree_new);
|
||||
engine.register_type::<GitTree>();
|
||||
engine.register_fn("git_tree_new", git_tree_new);
|
||||
|
||||
// Register GitTree methods
|
||||
engine.register_fn("list", git_tree_list);
|
||||
@@ -24,6 +25,7 @@ pub fn register_git_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>
|
||||
engine.register_fn("get", git_tree_get);
|
||||
|
||||
// Register GitRepo methods
|
||||
engine.register_type::<GitRepo>();
|
||||
engine.register_fn("path", git_repo_path);
|
||||
engine.register_fn("has_changes", git_repo_has_changes);
|
||||
engine.register_fn("pull", git_repo_pull);
|
||||
@@ -72,11 +74,12 @@ pub fn git_tree_list(git_tree: &mut GitTree) -> Result<Array, Box<EvalAltResult>
|
||||
|
||||
/// Wrapper for GitTree::find
|
||||
///
|
||||
/// Finds repositories matching a pattern or partial path.
|
||||
/// Finds repositories matching a pattern and returns them as an array of GitRepo objects.
|
||||
/// Assumes the underlying GitTree::find Rust method now returns Result<Vec<GitRepo>, GitError>.
|
||||
pub fn git_tree_find(git_tree: &mut GitTree, pattern: &str) -> Result<Array, Box<EvalAltResult>> {
|
||||
let repos = git_error_to_rhai_error(git_tree.find(pattern))?;
|
||||
let repos: Vec<GitRepo> = git_error_to_rhai_error(git_tree.find(pattern))?;
|
||||
|
||||
// Convert Vec<String> to Rhai Array
|
||||
// Convert Vec<GitRepo> to Rhai Array
|
||||
let mut array = Array::new();
|
||||
for repo in repos {
|
||||
array.push(Dynamic::from(repo));
|
||||
@@ -87,17 +90,30 @@ pub fn git_tree_find(git_tree: &mut GitTree, pattern: &str) -> Result<Array, Box
|
||||
|
||||
/// Wrapper for GitTree::get
|
||||
///
|
||||
/// Gets one or more GitRepo objects based on a path pattern or URL.
|
||||
pub fn git_tree_get(git_tree: &mut GitTree, path_or_url: &str) -> Result<Array, Box<EvalAltResult>> {
|
||||
let repos = git_error_to_rhai_error(git_tree.get(path_or_url))?;
|
||||
|
||||
// Convert Vec<GitRepo> to Rhai Array
|
||||
let mut array = Array::new();
|
||||
for repo in repos {
|
||||
array.push(Dynamic::from(repo));
|
||||
/// Gets a single GitRepo object based on an exact name or URL.
|
||||
/// The underlying Rust GitTree::get method returns Result<Vec<GitRepo>, GitError>.
|
||||
/// This wrapper ensures that for Rhai, 'get' returns a single GitRepo or an error
|
||||
/// if zero or multiple repositories are found (for local names/patterns),
|
||||
/// or if a URL operation fails or unexpectedly yields not exactly one result.
|
||||
pub fn git_tree_get(git_tree: &mut GitTree, name_or_url: &str) -> Result<GitRepo, Box<EvalAltResult>> {
|
||||
let mut repos_vec: Vec<GitRepo> = git_error_to_rhai_error(git_tree.get(name_or_url))?;
|
||||
|
||||
match repos_vec.len() {
|
||||
1 => Ok(repos_vec.remove(0)), // Efficient for Vec of size 1, transfers ownership
|
||||
0 => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Git error: Repository '{}' not found.", name_or_url).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
_ => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!(
|
||||
"Git error: Multiple repositories ({}) found matching '{}'. Use find() for patterns or provide a more specific name for get().",
|
||||
repos_vec.len(),
|
||||
name_or_url
|
||||
)
|
||||
.into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
|
||||
Ok(array)
|
||||
}
|
||||
|
||||
//
|
||||
|
@@ -6,9 +6,7 @@ use rhai::{Engine, EvalAltResult, Array, Map, Position};
|
||||
use std::collections::HashMap;
|
||||
use crate::text::{
|
||||
TextReplacer, TextReplacerBuilder,
|
||||
TemplateBuilder,
|
||||
dedent, prefix,
|
||||
name_fix, path_fix
|
||||
TemplateBuilder
|
||||
};
|
||||
|
||||
/// Register Text module functions with the Rhai engine
|
||||
|
@@ -1,39 +0,0 @@
|
||||
// 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!"
|
@@ -1,64 +0,0 @@
|
||||
// 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 simpler approach
|
||||
// First touch the file
|
||||
let touch_cmd = `touch ${test_file}`;
|
||||
run_command(touch_cmd);
|
||||
// Then write to it with a separate command
|
||||
let echo_cmd = `echo ${file_content} > ${test_file}`;
|
||||
let write_result = run_command(echo_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!"
|
@@ -1,64 +0,0 @@
|
||||
// 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!"
|
@@ -1,84 +0,0 @@
|
||||
// 05_directory_operations.rhai
|
||||
// Demonstrates directory operations using SAL, including the new chdir function
|
||||
|
||||
// Create a test directory structure
|
||||
let base_dir = "rhai_dir_test";
|
||||
let sub_dir = base_dir + "/tmp/test";
|
||||
|
||||
println("Creating directory structure...");
|
||||
let base_result = mkdir(base_dir+"/subdir");
|
||||
println(`Base directory creation result: ${base_result}`);
|
||||
|
||||
let sub_result = mkdir(sub_dir);
|
||||
println(`Subdirectory creation result: ${sub_result}`);
|
||||
|
||||
// Create a test file in the base directory
|
||||
let base_file = base_dir + "/base_file.txt";
|
||||
let base_content = "This is a file in the base directory.";
|
||||
// First touch the file
|
||||
run_command(`touch ${base_file}`);
|
||||
// Then write to it with a separate command
|
||||
run_command(`echo ${base_content} > ${base_file}`);
|
||||
|
||||
// Create a test file in the subdirectory
|
||||
let sub_file = sub_dir + "/sub_file.txt";
|
||||
let sub_content = "This is a file in the subdirectory.";
|
||||
// First touch the file
|
||||
run_command(`touch ${sub_file}`);
|
||||
// Then write to it with a separate command
|
||||
run_command(`echo ${sub_content} > ${sub_file}`);
|
||||
|
||||
// Get the current working directory before changing
|
||||
let pwd_before = run_command("pwd");
|
||||
println(`Current directory before chdir: ${pwd_before.stdout.trim()}`);
|
||||
|
||||
// Change to the base directory
|
||||
println(`Changing directory to: ${base_dir}`);
|
||||
let chdir_result = chdir(base_dir);
|
||||
println(`Directory change result: ${chdir_result}`);
|
||||
|
||||
// Get the current working directory after changing
|
||||
let pwd_after = run_command("pwd");
|
||||
println(`Current directory after chdir: ${pwd_after.stdout.trim()}`);
|
||||
|
||||
// List files in the current directory (which should now be the base directory)
|
||||
println("Files in the current directory:");
|
||||
let files = find_files(".", "*");
|
||||
println("Files found:");
|
||||
for file in files {
|
||||
println(`- ${file}`);
|
||||
}
|
||||
|
||||
// Change to the subdirectory
|
||||
println(`Changing directory to: subdir`);
|
||||
let chdir_sub_result = chdir("subdir");
|
||||
println(`Directory change result: ${chdir_sub_result}`);
|
||||
|
||||
// Get the current working directory after changing to subdirectory
|
||||
let pwd_final = run_command("pwd");
|
||||
println(`Current directory after second chdir: ${pwd_final.stdout.trim()}`);
|
||||
|
||||
// List files in the subdirectory
|
||||
println("Files in the subdirectory:");
|
||||
let subdir_files = find_files(".", "*");
|
||||
println("Files found:");
|
||||
for file in subdir_files {
|
||||
println(`- ${file}`);
|
||||
}
|
||||
|
||||
// Change back to the parent directory
|
||||
println("Changing directory back to parent...");
|
||||
let chdir_parent_result = chdir("..");
|
||||
println(`Directory change result: ${chdir_parent_result}`);
|
||||
|
||||
// Clean up (uncomment to actually delete the files)
|
||||
// println("Cleaning up...");
|
||||
// Change back to the original directory first
|
||||
// chdir(pwd_before.stdout.trim());
|
||||
// delete(sub_file);
|
||||
// delete(base_file);
|
||||
// delete(sub_dir);
|
||||
// delete(base_dir);
|
||||
// println("Cleanup complete");
|
||||
|
||||
"Directory operations script completed successfully!"
|
@@ -1,65 +0,0 @@
|
||||
// 06_file_read_write.rhai
|
||||
// Demonstrates file read and write operations using SAL
|
||||
|
||||
// Create a test directory
|
||||
let test_dir = "rhai_file_test_dir";
|
||||
println(`Creating directory: ${test_dir}`);
|
||||
let mkdir_result = mkdir(test_dir);
|
||||
println(`Directory creation result: ${mkdir_result}`);
|
||||
|
||||
// Define file paths
|
||||
let test_file = test_dir + "/test_file.txt";
|
||||
let append_file = test_dir + "/append_file.txt";
|
||||
|
||||
// 1. Write to a file
|
||||
println(`\n--- Writing to file: ${test_file} ---`);
|
||||
let content = "This is the first line of text.\nThis is the second line of text.";
|
||||
let write_result = file_write(test_file, content);
|
||||
println(`Write result: ${write_result}`);
|
||||
|
||||
// 2. Read from a file
|
||||
println(`\n--- Reading from file: ${test_file} ---`);
|
||||
let read_content = file_read(test_file);
|
||||
println("File content:");
|
||||
println(read_content);
|
||||
|
||||
// 3. Append to a file
|
||||
println(`\n--- Creating and appending to file: ${append_file} ---`);
|
||||
// First create the file with initial content
|
||||
let initial_content = "Initial content - line 1\nInitial content - line 2\n";
|
||||
let create_result = file_write(append_file, initial_content);
|
||||
println(`Create result: ${create_result}`);
|
||||
|
||||
// Now append to the file
|
||||
let append_content = "Appended content - line 3\nAppended content - line 4\n";
|
||||
let append_result = file_write_append(append_file, append_content);
|
||||
println(`Append result: ${append_result}`);
|
||||
|
||||
// Read the appended file to verify
|
||||
println(`\n--- Reading appended file: ${append_file} ---`);
|
||||
let appended_content = file_read(append_file);
|
||||
println("Appended file content:");
|
||||
println(appended_content);
|
||||
|
||||
// 4. Demonstrate multiple appends
|
||||
println(`\n--- Demonstrating multiple appends ---`);
|
||||
for i in range(1, 4) {
|
||||
// Use a simple counter instead of timestamp to avoid issues
|
||||
let log_entry = `Log entry #${i} - appended at iteration ${i}\n`;
|
||||
file_write_append(append_file, log_entry);
|
||||
println(`Added log entry #${i}`);
|
||||
}
|
||||
|
||||
// Read the final file content
|
||||
println(`\n--- Final file content after multiple appends ---`);
|
||||
let final_content = file_read(append_file);
|
||||
println(final_content);
|
||||
|
||||
// Clean up (uncomment to actually delete the files)
|
||||
// println("\nCleaning up...");
|
||||
// delete(test_file);
|
||||
// delete(append_file);
|
||||
// delete(test_dir);
|
||||
// println("Cleanup complete");
|
||||
|
||||
"File read/write operations script completed successfully!"
|
@@ -1,150 +0,0 @@
|
||||
// buildah.rhai
|
||||
// Demonstrates using buildah to create a custom image with golang and nginx,
|
||||
// then using nerdctl to run a container from that image
|
||||
|
||||
println("Starting buildah workflow to create a custom image...");
|
||||
|
||||
// Define image and container names
|
||||
let base_image = "ubuntu:22.04";
|
||||
let container_name = "golang-nginx-container";
|
||||
let final_image_name = "custom-golang-nginx:latest";
|
||||
|
||||
println(`Creating container '${container_name}' from base image '${base_image}'...`);
|
||||
|
||||
// Create a new buildah container using the builder pattern
|
||||
let builder = bah_new(container_name, base_image);
|
||||
|
||||
println("Enabling debug mode...");
|
||||
builder.debug_mode = true;
|
||||
|
||||
// Update package lists and install golang and nginx
|
||||
println("Installing packages (this may take a while)...");
|
||||
|
||||
// Update package lists
|
||||
let update_result = builder.run("apt-get update -y");
|
||||
|
||||
// Install required packages
|
||||
let install_result = builder.run("apt-get install -y golang nginx");
|
||||
|
||||
// Verify installations
|
||||
let go_version = builder.run("go version");
|
||||
println(`Go version: ${go_version.stdout}`);
|
||||
|
||||
let nginx_version = builder.run("nginx -v");
|
||||
println(`Nginx version: ${nginx_version.stderr}`); // nginx outputs version to stderr
|
||||
|
||||
// Create a simple Go web application
|
||||
println("Creating a simple Go web application...");
|
||||
|
||||
// Create a directory for the Go application
|
||||
builder.run("mkdir -p /app");
|
||||
|
||||
// Create a simple Go web server
|
||||
let go_app = `
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello from Go running in a custom container!")
|
||||
})
|
||||
|
||||
fmt.Println("Starting server on :8080")
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
`;
|
||||
|
||||
// Write the Go application to a file using the write_content method
|
||||
builder.write_content(go_app, "/app/main.go");
|
||||
|
||||
// Compile the Go application
|
||||
builder.run("cd /app && go build -o server main.go");
|
||||
|
||||
// Configure nginx to proxy to the Go application
|
||||
let nginx_conf = `
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// Write the nginx configuration using the write_content method
|
||||
let nginx_conf_result = builder.write_content(nginx_conf, "/etc/nginx/sites-available/default");
|
||||
|
||||
// Create a startup script
|
||||
let startup_script = `
|
||||
#!/bin/bash
|
||||
# Start the Go application in the background
|
||||
cd /app && ./server &
|
||||
# Start nginx in the foreground
|
||||
nginx -g "daemon off;"
|
||||
`;
|
||||
|
||||
// Write the startup script using the write_content method
|
||||
let startup_script_result = builder.write_content(startup_script, "/start.sh");
|
||||
builder.run("chmod +x /start.sh");
|
||||
|
||||
// Set the entrypoint to the startup script
|
||||
println("Setting entrypoint to /start.sh...");
|
||||
builder.set_entrypoint("/start.sh");
|
||||
|
||||
// Read back the startup script to verify it was written correctly
|
||||
let read_script = builder.read_content("/start.sh");
|
||||
println("Startup script content verification:");
|
||||
println(read_script);
|
||||
|
||||
// Commit the container to a new image
|
||||
println(`Committing container to image '${final_image_name}'...`);
|
||||
let commit_result = builder.commit(final_image_name);
|
||||
|
||||
// Clean up the buildah container
|
||||
println("Cleaning up buildah container...");
|
||||
builder.remove();
|
||||
|
||||
// Now use nerdctl to run a container from the new image
|
||||
println("\nStarting container from the new image using nerdctl...");
|
||||
|
||||
// Create a container using the builder pattern
|
||||
// Use localhost/ prefix to ensure nerdctl uses the local image
|
||||
let local_image_name = "localhost/" + final_image_name;
|
||||
println(`Using local image: ${local_image_name}`);
|
||||
|
||||
// Tag the image with the localhost prefix for nerdctl compatibility
|
||||
println(`Tagging image as ${local_image_name}...`);
|
||||
let tag_result = bah_image_tag(final_image_name, local_image_name);
|
||||
|
||||
// Print a command to check if the image exists in buildah
|
||||
println("\nTo verify the image was created with buildah, run:");
|
||||
println("buildah images");
|
||||
|
||||
// Note: If nerdctl cannot find the image, you may need to push it to a registry
|
||||
println("\nNote: If nerdctl cannot find the image, you may need to push it to a registry:");
|
||||
println("buildah push localhost/custom-golang-nginx:latest docker://localhost:5000/custom-golang-nginx:latest");
|
||||
println("nerdctl pull localhost:5000/custom-golang-nginx:latest");
|
||||
|
||||
let container = nerdctl_container_from_image("golang-nginx-demo", local_image_name)
|
||||
.with_detach(true)
|
||||
.with_port("8080:80") // Map port 80 in the container to 8080 on the host
|
||||
.with_restart_policy("unless-stopped")
|
||||
.build();
|
||||
|
||||
// Start the container
|
||||
let start_result = container.start();
|
||||
|
||||
println("\nWorkflow completed successfully!");
|
||||
println("The web server should be running at http://localhost:8080");
|
||||
println("You can check container logs with: nerdctl logs golang-nginx-demo");
|
||||
println("To stop the container: nerdctl stop golang-nginx-demo");
|
||||
println("To remove the container: nerdctl rm golang-nginx-demo");
|
||||
|
||||
"Buildah and nerdctl workflow completed successfully!"
|
@@ -1,39 +0,0 @@
|
||||
// buildah_debug.rhai
|
||||
// Demonstrates using the debug flag on the buildah Builder
|
||||
|
||||
println("Starting buildah debug example...");
|
||||
|
||||
// Define image and container names
|
||||
let base_image = "ubuntu:22.04";
|
||||
let container_name = "debug-test-container";
|
||||
|
||||
println(`Creating container '${container_name}' from base image '${base_image}'...`);
|
||||
|
||||
// Create a new buildah container using the builder pattern
|
||||
let builder = bah_new(container_name, base_image);
|
||||
|
||||
// Enable debug mode
|
||||
println("Enabling debug mode...");
|
||||
builder.debug_mode = true;
|
||||
|
||||
// Run a simple command to see debug output
|
||||
println("Running a command with debug enabled...");
|
||||
let result = builder.run("echo 'Hello from debug mode'");
|
||||
|
||||
// Disable debug mode
|
||||
println("Disabling debug mode...");
|
||||
builder.debug_mode = false;
|
||||
|
||||
// Run another command without debug
|
||||
println("Running a command with debug disabled...");
|
||||
let result2 = builder.run("echo 'Hello without debug'");
|
||||
|
||||
// Enable debug mode again
|
||||
println("Enabling debug mode again...");
|
||||
builder.debug_mode = true;
|
||||
|
||||
// Remove the container with debug enabled
|
||||
println("Removing the container with debug enabled...");
|
||||
builder.remove();
|
||||
|
||||
println("Debug example completed!");
|
@@ -1,210 +0,0 @@
|
||||
// containerd_grpc_setup.rhai
|
||||
//
|
||||
// This script sets up a Rust project with gRPC connectivity to containerd
|
||||
// Following the steps from the instructions document
|
||||
|
||||
|
||||
run("apt-get -y protobuf-compiler ");
|
||||
|
||||
// Step 1: Set up project directory
|
||||
let project_dir = "/tmp/containerd-rust-client";
|
||||
print(`Setting up project in: ${project_dir}`);
|
||||
|
||||
// Clean up any existing directory
|
||||
if exist(project_dir) {
|
||||
print("Found existing project directory, removing it...");
|
||||
delete(project_dir);
|
||||
}
|
||||
|
||||
// Create our project directory
|
||||
mkdir(project_dir);
|
||||
|
||||
// Change to the project directory
|
||||
chdir(project_dir);
|
||||
|
||||
// Step 2: Clone containerd's gRPC proto files
|
||||
print("Cloning containerd repository to get proto files...");
|
||||
let git_tree = gittree_new(project_dir);
|
||||
let repos = git_tree.get("https://github.com/containerd/containerd.git");
|
||||
let repo = repos[0];
|
||||
print(`Cloned containerd repository to: ${repo.path()}`);
|
||||
|
||||
// Step 3: Create necessary project files
|
||||
print("Creating Cargo.toml file...");
|
||||
// Using raw string with # for multiline content
|
||||
let cargo_toml = #"
|
||||
[package]
|
||||
name = "containerd-rust-client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tonic = "0.11"
|
||||
prost = "0.12"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
hyper-unix-connector = "0.2.0"
|
||||
tower = "0.4"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.11"
|
||||
"#;
|
||||
|
||||
file_write("Cargo.toml", cargo_toml);
|
||||
print("Created Cargo.toml file");
|
||||
|
||||
// Step 4: Set up build.rs to compile protos
|
||||
print("Creating build.rs file...");
|
||||
let build_rs = #"
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=containerd/api/services/images/v1/images.proto");
|
||||
println!("cargo:rerun-if-changed=containerd/api/services/containers/v1/containers.proto");
|
||||
|
||||
tonic_build::configure()
|
||||
.build_server(false)
|
||||
.compile(
|
||||
&[
|
||||
"containerd/api/services/images/v1/images.proto",
|
||||
"containerd/api/services/containers/v1/containers.proto",
|
||||
// Add more proto files as needed
|
||||
],
|
||||
&[
|
||||
"containerd",
|
||||
"containerd/api",
|
||||
"containerd/api/types"
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
"#;
|
||||
|
||||
file_write("build.rs", build_rs);
|
||||
print("Created build.rs file");
|
||||
|
||||
// Step 5: Create src directory and main.rs file
|
||||
mkdir("src");
|
||||
|
||||
// Create a helper function for Unix socket connection
|
||||
print("Creating src/main.rs file...");
|
||||
let main_rs = #"
|
||||
use tonic::transport::{Channel, Endpoint, Uri};
|
||||
use tower::service_fn;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// The proto-generated modules will be available after build
|
||||
// use containerd::services::images::v1::{
|
||||
// images_client::ImagesClient,
|
||||
// GetImageRequest,
|
||||
// };
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("Connecting to containerd gRPC...");
|
||||
|
||||
// Path to containerd socket
|
||||
let socket_path = "/run/containerd/containerd.sock";
|
||||
|
||||
// Connect to the Unix socket
|
||||
let channel = unix_socket_channel(socket_path).await?;
|
||||
|
||||
// Now we'd create a client and use it
|
||||
// let mut client = ImagesClient::new(channel);
|
||||
// let response = client.get(GetImageRequest {
|
||||
// name: "docker.io/library/ubuntu:latest".to_string(),
|
||||
// }).await?;
|
||||
// println!("Image: {:?}", response.into_inner());
|
||||
|
||||
println!("Connection to containerd socket established successfully!");
|
||||
println!("This is a template - uncomment the client code after building.");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Helper function to connect to Unix socket
|
||||
async fn unix_socket_channel(path: &str) -> Result<Channel, Box<dyn std::error::Error>> {
|
||||
// Use a placeholder URI since Unix sockets don't have URIs
|
||||
let endpoint = Endpoint::try_from("http://[::]:50051")?;
|
||||
|
||||
// The socket path to connect to
|
||||
let path_to_connect = path.to_string();
|
||||
|
||||
// Create a connector function that connects to the Unix socket
|
||||
let channel = endpoint
|
||||
.connect_with_connector(service_fn(move |_: Uri| {
|
||||
let path = path_to_connect.clone();
|
||||
async move {
|
||||
tokio::net::UnixStream::connect(path)
|
||||
.await
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
|
||||
}
|
||||
}))
|
||||
.await?;
|
||||
|
||||
Ok(channel)
|
||||
}
|
||||
"#;
|
||||
|
||||
file_write("src/main.rs", main_rs);
|
||||
print("Created src/main.rs file");
|
||||
|
||||
// Step 6: Create a README.md file
|
||||
print("Creating README.md file...");
|
||||
// Using raw string with # for multiline content containing markdown backticks
|
||||
let readme = #"# containerd Rust gRPC Client
|
||||
|
||||
A Rust client for interacting with containerd via gRPC.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Rust and Cargo installed
|
||||
- containerd running on your system
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
cargo run
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Connect to containerd via Unix socket
|
||||
- Query image information
|
||||
- Work with containers
|
||||
|
||||
## Structure
|
||||
|
||||
- `src/main.rs` - Example client code
|
||||
- `build.rs` - Proto compilation script
|
||||
"#;
|
||||
|
||||
file_write("README.md", readme);
|
||||
print("Created README.md file");
|
||||
|
||||
// Step 7: Build the project
|
||||
print("Building the project...");
|
||||
let build_result = run("cargo build");
|
||||
|
||||
if build_result.success {
|
||||
print("Project built successfully!");
|
||||
} else {
|
||||
print(`Build failed with error: ${build_result.stderr}`);
|
||||
}
|
||||
|
||||
print(`
|
||||
--------------------------------------
|
||||
🎉 Setup complete!
|
||||
|
||||
Project created at: ${project_dir}
|
||||
|
||||
To use the project:
|
||||
1. cd ${project_dir}
|
||||
2. cargo run
|
||||
|
||||
Note: Make sure containerd is running and the socket exists at /run/containerd/containerd.sock
|
||||
--------------------------------------
|
||||
`);
|
@@ -1,105 +0,0 @@
|
||||
|
||||
print("\n=== Test download() Functionality ===");
|
||||
|
||||
// Create test directory
|
||||
let download_dir = "/tmp/downloadtest";
|
||||
|
||||
// Clean up any previous test files
|
||||
delete(download_dir);
|
||||
mkdir(download_dir);
|
||||
print("Created test directory for downloads at " + download_dir);
|
||||
|
||||
// Test URLs
|
||||
let zip_url = "https://github.com/freeflowuniverse/herolib/archive/refs/tags/v1.0.24.zip";
|
||||
let targz_url = "https://github.com/freeflowuniverse/herolib/archive/refs/tags/v1.0.24.tar.gz";
|
||||
let binary_url = "https://github.com/freeflowuniverse/herolib/releases/download/v1.0.24/hero-aarch64-unknown-linux-musl";
|
||||
|
||||
// Create destinations
|
||||
let zip_dest = `${download_dir}/zip`;
|
||||
let targz_dest = `${download_dir}/targz`;
|
||||
let binary_dest = `${download_dir}/hero-binary`;
|
||||
|
||||
|
||||
//PART 1
|
||||
|
||||
// Download and extract .zip file
|
||||
print("\nTesting .zip download:");
|
||||
// Download function now extracts zip files automatically
|
||||
let result = download(zip_url, zip_dest, 0);
|
||||
|
||||
// Check if files were extracted
|
||||
let file_count = find_files(zip_dest, "*").len();
|
||||
print(` Files found after extraction: ${file_count}`);
|
||||
let success_msg = if file_count > 0 { "yes" } else { "no" };
|
||||
print(` Extraction successful: ${success_msg}`);
|
||||
|
||||
//PART 2
|
||||
|
||||
// Download and extract .tar.gz file
|
||||
print("\nTesting .tar.gz download:");
|
||||
let result = download(targz_url, targz_dest, 0);
|
||||
|
||||
// Check if files were extracted (download function should extract tar.gz automatically)
|
||||
let file_count = find_files(targz_dest, "*").len();
|
||||
print(` Files found after extraction: ${file_count}`);
|
||||
let success_msg = if file_count > 100 { "yes" } else { "no" };
|
||||
print(` Extraction successful: ${success_msg}`);
|
||||
|
||||
//PART 3
|
||||
|
||||
// Download binary file and check size
|
||||
print("\nTesting binary download:");
|
||||
download_file(binary_url, binary_dest, 8000);
|
||||
|
||||
// Check file size using our new file_size function
|
||||
let size_bytes = file_size(binary_dest);
|
||||
let size_mb = size_bytes / (1024 * 1024);
|
||||
print(` File size: ${size_mb} MB`);
|
||||
let size_check = if size_mb > 5 { "yes" } else { "no" };
|
||||
print(` Size > 5MB: ${size_check}`);
|
||||
let success_msg = if size_mb >= 8 > 100 { "yes" } else { "no" };
|
||||
print(` Minimum size check passed:${success_msg}`);
|
||||
|
||||
// Clean up test files
|
||||
delete(download_dir);
|
||||
print("Cleaned up test directory");
|
||||
//PART 4
|
||||
|
||||
// Test the new download_file function
|
||||
print("\nTesting download_file function:");
|
||||
let text_url = "https://raw.githubusercontent.com/freeflowuniverse/herolib/main/README.md";
|
||||
let text_file_dest = `${download_dir}/README.md`;
|
||||
|
||||
// Create the directory again for this test
|
||||
mkdir(download_dir);
|
||||
|
||||
// Download a text file using the new download_file function
|
||||
let file_result = download_file(text_url, text_file_dest, 0);
|
||||
print(` File downloaded to: ${file_result}`);
|
||||
|
||||
// Check if the file exists and has content
|
||||
let file_exists = exist(text_file_dest);
|
||||
print(` File exists: ${file_exists}`);
|
||||
let file_content = file_read(text_file_dest);
|
||||
let content_check = if file_content.len() > 100 { "yes" } else { "no" };
|
||||
print(` File has content: ${content_check}`);
|
||||
|
||||
//PART 5
|
||||
|
||||
// Test the new chmod_exec function
|
||||
print("\nTesting chmod_exec function:");
|
||||
// Create a simple shell script
|
||||
let script_path = `${download_dir}/test_script.sh`;
|
||||
file_write(script_path, "#!/bin/sh\necho 'Hello from test script'");
|
||||
|
||||
// Make it executable
|
||||
let chmod_result = chmod_exec(script_path);
|
||||
print(` ${chmod_result}`);
|
||||
|
||||
// Clean up test files again
|
||||
delete(download_dir);
|
||||
print("Cleaned up test directory");
|
||||
|
||||
print("\nAll Download Tests completed successfully!");
|
||||
"Download Tests Success"
|
||||
"Download Tests Success"
|
@@ -1,217 +0,0 @@
|
||||
// Comprehensive file system operations test script with assertions
|
||||
|
||||
print("===== File System Operations Test =====");
|
||||
|
||||
// Helper functions for testing
|
||||
fn assert(condition, message) {
|
||||
if (condition == false) {
|
||||
print(`FAILED: ${message}`);
|
||||
throw `Assertion failed: ${message}`;
|
||||
} else {
|
||||
print(`PASSED: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_equal(actual, expected, message) {
|
||||
// Convert numbers to strings before comparison to avoid type issues
|
||||
let actual_str = actual.to_string();
|
||||
let expected_str = expected.to_string();
|
||||
|
||||
if (actual_str != expected_str) {
|
||||
print(`FAILED: ${message} - Expected '${expected}', got '${actual}'`);
|
||||
throw `Assertion failed: ${message}`;
|
||||
} else {
|
||||
print(`PASSED: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_true(value, message) {
|
||||
assert(value, message);
|
||||
}
|
||||
|
||||
fn assert_false(value, message) {
|
||||
assert(value == false, message);
|
||||
}
|
||||
|
||||
// Directory for tests
|
||||
let test_dir = "/tmp/herodo_test_fs";
|
||||
let tests_total = 0;
|
||||
|
||||
// Setup - create test directory
|
||||
print("\n=== Setup ===");
|
||||
if exist(test_dir) {
|
||||
print(`Test directory exists, removing it first...`);
|
||||
let result = delete(test_dir);
|
||||
// Function will throw an error if it fails
|
||||
assert_false(exist(test_dir), "Test directory should not exist after deletion");
|
||||
}
|
||||
|
||||
// Test mkdir
|
||||
print("\n=== Test mkdir() ===");
|
||||
print(`Creating test directory: ${test_dir}`);
|
||||
tests_total += 1;
|
||||
let mkdir_result = mkdir(test_dir);
|
||||
// Now can directly use the returned success message
|
||||
assert_true(exist(test_dir), "Test directory should exist after creation");
|
||||
|
||||
// Test mkdir with nested paths
|
||||
print(`Creating nested directory: ${test_dir}/subdir/nested`);
|
||||
tests_total += 1;
|
||||
let nested_result = mkdir(`${test_dir}/subdir/nested`);
|
||||
assert_true(exist(`${test_dir}/subdir/nested`), "Nested directory should exist after creation");
|
||||
|
||||
// Test duplicate mkdir (should not error)
|
||||
print(`Creating existing directory again: ${test_dir}`);
|
||||
tests_total += 1;
|
||||
let duplicate_result = mkdir(test_dir);
|
||||
// This should just return a message that directory already exists
|
||||
|
||||
// Test file creation using run
|
||||
print("\n=== Test file creation ===");
|
||||
let file1 = `${test_dir}/file1.txt`;
|
||||
let file2 = `${test_dir}/file2.txt`;
|
||||
let file3 = `${test_dir}/subdir/file3.txt`;
|
||||
|
||||
// Create files
|
||||
print(`Creating test files...`);
|
||||
let touch_cmd = `touch ${file1} ${file2} ${file3}`;
|
||||
let touch_result = run(touch_cmd);
|
||||
tests_total += 1;
|
||||
assert_true(touch_result.success, "File creation using touch should succeed");
|
||||
|
||||
// Verify files exist
|
||||
print(`Verifying files exist...`);
|
||||
tests_total += 1;
|
||||
assert_true(exist(file1), "File 1 should exist after creation");
|
||||
assert_true(exist(file2), "File 2 should exist after creation");
|
||||
assert_true(exist(file3), "File 3 should exist after creation");
|
||||
print("All test files were created successfully");
|
||||
|
||||
// Test copy
|
||||
print("\n=== Test copy() ===");
|
||||
let copy_file = `${test_dir}/file1_copy.txt`;
|
||||
print(`Copying ${file1} to ${copy_file}`);
|
||||
tests_total += 1;
|
||||
let copy_result = copy(file1, copy_file);
|
||||
tests_total += 1;
|
||||
assert_true(exist(copy_file), "Copied file should exist");
|
||||
|
||||
// Test directory copy
|
||||
print(`Copying directory ${test_dir}/subdir to ${test_dir}/subdir_copy`);
|
||||
tests_total += 1;
|
||||
let dir_copy_result = copy(`${test_dir}/subdir`, `${test_dir}/subdir_copy`);
|
||||
tests_total += 1;
|
||||
assert_true(exist(`${test_dir}/subdir_copy`), "Copied directory should exist");
|
||||
tests_total += 1;
|
||||
assert_true(exist(`${test_dir}/subdir_copy/file3.txt`), "Files in copied directory should exist");
|
||||
|
||||
// Test file searching
|
||||
print("\n=== Test find_file() and find_files() ===");
|
||||
|
||||
// Create log files for testing search
|
||||
print("Creating log files for testing search...");
|
||||
let log_file1 = `${test_dir}/subdir/test1.log`;
|
||||
let log_file2 = `${test_dir}/subdir/test2.log`;
|
||||
let log_file3 = `${test_dir}/subdir_copy/test3.log`;
|
||||
let log_touch_cmd = `touch ${log_file1} ${log_file2} ${log_file3}`;
|
||||
let log_touch_result = run(log_touch_cmd);
|
||||
tests_total += 1;
|
||||
assert_true(log_touch_result.success, "Log file creation should succeed");
|
||||
|
||||
// Verify log files exist
|
||||
print("Verifying log files exist...");
|
||||
assert_true(exist(log_file1), "Log file 1 should exist after creation");
|
||||
assert_true(exist(log_file2), "Log file 2 should exist after creation");
|
||||
assert_true(exist(log_file3), "Log file 3 should exist after creation");
|
||||
print("All log files were created successfully");
|
||||
|
||||
// Test find_file
|
||||
print("Testing find_file for a single file:");
|
||||
let found_file = find_file(test_dir, "file1.txt");
|
||||
tests_total += 1;
|
||||
assert_true(found_file.to_string().contains("file1.txt"), "find_file should find the correct file");
|
||||
|
||||
// Test find_file with wildcard
|
||||
print("Testing find_file with wildcard:");
|
||||
let log_file = find_file(test_dir, "*.log");
|
||||
print(`Found log file: ${log_file}`);
|
||||
tests_total += 1;
|
||||
// Check if the log file path contains '.log'
|
||||
let is_log_file = log_file.to_string().contains(".log");
|
||||
assert_true(is_log_file, "find_file should find a log file");
|
||||
|
||||
// Test find_files
|
||||
print("Testing find_files with wildcard:");
|
||||
let log_files = find_files(test_dir, "*.log");
|
||||
print(`Found ${log_files.len()} log files with find_files`);
|
||||
tests_total += 1;
|
||||
assert_equal(log_files.len(), 3, "find_files should find all 3 log files");
|
||||
|
||||
// Test find_dir
|
||||
print("\n=== Test find_dir() and find_dirs() ===");
|
||||
let found_dir = find_dir(test_dir, "subdir");
|
||||
tests_total += 1;
|
||||
assert_true(found_dir.to_string().contains("subdir"), "find_dir should find the correct directory");
|
||||
|
||||
// Test find_dirs
|
||||
let all_dirs = find_dirs(test_dir, "*dir*");
|
||||
tests_total += 1;
|
||||
assert_equal(all_dirs.len(), 2, "find_dirs should find both 'subdir' and 'subdir_copy'");
|
||||
tests_total += 2;
|
||||
assert_true(all_dirs.contains(`${test_dir}/subdir`), "find_dirs should include the 'subdir' directory");
|
||||
assert_true(all_dirs.contains(`${test_dir}/subdir_copy`), "find_dirs should include the 'subdir_copy' directory");
|
||||
|
||||
// Test sync by manually copying instead of rsync
|
||||
print("\n=== Test sync() ===");
|
||||
print(`Copying directory ${test_dir}/subdir to ${test_dir}/sync_target`);
|
||||
tests_total += 1;
|
||||
let sync_result = copy(`${test_dir}/subdir`, `${test_dir}/sync_target`);
|
||||
tests_total += 1;
|
||||
assert_true(exist(`${test_dir}/sync_target`), "Sync target directory should exist");
|
||||
|
||||
// Create test files in sync target to verify they exist
|
||||
print("Creating test files in sync target...");
|
||||
let sync_file1 = `${test_dir}/sync_target/sync_test1.log`;
|
||||
let sync_file2 = `${test_dir}/sync_target/sync_test2.log`;
|
||||
let sync_touch_cmd = `touch ${sync_file1} ${sync_file2}`;
|
||||
let sync_touch_result = run(sync_touch_cmd);
|
||||
tests_total += 1;
|
||||
assert_true(sync_touch_result.success, "Creating test files in sync target should succeed");
|
||||
tests_total += 1;
|
||||
assert_true(exist(sync_file1), "Test files should exist in sync target");
|
||||
|
||||
// Test delete
|
||||
print("\n=== Test delete() ===");
|
||||
print(`Deleting file: ${copy_file}`);
|
||||
tests_total += 1;
|
||||
let delete_file_result = delete(copy_file);
|
||||
tests_total += 1;
|
||||
assert_false(exist(copy_file), "File should not exist after deletion");
|
||||
|
||||
// Test delete non-existent file (should be defensive)
|
||||
print(`Deleting non-existent file:`);
|
||||
tests_total += 1;
|
||||
let nonexistent_result = delete(`${test_dir}/nonexistent.txt`);
|
||||
// This should not throw an error, just inform no file was deleted
|
||||
|
||||
// Test delete directory
|
||||
print(`Deleting directory: ${test_dir}/subdir_copy`);
|
||||
tests_total += 1;
|
||||
let dir_delete_result = delete(`${test_dir}/subdir_copy`);
|
||||
tests_total += 1;
|
||||
assert_false(exist(`${test_dir}/subdir_copy`), "Directory should not exist after deletion");
|
||||
|
||||
// Cleanup
|
||||
print("\n=== Cleanup ===");
|
||||
print(`Removing test directory: ${test_dir}`);
|
||||
tests_total += 1;
|
||||
let cleanup_result = delete(test_dir);
|
||||
tests_total += 1;
|
||||
assert_false(exist(test_dir), "Test directory should not exist after cleanup");
|
||||
|
||||
// Test summary
|
||||
print("\n===== Test Summary =====");
|
||||
print(`Total tests run: ${tests_total}`);
|
||||
print(`All tests passed!`);
|
||||
|
||||
"File System Test Success - All tests passed"
|
@@ -1,164 +0,0 @@
|
||||
// Simplified test script for Git module functions
|
||||
|
||||
// Ensure test directory exists using a bash script
|
||||
fn ensure_test_dir() {
|
||||
print("Ensuring test directory exists at /tmp/code");
|
||||
|
||||
// Create a bash script to set up the test environment
|
||||
let setup_script = `#!/bin/bash -ex
|
||||
rm -rf /tmp/code
|
||||
mkdir -p /tmp/code
|
||||
cd /tmp/code
|
||||
|
||||
mkdir -p myserver.com/myaccount/repogreen
|
||||
mkdir -p myserver.com/myaccount/repored
|
||||
|
||||
cd myserver.com/myaccount/repogreen
|
||||
git init
|
||||
echo 'Initial test file' > test.txt
|
||||
git add test.txt
|
||||
git config --local user.email 'test@example.com'
|
||||
git config --local user.name 'Test User'
|
||||
git commit -m 'Initial commit'
|
||||
|
||||
cd myserver.com/myaccount/repored
|
||||
git init
|
||||
echo 'Initial test file' > test2.txt
|
||||
git add test2.txt
|
||||
git config --local user.email 'test@example.com'
|
||||
git config --local user.name 'Test User'
|
||||
git commit -m 'Initial commit'
|
||||
|
||||
//now we have 2 repos
|
||||
|
||||
`;
|
||||
|
||||
// Run the setup script
|
||||
let result = run(setup_script);
|
||||
if !result.success {
|
||||
print("Failed to set up test directory");
|
||||
print(`Error: ${result.stderr}`);
|
||||
throw "Test setup failed";
|
||||
}
|
||||
}
|
||||
|
||||
// Test GitTree creation
|
||||
fn test_git_tree_creation() {
|
||||
print("\n=== Testing GitTree creation ===");
|
||||
let git_tree = gittree_new("/tmp/code");
|
||||
print(`Created GitTree with base path: /tmp/code`);
|
||||
}
|
||||
|
||||
// Test GitTree list method
|
||||
fn test_git_tree_list() {
|
||||
print("\n=== Testing GitTree list method ===");
|
||||
let git_tree = gittree_new("/tmp/code");
|
||||
let repos = git_tree.list();
|
||||
|
||||
print(`Found ${repos.len()} repositories`);
|
||||
|
||||
// Print repositories
|
||||
for repo in repos {
|
||||
print(` - ${repo}`);
|
||||
}
|
||||
|
||||
if repos.len() == 0 {
|
||||
print("No repositories found, which is unexpected");
|
||||
throw "No repositories found";
|
||||
}
|
||||
|
||||
if repos.len() != 2 {
|
||||
print("No enough repositories found, needs to be 2");
|
||||
throw "No enough repositories found";
|
||||
}
|
||||
}
|
||||
|
||||
// Test GitTree find method
|
||||
fn test_git_tree_find() {
|
||||
print("\n=== Testing GitTree find method ===");
|
||||
let git_tree = gittree_new("/tmp/code");
|
||||
|
||||
// Search for repositories with "code" in the name
|
||||
let search_pattern = "myaccount/repo"; //we need to check if we need *, would be better not
|
||||
print(`Searching for repositories matching pattern: ${search_pattern}`);
|
||||
let matching = git_tree.find(search_pattern);
|
||||
|
||||
print(`Found ${matching.len()} matching repositories`);
|
||||
for repo in matching {
|
||||
print(` - ${repo}`);
|
||||
}
|
||||
|
||||
if matching.len() == 0 {
|
||||
print("No matching repositories found, which is unexpected");
|
||||
throw "No matching repositories found";
|
||||
}
|
||||
if repos.len() != 2 {
|
||||
print("No enough repositories found, needs to be 2");
|
||||
throw "No enough repositories found";
|
||||
}
|
||||
}
|
||||
|
||||
// Test GitRepo operations
|
||||
fn test_git_repo_operations() {
|
||||
print("\n=== Testing GitRepo operations ===");
|
||||
let git_tree = gittree_new("/tmp/code");
|
||||
let repos = git_tree.list();
|
||||
|
||||
if repos.len() == 0 {
|
||||
print("No repositories found, which is unexpected");
|
||||
throw "No repositories found";
|
||||
}
|
||||
|
||||
// Get the first repo
|
||||
let repo_path = repos[0];
|
||||
print(`Testing operations on repository: ${repo_path}`);
|
||||
|
||||
// Get GitRepo object
|
||||
let git_repos = git_tree.get(repo_path);
|
||||
if git_repos.len() == 0 {
|
||||
print("Failed to get GitRepo object");
|
||||
throw "Failed to get GitRepo object";
|
||||
}
|
||||
|
||||
let git_repo = git_repos[0];
|
||||
|
||||
// Test has_changes method
|
||||
print("Testing has_changes method");
|
||||
let has_changes = git_repo.has_changes();
|
||||
print(`Repository has changes: ${has_changes}`);
|
||||
|
||||
// Create a change to test
|
||||
print("Creating a change to test");
|
||||
file_write("/tmp/code/test2.txt", "Another test file");
|
||||
|
||||
// Check if changes are detected
|
||||
let has_changes_after = git_repo.has_changes();
|
||||
print(`Repository has changes after modification: ${has_changes_after}`);
|
||||
|
||||
if !has_changes_after {
|
||||
print("Changes not detected, which is unexpected");
|
||||
throw "Changes not detected";
|
||||
}
|
||||
|
||||
// Clean up the change
|
||||
delete("/tmp/code/test2.txt");
|
||||
}
|
||||
|
||||
// Run all tests
|
||||
fn run_all_tests() {
|
||||
print("Starting Git module tests...");
|
||||
|
||||
// Ensure test directory exists
|
||||
ensure_test_dir();
|
||||
|
||||
// Run tests
|
||||
test_git_tree_creation();
|
||||
test_git_tree_list();
|
||||
test_git_tree_find();
|
||||
test_git_repo_operations();
|
||||
|
||||
print("\nAll tests completed successfully!");
|
||||
}
|
||||
|
||||
// Run all tests
|
||||
run_all_tests();
|
@@ -1,32 +0,0 @@
|
||||
|
||||
fn dragonfly(){
|
||||
download("https://github.com/dragonflyoss/dragonfly/releases/download/v2.2.1/dragonfly-2.2.1-linux-amd64.tar.gz", "/tmp/dragonfly", 55000);
|
||||
copy("/tmp/dragonfly","/root/hero/bin");
|
||||
delete("/tmp/dragonfly");
|
||||
}
|
||||
|
||||
fn nydus(){
|
||||
let url="https://github.com/dragonflyoss/nydus/releases/download/v2.3.1/nydus-static-v2.3.1-linux-amd64.tgz";
|
||||
download(url,"/tmp/nydus",20);
|
||||
copy("/tmp/nydus/nydus-static/*","/root/hero/bin/");
|
||||
delete("/tmp/nydus");
|
||||
}
|
||||
|
||||
fn nerdctl(){
|
||||
let name="nerctl"
|
||||
let url="https://github.com/containerd/nerdctl/releases/download/v2.0.4/nerdctl-2.0.4-linux-amd64.tar.gz"
|
||||
download(url,"/tmp/nydus",20);
|
||||
//copy(`/tmp/{name}/*`,"/root/hero/bin/");
|
||||
//delete("/tmp/{name}");
|
||||
|
||||
let name="containerd"
|
||||
let url="https://github.com/containerd/containerd/releases/download/v2.0.4/containerd-2.0.4-linux-amd64.tar.gz";
|
||||
download(url,"/tmp/nydus",20);
|
||||
//copy(`/tmp/{name}/*`,"/root/hero/bin/");
|
||||
//delete("/tmp/{name}");
|
||||
|
||||
}
|
||||
|
||||
nydus();
|
||||
|
||||
"done"
|
@@ -1,124 +0,0 @@
|
||||
|
||||
|
||||
## ✅ Step-by-step: Connect Rust to containerd via gRPC
|
||||
|
||||
|
||||
CREATE A rhai script executing the following instructions below
|
||||
use all rhai script features we have + give priority to what functions we have defined in /src/docs/docs/sal in this repo
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 1. 🧱 Install Dependencies
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tonic = "0.11"
|
||||
prost = "0.12"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.11"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 📁 Clone containerd's gRPC proto files
|
||||
|
||||
```bash
|
||||
git clone https://github.com/containerd/containerd.git
|
||||
cd containerd
|
||||
```
|
||||
|
||||
Containerd's API protos are in:
|
||||
```
|
||||
api/services/ # gRPC service definitions
|
||||
api/types/ # message types
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 📦 Set up `build.rs` to compile protos
|
||||
|
||||
In your Rust project root, create a `build.rs` file:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
tonic_build::configure()
|
||||
.build_server(false)
|
||||
.compile(
|
||||
&[
|
||||
"containerd/api/services/images/v1/images.proto",
|
||||
"containerd/api/services/containers/v1/containers.proto",
|
||||
// Add more proto files as needed
|
||||
],
|
||||
&[
|
||||
"containerd/api",
|
||||
"containerd/api/types"
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
Make sure to place the `containerd` directory somewhere your build can see — for example, symlink it or move it into your project as `proto/containerd`.
|
||||
|
||||
---
|
||||
|
||||
### 4. 🧪 Example: Connect to containerd's image service
|
||||
|
||||
After `build.rs` compiles the protos, your code can access them like this:
|
||||
|
||||
```rust
|
||||
use tonic::transport::Channel;
|
||||
use containerd::services::images::v1::{
|
||||
images_client::ImagesClient,
|
||||
GetImageRequest,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Connect to containerd's gRPC socket (default path)
|
||||
let channel = Channel::from_static("http://[::]:50051") // placeholder
|
||||
.connect()
|
||||
.await?;
|
||||
|
||||
let mut client = ImagesClient::new(channel);
|
||||
|
||||
let response = client.get(GetImageRequest {
|
||||
name: "docker.io/library/ubuntu:latest".to_string(),
|
||||
}).await?;
|
||||
|
||||
println!("Image: {:?}", response.into_inner());
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
🔧 Note: containerd uses a **Unix socket**, so replace the channel connection with:
|
||||
|
||||
```rust
|
||||
use tonic::transport::{Endpoint, Uri};
|
||||
use tower::service_fn;
|
||||
use hyper_unix_connector::UnixConnector;
|
||||
|
||||
let uds = tokio::net::UnixStream::connect("/run/containerd/containerd.sock").await?;
|
||||
let channel = Endpoint::try_from("http://[::]:50051")?
|
||||
.connect_with_connector(service_fn(move |_| async move {
|
||||
Ok::<_, std::io::Error>(uds)
|
||||
}))
|
||||
.await?;
|
||||
```
|
||||
|
||||
(We can wrap that part into a helper if you want.)
|
||||
|
||||
---
|
||||
|
||||
### 5. 🔁 Rebuild the project
|
||||
|
||||
Each time you add or change a `.proto`, rebuild to regenerate code:
|
||||
|
||||
```bash
|
||||
cargo clean && cargo build
|
||||
```
|
@@ -1,42 +0,0 @@
|
||||
|
||||
|
||||
|
||||
fn nerdctl_download(){
|
||||
let name="nerdctl";
|
||||
let url="https://github.com/containerd/nerdctl/releases/download/v2.0.4/nerdctl-2.0.4-linux-amd64.tar.gz";
|
||||
download(url,`/tmp/${name}`,20000);
|
||||
copy(`/tmp/${name}/*`,"/root/hero/bin/");
|
||||
delete(`/tmp/${name}`);
|
||||
|
||||
let name="containerd";
|
||||
let url="https://github.com/containerd/containerd/releases/download/v2.0.4/containerd-2.0.4-linux-amd64.tar.gz";
|
||||
download(url,`/tmp/${name}`,20000);
|
||||
copy(`/tmp/${name}/bin/*`,"/root/hero/bin/");
|
||||
delete(`/tmp/${name}`);
|
||||
|
||||
run("apt-get -y install buildah runc");
|
||||
|
||||
let url="https://github.com/threefoldtech/rfs/releases/download/v2.0.6/rfs";
|
||||
download_file(url,`/tmp/rfs`,10000);
|
||||
chmod_exec("/tmp/rfs");
|
||||
mv(`/tmp/rfs`,"/root/hero/bin/");
|
||||
|
||||
}
|
||||
|
||||
fn ipfs_download(){
|
||||
let name="ipfs";
|
||||
let url="https://github.com/ipfs/kubo/releases/download/v0.34.1/kubo_v0.34.1_linux-amd64.tar.gz";
|
||||
download(url,`/tmp/${name}`,20);
|
||||
copy(`/tmp/${name}/kubo/ipfs`,"/root/hero/bin/ipfs");
|
||||
// delete(`/tmp/${name}`);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
nerdctl_download();
|
||||
// ipfs_download();
|
||||
|
||||
"done"
|
@@ -1,86 +0,0 @@
|
||||
// 08__web_server.rhai
|
||||
// Demonstrates a complete workflow to set up a web server using
|
||||
// Note: This script requires to be installed and may need root privileges
|
||||
|
||||
println("Starting web server workflow...");
|
||||
|
||||
// Create and use a temporary directory for all files
|
||||
let work_dir = "/tmp/";
|
||||
mkdir(work_dir);
|
||||
chdir(work_dir);
|
||||
println(`Working in directory: ${work_dir}`);
|
||||
|
||||
|
||||
println("\n=== Creating custom nginx configuration ===");
|
||||
let config_content = `
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
let config_file = `${work_dir}/custom-nginx.conf`;
|
||||
// Use file_write instead of run command
|
||||
file_write(config_file, config_content);
|
||||
println(`Created custom nginx configuration file at ${config_file}`);
|
||||
|
||||
// Step 3: Create a custom index.html file
|
||||
println("\n=== Creating custom index.html ===");
|
||||
let html_content = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Demo</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 40px;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
}
|
||||
h1 {
|
||||
color: #0066cc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello from HeroScript !</h1>
|
||||
<p>This page is served by an Nginx container.</p>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
let html_file = `${work_dir}/index.html`;
|
||||
// Use file_write instead of run command
|
||||
file_write(html_file, html_content);
|
||||
println(`Created custom index.html file at ${html_file}`);
|
||||
|
||||
println("\n=== Creating nginx container ===");
|
||||
let container_name = "nginx-demo";
|
||||
|
||||
let env_map = #{}; // Create an empty map
|
||||
env_map["NGINX_HOST"] = "localhost";
|
||||
env_map["NGINX_PORT"] = "80";
|
||||
env_map["NGINX_WORKER_PROCESSES"] = "auto";
|
||||
|
||||
// Create a container with a rich set of options using batch methods
|
||||
let container = nerdctl_container_from_image(container_name, "nginx:latest")
|
||||
.reset()
|
||||
.with_detach(true)
|
||||
.with_ports(["8080:80"]) // Add multiple ports at once
|
||||
.with_volumes([`${work_dir}:/usr/share/nginx/html`, "/var/log:/var/log/nginx"]) // Mount our work dir
|
||||
.with_envs(env_map) // Add multiple environment variables at once
|
||||
.with_cpu_limit("1.0")
|
||||
.with_memory_limit("512m")
|
||||
.start();
|
||||
|
||||
|
||||
println("\n web server workflow completed successfully!");
|
||||
println("The web server is running at http://localhost:8080");
|
||||
|
||||
"Web server script completed successfully!"
|
@@ -1,113 +0,0 @@
|
||||
// Example script demonstrating the mypackage management functions
|
||||
|
||||
// Set debug mode to true to see detailed output
|
||||
package_set_debug(true);
|
||||
|
||||
// Function to demonstrate mypackage management on Ubuntu
|
||||
fn demo_ubuntu() {
|
||||
print("Demonstrating mypackage management on Ubuntu...");
|
||||
|
||||
// Update mypackage lists
|
||||
print("Updating mypackage lists...");
|
||||
let result = package_update();
|
||||
print(`Update result: ${result}`);
|
||||
|
||||
// Check if a mypackage is installed
|
||||
let mypackage = "htop";
|
||||
print(`Checking if ${mypackage} is installed...`);
|
||||
let is_installed = package_is_installed(mypackage);
|
||||
print(`${mypackage} is installed: ${is_installed}`);
|
||||
|
||||
// Install a mypackage if not already installed
|
||||
if !is_installed {
|
||||
print(`Installing ${mypackage}...`);
|
||||
let install_result = package_install(mypackage);
|
||||
print(`Install result: ${install_result}`);
|
||||
}
|
||||
|
||||
// List installed packages (limited to first 5 for brevity)
|
||||
print("Listing installed packages (first 5)...");
|
||||
let packages = package_list();
|
||||
for i in 0..min(5, packages.len()) {
|
||||
print(` - ${packages[i]}`);
|
||||
}
|
||||
|
||||
// Search for packages
|
||||
let search_term = "editor";
|
||||
print(`Searching for packages with term '${search_term}'...`);
|
||||
let search_results = package_search(search_term);
|
||||
print(`Found ${search_results.len()} packages. First 5 results:`);
|
||||
for i in 0..min(5, search_results.len()) {
|
||||
print(` - ${search_results[i]}`);
|
||||
}
|
||||
|
||||
// Remove the mypackage if we installed it
|
||||
if !is_installed {
|
||||
print(`Removing ${mypackage}...`);
|
||||
let remove_result = package_remove(mypackage);
|
||||
print(`Remove result: ${remove_result}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to demonstrate mypackage management on macOS
|
||||
fn demo_macos() {
|
||||
print("Demonstrating mypackage management on macOS...");
|
||||
|
||||
// Update mypackage lists
|
||||
print("Updating mypackage lists...");
|
||||
let result = package_update();
|
||||
print(`Update result: ${result}`);
|
||||
|
||||
// Check if a mypackage is installed
|
||||
let mypackage = "wget";
|
||||
print(`Checking if ${mypackage} is installed...`);
|
||||
let is_installed = package_is_installed(mypackage);
|
||||
print(`${mypackage} is installed: ${is_installed}`);
|
||||
|
||||
// Install a mypackage if not already installed
|
||||
if !is_installed {
|
||||
print(`Installing ${mypackage}...`);
|
||||
let install_result = package_install(mypackage);
|
||||
print(`Install result: ${install_result}`);
|
||||
}
|
||||
|
||||
// List installed packages (limited to first 5 for brevity)
|
||||
print("Listing installed packages (first 5)...");
|
||||
let packages = package_list();
|
||||
for i in 0..min(5, packages.len()) {
|
||||
print(` - ${packages[i]}`);
|
||||
}
|
||||
|
||||
// Search for packages
|
||||
let search_term = "editor";
|
||||
print(`Searching for packages with term '${search_term}'...`);
|
||||
let search_results = package_search(search_term);
|
||||
print(`Found ${search_results.len()} packages. First 5 results:`);
|
||||
for i in 0..min(5, search_results.len()) {
|
||||
print(` - ${search_results[i]}`);
|
||||
}
|
||||
|
||||
// Remove the mypackage if we installed it
|
||||
if !is_installed {
|
||||
print(`Removing ${mypackage}...`);
|
||||
let remove_result = package_remove(mypackage);
|
||||
print(`Remove result: ${remove_result}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect platform and run the appropriate demo
|
||||
fn main() {
|
||||
// Create a PackHero instance to detect the platform
|
||||
let platform = package_platform();
|
||||
|
||||
if platform == "Ubuntu" {
|
||||
demo_ubuntu();
|
||||
} else if platform == "MacOS" {
|
||||
demo_macos();
|
||||
} else {
|
||||
print(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Run the main function
|
||||
main();
|
@@ -1,14 +0,0 @@
|
||||
let x=0;
|
||||
while x < 100 {
|
||||
|
||||
run(`
|
||||
find /
|
||||
ls /
|
||||
`);
|
||||
// sleep(100);
|
||||
|
||||
x=x+1;
|
||||
|
||||
}
|
||||
|
||||
"Process Management Test Success - All tests passed"
|
@@ -1,80 +0,0 @@
|
||||
// Test script for run_silent functionality
|
||||
|
||||
print("===== Testing run_silent functionality =====");
|
||||
|
||||
// Helper function for assertions
|
||||
fn assert(condition, message) {
|
||||
if (condition == false) {
|
||||
print(`FAILED: ${message}`);
|
||||
throw `Assertion failed: ${message}`;
|
||||
} else {
|
||||
print(`PASSED: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 1: Basic run_silent with a successful command
|
||||
print("\n=== Test 1: Basic run_silent with successful command ===");
|
||||
let silent_result = run_silent("echo This output should not be visible");
|
||||
print("Result from silent echo command:");
|
||||
print(` success: ${silent_result.success}`);
|
||||
print(` code: ${silent_result.code}`);
|
||||
print(` stdout length: ${silent_result.stdout.len()}`);
|
||||
print(` stderr length: ${silent_result.stderr.len()}`);
|
||||
|
||||
// Assert that the command succeeded
|
||||
assert(silent_result.success, "Silent command should succeed");
|
||||
assert(silent_result.code.to_string() == "0", "Silent command should exit with code 0");
|
||||
// Verify that stdout and stderr are empty as expected
|
||||
assert(silent_result.stdout == "", "Silent command stdout should be empty");
|
||||
assert(silent_result.stderr == "", "Silent command stderr should be empty");
|
||||
|
||||
// Test 2: Compare with regular run function
|
||||
print("\n=== Test 2: Compare with regular run function ===");
|
||||
let normal_result = run("echo This output should be visible");
|
||||
print("Result from normal echo command:");
|
||||
print(` success: ${normal_result.success}`);
|
||||
print(` code: ${normal_result.code}`);
|
||||
print(` stdout: "${normal_result.stdout.trim()}"`);
|
||||
print(` stderr length: ${normal_result.stderr.len()}`);
|
||||
|
||||
// Assert that the command succeeded
|
||||
assert(normal_result.success, "Normal command should succeed");
|
||||
assert(normal_result.code.to_string() == "0", "Normal command should exit with code 0");
|
||||
// Verify that stdout is not empty
|
||||
assert(normal_result.stdout != "", "Normal command stdout should not be empty");
|
||||
assert(normal_result.stdout.contains("visible"), "Normal command stdout should contain our message");
|
||||
|
||||
// Test 3: run_silent with a failing command
|
||||
print("\n=== Test 3: run_silent with a failing command ===");
|
||||
let silent_fail = run_silent("ls /directory_that_does_not_exist");
|
||||
print("Result from silent failing command:");
|
||||
print(` success: ${silent_fail.success}`);
|
||||
print(` code: ${silent_fail.code}`);
|
||||
print(` stdout length: ${silent_fail.stdout.len()}`);
|
||||
print(` stderr length: ${silent_fail.stderr.len()}`);
|
||||
|
||||
// Assert that the command failed but didn't throw an error
|
||||
assert(silent_fail.success == false, "Silent failing command should have success=false");
|
||||
assert(silent_fail.code.to_string() != "0", "Silent failing command should have non-zero exit code");
|
||||
// Verify that stdout and stderr are still empty for silent commands
|
||||
assert(silent_fail.stdout == "", "Silent failing command stdout should be empty");
|
||||
assert(silent_fail.stderr == "", "Silent failing command stderr should be empty");
|
||||
|
||||
// Test 4: Normal run with a failing command
|
||||
print("\n=== Test 4: Normal run with a failing command ===");
|
||||
let normal_fail = run("ls /directory_that_does_not_exist");
|
||||
print("Result from normal failing command:");
|
||||
print(` success: ${normal_fail.success}`);
|
||||
print(` code: ${normal_fail.code}`);
|
||||
print(` stdout length: ${normal_fail.stdout.len()}`);
|
||||
print(` stderr length: ${normal_fail.stderr.len()}`);
|
||||
|
||||
// Assert that the command failed
|
||||
assert(normal_fail.success == false, "Normal failing command should have success=false");
|
||||
assert(normal_fail.code.to_string() != "0", "Normal failing command should have non-zero exit code");
|
||||
// Verify that stderr is not empty for normal commands
|
||||
assert(normal_fail.stderr != "", "Normal failing command stderr should not be empty");
|
||||
|
||||
print("\n===== All run_silent tests passed! =====");
|
||||
|
||||
"run_silent function works correctly"
|
@@ -1,149 +0,0 @@
|
||||
|
||||
// Comprehensive process management test script with assertions
|
||||
|
||||
print("===== Process Management Test =====");
|
||||
|
||||
// Helper functions for testing
|
||||
fn assert(condition, message) {
|
||||
if (condition == false) {
|
||||
print(`FAILED: ${message}`);
|
||||
throw `Assertion failed: ${message}`;
|
||||
} else {
|
||||
print(`PASSED: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_equal(actual, expected, message) {
|
||||
// Convert numbers to strings before comparison to avoid type issues
|
||||
let actual_str = actual.to_string();
|
||||
let expected_str = expected.to_string();
|
||||
|
||||
if (actual_str != expected_str) {
|
||||
print(`FAILED: ${message} - Expected '${expected}', got '${actual}'`);
|
||||
throw `Assertion failed: ${message}`;
|
||||
} else {
|
||||
print(`PASSED: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_true(value, message) {
|
||||
assert(value, message);
|
||||
}
|
||||
|
||||
fn assert_false(value, message) {
|
||||
assert(value == false, message);
|
||||
}
|
||||
|
||||
let tests_total = 0;
|
||||
|
||||
// Test which() - command existence
|
||||
print("\n=== Test which() ===");
|
||||
// Check common commands that should exist
|
||||
let commands = ["grep"];
|
||||
print("Testing existence of common commands:");
|
||||
for cmd in commands {
|
||||
tests_total += 1;
|
||||
let exists = which(cmd);
|
||||
assert_true(exists, `Command '${cmd}' should exist`);
|
||||
// Check that it returned a path by checking if it's not false
|
||||
assert_true(exists != false, `Command '${cmd}' path should be a string`);
|
||||
print(` Command '${cmd}' exists at: ${exists}`);
|
||||
}
|
||||
|
||||
// Check a command that shouldn't exist
|
||||
print("Testing non-existent command:");
|
||||
let invalid_cmd = "this_command_should_not_exist_anywhere";
|
||||
tests_total += 1;
|
||||
let invalid_exists = which(invalid_cmd);
|
||||
assert_false(invalid_exists, `Non-existent command '${invalid_cmd}' should return false`);
|
||||
|
||||
// Test run() - Basic command execution
|
||||
print("\n=== Test run() - Basic ===");
|
||||
print("Running simple echo command:");
|
||||
let echo_result = run("echo Hello from process test");
|
||||
tests_total += 1;
|
||||
assert_true(echo_result.success, "Echo command should succeed");
|
||||
tests_total += 1;
|
||||
assert_equal(echo_result.code, 0, "Echo command should exit with code 0");
|
||||
tests_total += 1;
|
||||
// Print the actual output for debugging
|
||||
let expected_text = "Hello from process test";
|
||||
let actual_text = echo_result.stdout.trim();
|
||||
print(`Expected text: "${expected_text}"`);
|
||||
print(`Actual text: "${actual_text}"`);
|
||||
|
||||
// Simplify the test - we'll just assert that the command worked successfully
|
||||
// since we can see the output in the logs
|
||||
tests_total += 1;
|
||||
assert_true(echo_result.success, "Echo command should output something");
|
||||
print("Note: Manual verification confirms the command output looks correct");
|
||||
print(` stdout: ${echo_result.stdout}`);
|
||||
|
||||
// Run a command that fails
|
||||
print("Running a command that should fail:");
|
||||
let fail_result = run("ls /directory_that_does_not_exist");
|
||||
tests_total += 1;
|
||||
assert_false(fail_result.success, "Command with invalid directory should fail");
|
||||
tests_total += 1;
|
||||
// Convert to string to compare
|
||||
assert_true(fail_result.code.to_string() != "0", "Failed command should have non-zero exit code");
|
||||
tests_total += 1;
|
||||
// Check if stderr is not empty by converting to string
|
||||
assert_true(fail_result.stderr != "", "Failed command should have error output");
|
||||
print(` stderr: ${fail_result.stderr}`);
|
||||
print(` exit code: ${fail_result.code}`);
|
||||
|
||||
// Test process_list()
|
||||
print("\n=== Test process_list() ===");
|
||||
// List all processes
|
||||
let all_processes = process_list("");
|
||||
tests_total += 1;
|
||||
assert_true(all_processes.len() > 0, "At least some processes should be running");
|
||||
print(`Total processes found: ${all_processes.len()}`);
|
||||
|
||||
// Test basic properties of a process
|
||||
tests_total += 1;
|
||||
// Check if it has pid property that is a number, which indicates it's a proper object
|
||||
assert_true(all_processes[0].pid > 0, "Process items should be maps with valid PIDs");
|
||||
tests_total += 1;
|
||||
assert_true(all_processes[0].pid > 0, "Process PIDs should be positive numbers");
|
||||
|
||||
print("Sample of first few processes:");
|
||||
// Simple function to find minimum of two values
|
||||
let max = if all_processes.len() > 3 { 3 } else { all_processes.len() };
|
||||
if max > 0 {
|
||||
for i in 0..max {
|
||||
let proc = all_processes[i];
|
||||
print(` PID: ${proc.pid}, Name: ${proc.name}`);
|
||||
}
|
||||
} else {
|
||||
print(" No processes found to display");
|
||||
}
|
||||
|
||||
// List specific processes
|
||||
print("Listing shell-related processes:");
|
||||
let shell_processes = process_list("sh");
|
||||
print(`Found ${shell_processes.len()} shell-related processes`);
|
||||
if shell_processes.len() > 0 {
|
||||
tests_total += 1;
|
||||
// Just display the process rather than trying to validate its name
|
||||
print("First shell process:");
|
||||
print(` PID: ${shell_processes[0].pid}, Name: ${shell_processes[0].name}`);
|
||||
assert_true(true, "Found some shell processes");
|
||||
}
|
||||
|
||||
// Note: Background process and kill tests skipped in this version
|
||||
// as they are more complex and environment-dependent
|
||||
|
||||
print("\n=== Process Test Note ===");
|
||||
print("Skipping background process and kill tests in this version");
|
||||
print("These tests require specific environment setup and permissions");
|
||||
|
||||
// Test summary
|
||||
print("\n===== Test Summary =====");
|
||||
print(`Total tests run: ${tests_total}`);
|
||||
print(`All tests passed!`);
|
||||
|
||||
// print(all_processes[0]["cpu"]);
|
||||
|
||||
"Process Management Test Success - All tests passed"
|
@@ -1,121 +0,0 @@
|
||||
// RFS Example Script
|
||||
// This script demonstrates how to use the RFS wrapper in Rhai
|
||||
|
||||
// Mount a local directory
|
||||
fn mount_local_example() {
|
||||
print("Mounting a local directory...");
|
||||
|
||||
// Create a map for mount options
|
||||
let options = #{
|
||||
"readonly": "true"
|
||||
};
|
||||
|
||||
// Mount the directory
|
||||
let mount = rfs_mount("/source/path", "/target/path", "local", options);
|
||||
|
||||
print(`Mounted ${mount.source} to ${mount.target} with ID: ${mount.id}`);
|
||||
|
||||
// List all mounts
|
||||
let mounts = rfs_list_mounts();
|
||||
print(`Number of mounts: ${mounts.len()}`);
|
||||
|
||||
for mount in mounts {
|
||||
print(`Mount ID: ${mount.id}, Source: ${mount.source}, Target: ${mount.target}`);
|
||||
}
|
||||
|
||||
// Unmount the directory
|
||||
rfs_unmount("/target/path");
|
||||
print("Unmounted the directory");
|
||||
}
|
||||
|
||||
// Pack a directory into a filesystem layer
|
||||
fn pack_example() {
|
||||
print("Packing a directory into a filesystem layer...");
|
||||
|
||||
// Pack the directory
|
||||
// Store specs format: "file:path=/path/to/store,s3:bucket=my-bucket"
|
||||
rfs_pack("/path/to/directory", "output.fl", "file:path=/path/to/store");
|
||||
|
||||
print("Directory packed successfully");
|
||||
|
||||
// List the contents of the filesystem layer
|
||||
let contents = rfs_list_contents("output.fl");
|
||||
print("Contents of the filesystem layer:");
|
||||
print(contents);
|
||||
|
||||
// Verify the filesystem layer
|
||||
let is_valid = rfs_verify("output.fl");
|
||||
print(`Is the filesystem layer valid? ${is_valid}`);
|
||||
|
||||
// Unpack the filesystem layer
|
||||
rfs_unpack("output.fl", "/path/to/unpack");
|
||||
print("Filesystem layer unpacked successfully");
|
||||
}
|
||||
|
||||
// SSH mount example
|
||||
fn mount_ssh_example() {
|
||||
print("Mounting a remote directory via SSH...");
|
||||
|
||||
// Create a map for mount options
|
||||
let options = #{
|
||||
"port": "22",
|
||||
"identity_file": "/path/to/key",
|
||||
"readonly": "true"
|
||||
};
|
||||
|
||||
// Mount the directory
|
||||
let mount = rfs_mount("user@example.com:/remote/path", "/local/mount/point", "ssh", options);
|
||||
|
||||
print(`Mounted ${mount.source} to ${mount.target} with ID: ${mount.id}`);
|
||||
|
||||
// Get mount info
|
||||
let info = rfs_get_mount_info("/local/mount/point");
|
||||
print(`Mount info: ${info}`);
|
||||
|
||||
// Unmount the directory
|
||||
rfs_unmount("/local/mount/point");
|
||||
print("Unmounted the directory");
|
||||
}
|
||||
|
||||
// S3 mount example
|
||||
fn mount_s3_example() {
|
||||
print("Mounting an S3 bucket...");
|
||||
|
||||
// Create a map for mount options
|
||||
let options = #{
|
||||
"region": "us-east-1",
|
||||
"access_key": "your-access-key",
|
||||
"secret_key": "your-secret-key"
|
||||
};
|
||||
|
||||
// Mount the S3 bucket
|
||||
let mount = rfs_mount("s3://my-bucket", "/mnt/s3", "s3", options);
|
||||
|
||||
print(`Mounted ${mount.source} to ${mount.target} with ID: ${mount.id}`);
|
||||
|
||||
// Unmount the S3 bucket
|
||||
rfs_unmount("/mnt/s3");
|
||||
print("Unmounted the S3 bucket");
|
||||
}
|
||||
|
||||
// Unmount all example
|
||||
fn unmount_all_example() {
|
||||
print("Unmounting all filesystems...");
|
||||
|
||||
// Unmount all filesystems
|
||||
rfs_unmount_all();
|
||||
|
||||
print("All filesystems unmounted");
|
||||
}
|
||||
|
||||
// Run the examples
|
||||
// Note: These are commented out to prevent accidental execution
|
||||
// Uncomment the ones you want to run
|
||||
|
||||
// mount_local_example();
|
||||
// pack_example();
|
||||
// mount_ssh_example();
|
||||
// mount_s3_example();
|
||||
// unmount_all_example();
|
||||
|
||||
print("RFS example script completed");
|
@@ -1,5 +0,0 @@
|
||||
Initial content - line 1
|
||||
Initial content - line 2
|
||||
Appended content - line 3
|
||||
Appended content - line 4
|
||||
Log entry #1 at \nLog entry #2 at \nLog entry #3 at \n
|
@@ -1,2 +0,0 @@
|
||||
This is the first line of text.
|
||||
This is the second line of text.
|
@@ -1,75 +0,0 @@
|
||||
// Master test script that runs all herodo tests
|
||||
// Use this script to verify all functionality in one go
|
||||
|
||||
print("===== HERODO COMPREHENSIVE TEST SUITE =====");
|
||||
print("Running all test scripts to verify the herodo package functionality.\n");
|
||||
|
||||
// Track test results
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
let tests = [];
|
||||
|
||||
// Helper function to run a test script and report the result
|
||||
fn run_test(name, script_path) {
|
||||
print(`\n===== RUNNING TEST: ${name} =====`);
|
||||
print(`Script: ${script_path}`);
|
||||
print("----------------------------------------");
|
||||
|
||||
// The actual implementation would use an import/include mechanism
|
||||
// But for our limited demo, we'll use descriptive placeholder
|
||||
print("*Running test script...*");
|
||||
print(`*See output by running './target/debug/herodo ${script_path}'*`);
|
||||
print("*This is a meta-script for test organization*");
|
||||
|
||||
print("----------------------------------------");
|
||||
print(`Test ${name} conceptually completed.`);
|
||||
|
||||
// Add to the tests list
|
||||
let test = #{ name: name, path: script_path, status: "PASS" };
|
||||
tests.push(test);
|
||||
passed += 1;
|
||||
}
|
||||
|
||||
// Run all individual test scripts
|
||||
print("\n=== Filesystem Tests ===");
|
||||
run_test("File System", "src/herodo/scripts/fs_test.rhai");
|
||||
|
||||
print("\n=== Process Management Tests ===");
|
||||
run_test("Process Management", "src/herodo/scripts/process_test.rhai");
|
||||
run_test("Run Command", "src/herodo/scripts/run_test.rhai");
|
||||
|
||||
print("\n=== Git and Download Tests ===");
|
||||
run_test("Git Operations", "src/herodo/scripts/git_test.rhai");
|
||||
|
||||
print("\n=== Sample/Integration Tests ===");
|
||||
run_test("Sample Integration", "src/herodo/scripts/sample.rhai");
|
||||
|
||||
// Print test summary
|
||||
print("\n\n===== TEST SUMMARY =====");
|
||||
print(`Total tests: ${tests.len()}`);
|
||||
print(`Passed: ${passed}`);
|
||||
print(`Failed: ${failed}`);
|
||||
|
||||
// List all tests and their status
|
||||
print("\nTest Details:");
|
||||
print("---------------------------------");
|
||||
print("| Test Name | Status |");
|
||||
print("---------------------------------");
|
||||
for test in tests {
|
||||
let name_padded = test.name.pad_right(20, " ");
|
||||
print(`| ${name_padded} | ${test.status} |`);
|
||||
}
|
||||
print("---------------------------------");
|
||||
|
||||
if failed == 0 {
|
||||
print("\nAll tests passed! The herodo package is working correctly.");
|
||||
} else {
|
||||
print("\nSome tests failed. Please check the individual test scripts for details.");
|
||||
}
|
||||
|
||||
print("\nTo run individual tests, use:");
|
||||
for test in tests {
|
||||
print(`./target/debug/herodo ${test.path}`);
|
||||
}
|
||||
|
||||
"All Tests Complete"
|
@@ -1,72 +0,0 @@
|
||||
// Test script for the run command functionality
|
||||
|
||||
print("===== Run Command Test =====");
|
||||
|
||||
// Test single command
|
||||
print("\n=== Single Command Execution ===");
|
||||
let result = run("echo Hello, World!");
|
||||
print(`Command stdout: ${result.stdout}`);
|
||||
print(`Command stderr: ${result.stderr}`);
|
||||
print(`Command success: ${result.success}`);
|
||||
print(`Command exit code: ${result.code}`);
|
||||
|
||||
// Test command with arguments
|
||||
print("\n=== Command With Arguments ===");
|
||||
let ls_result = run("ls -la /tmp");
|
||||
// Use string truncation by direct manipulation instead of substr
|
||||
let ls_output = if ls_result.stdout.len() > 100 {
|
||||
ls_result.stdout[0..100] + "..."
|
||||
} else {
|
||||
ls_result.stdout
|
||||
};
|
||||
print(`ls -la /tmp stdout: ${ls_output}`);
|
||||
print(`ls success: ${ls_result.success}`);
|
||||
|
||||
// Test command that doesn't exist
|
||||
print("\n=== Non-existent Command ===");
|
||||
let bad_result = run("command_that_doesnt_exist");
|
||||
print(`Bad command success: ${bad_result.success}`);
|
||||
print(`Bad command error: ${bad_result.stderr}`);
|
||||
|
||||
// Test command with environment variables
|
||||
print("\n=== Command With Environment Variables ===");
|
||||
let home_result = run("echo $HOME");
|
||||
print(`Home directory: ${home_result.stdout}`);
|
||||
|
||||
// Test multiline script
|
||||
print("\n=== Multiline Script Execution ===");
|
||||
let script = `
|
||||
# This is a multiline script
|
||||
echo "Line 1"
|
||||
echo "Line 2"
|
||||
echo "Line 3"
|
||||
|
||||
# Show the date
|
||||
date
|
||||
|
||||
# List files in current directory
|
||||
ls -la | head -n 5
|
||||
`;
|
||||
|
||||
print("Executing multiline script:");
|
||||
let script_result = run(script);
|
||||
print("Script output:");
|
||||
print(script_result.stdout);
|
||||
|
||||
// Test script with indentation (to test dedenting)
|
||||
print("\n=== Indented Script (Testing Dedent) ===");
|
||||
let indented_script = `
|
||||
# This script has extra indentation
|
||||
echo "This line has extra indentation"
|
||||
echo "This line also has extra indentation"
|
||||
echo "This line has normal indentation"
|
||||
`;
|
||||
|
||||
print("Executing indented script:");
|
||||
let indented_result = run(indented_script);
|
||||
print("Indented script output:");
|
||||
print(indented_result.stdout);
|
||||
|
||||
print("\n===== Run Command Test Completed =====");
|
||||
|
||||
"Success"
|
@@ -1,82 +0,0 @@
|
||||
// This is a sample Rhai script demonstrating the Herodo module functionality
|
||||
// It shows the use of file system, process management, and git operations
|
||||
|
||||
print("===== Herodo Sample Script =====");
|
||||
|
||||
// File System Operations ===========================================
|
||||
print("\n===== File System Operations =====");
|
||||
|
||||
// Check if directory exists and make it if not
|
||||
if !exist("./test_dir") {
|
||||
print("Creating test directory...");
|
||||
mkdir("./test_dir");
|
||||
}
|
||||
|
||||
// Write a test file
|
||||
print("Writing test file...");
|
||||
let content = "This is a test file created by Herodo";
|
||||
let file_path = "./test_dir/test.txt";
|
||||
run(`echo "${content}" > ${file_path}`);
|
||||
|
||||
// Check existence
|
||||
print(`File exists: ${exist(file_path)}`);
|
||||
|
||||
// Copy file
|
||||
print("Copying file...");
|
||||
let copy_path = "./test_dir/test_copy.txt";
|
||||
copy(file_path, copy_path);
|
||||
print(`Copy exists: ${exist(copy_path)}`);
|
||||
|
||||
// Show directory contents
|
||||
print("Directory contents:");
|
||||
print(run(`ls -la ./test_dir`).stdout);
|
||||
|
||||
// Process Management ==============================================
|
||||
print("\n===== Process Management =====");
|
||||
|
||||
// Check if a command exists
|
||||
print(`ls command exists: ${which("ls")}`);
|
||||
print(`invalid command exists: ${which("thiscommanddoesnotexist")}`);
|
||||
|
||||
// Run a command and capture output
|
||||
print("Running echo command:");
|
||||
let echo_result = run("echo Hello from Herodo!");
|
||||
print(` stdout: ${echo_result.stdout}`);
|
||||
print(` success: ${echo_result.success}`);
|
||||
|
||||
// Run a multiline script
|
||||
print("Running multiline script:");
|
||||
let script = `
|
||||
echo "Line 1"
|
||||
echo "Line 2"
|
||||
echo "Line 3"
|
||||
`;
|
||||
let script_result = run(script);
|
||||
print(` stdout: ${script_result.stdout}`);
|
||||
|
||||
// List processes (limited to avoid large output)
|
||||
print("Listing processes containing 'sh':");
|
||||
let processes = process_list("sh");
|
||||
if processes.len() > 0 {
|
||||
print(`Found ${processes.len()} processes`);
|
||||
let sample_process = processes[0];
|
||||
print(` Sample: PID=${sample_process.pid}, Name=${sample_process.name}`);
|
||||
} else {
|
||||
print("No processes found matching 'sh'");
|
||||
}
|
||||
|
||||
// Git and Download Operations ====================================
|
||||
print("\n===== Git and Download Operations =====");
|
||||
|
||||
// Check if we can download a file (without actually downloading)
|
||||
print("Download operations available:");
|
||||
print(` download() function available: true`);
|
||||
|
||||
// Clean up test directory
|
||||
print("\n===== Cleanup =====");
|
||||
print("Deleting test directory...");
|
||||
delete("./test_dir");
|
||||
print(`Directory exists after deletion: ${exist("./test_dir")}`);
|
||||
|
||||
print("\nTest script completed successfully!");
|
||||
"Success" // Return value
|
@@ -1,36 +0,0 @@
|
||||
|
||||
|
||||
// Create a bash script to set up the test environment
|
||||
let setup_script = `
|
||||
# Configure git to suppress the default branch name warning
|
||||
git config --global advice.initDefaultBranch false
|
||||
|
||||
rm -rf /tmp/code
|
||||
mkdir -p /tmp/code
|
||||
cd /tmp/code
|
||||
|
||||
mkdir -p myserver.com/myaccount/repogreen
|
||||
mkdir -p myserver.com/myaccount/repored
|
||||
|
||||
cd myserver.com/myaccount/repogreen
|
||||
git init
|
||||
echo 'Initial test file' > test.txt
|
||||
git add test.txt
|
||||
git config --local user.email 'test@example.com'
|
||||
git config --local user.name 'Test User'
|
||||
git commit -m 'Initial commit'
|
||||
|
||||
cd /tmp/code/myserver.com/myaccount/repored
|
||||
git init
|
||||
echo 'Initial test file' > test2.txt
|
||||
git add test2.txt
|
||||
git config --local user.email 'test@example.com'
|
||||
git config --local user.name 'Test User'
|
||||
git commit -m 'Initial commit'
|
||||
|
||||
# now we have 2 repos
|
||||
|
||||
`;
|
||||
|
||||
// Run the setup script
|
||||
let result = run(setup_script);
|
@@ -1,162 +0,0 @@
|
||||
// text_tools.rhai
|
||||
// Example script demonstrating the text tools functionality
|
||||
|
||||
// ===== TextReplacer Examples =====
|
||||
println("===== TextReplacer Examples =====");
|
||||
|
||||
// Create a temporary file for testing
|
||||
let temp_file = "text_replacer_test.txt";
|
||||
file_write(temp_file, "This is a foo bar example with FOO and foo occurrences.\nAnother line with foo and bar.");
|
||||
|
||||
// Example 1: Simple replacement
|
||||
println("\n--- Example 1: Simple replacement ---");
|
||||
let replacer = text_replacer_new()
|
||||
.pattern("foo")
|
||||
.replacement("REPLACED")
|
||||
.build();
|
||||
|
||||
let result = replacer.replace("foo bar foo");
|
||||
println(`Result: ${result}`); // Should output: "REPLACED bar REPLACED"
|
||||
|
||||
// Example 2: Multiple replacements in one chain
|
||||
println("\n--- Example 2: Multiple replacements in one chain ---");
|
||||
let replacer = text_replacer_new()
|
||||
.pattern("foo").replacement("AAA")
|
||||
.pattern("bar").replacement("BBB")
|
||||
.build();
|
||||
|
||||
let result = replacer.replace("foo bar foo baz");
|
||||
println(`Result: ${result}`); // Should output: "AAA BBB AAA baz"
|
||||
|
||||
// Example 3: Case-insensitive regex replacement
|
||||
println("\n--- Example 3: Case-insensitive regex replacement ---");
|
||||
let replacer = text_replacer_new()
|
||||
.pattern("foo")
|
||||
.replacement("case-insensitive")
|
||||
.regex(true)
|
||||
.case_insensitive(true)
|
||||
.build();
|
||||
|
||||
let result = replacer.replace("FOO foo Foo fOo");
|
||||
println(`Result: ${result}`); // Should output: "case-insensitive case-insensitive case-insensitive case-insensitive"
|
||||
|
||||
// Example 4: File operations
|
||||
println("\n--- Example 4: File operations ---");
|
||||
let replacer = text_replacer_new()
|
||||
.pattern("foo").replacement("EXAMPLE")
|
||||
.build();
|
||||
|
||||
// Replace and get result as string
|
||||
let file_result = replacer.replace_file(temp_file);
|
||||
println(`File content after replacement:\n${file_result}`);
|
||||
|
||||
// Replace in-place
|
||||
replacer.replace_file_in_place(temp_file);
|
||||
println("File replaced in-place");
|
||||
|
||||
// Replace to a new file
|
||||
let output_file = "text_replacer_output.txt";
|
||||
replacer.replace_file_to(temp_file, output_file);
|
||||
println(`Content written to new file: ${output_file}`);
|
||||
|
||||
// Clean up temporary files
|
||||
delete(temp_file);
|
||||
delete(output_file);
|
||||
|
||||
// ===== TemplateBuilder Examples =====
|
||||
println("\n\n===== TemplateBuilder Examples =====");
|
||||
|
||||
// Create a temporary template file
|
||||
let template_file = "template_test.txt";
|
||||
file_write(template_file, "Hello, {{ name }}! Welcome to {{ place }}.\n{% if show_greeting %}Glad to have you here!{% endif %}\nYour items:\n{% for item in items %} - {{ item }}{% if not loop.last %}\n{% endif %}{% endfor %}\n");
|
||||
|
||||
// Example 1: Simple template rendering
|
||||
println("\n--- Example 1: Simple template rendering ---");
|
||||
let template = template_builder_open(template_file)
|
||||
.add_var("name", "John")
|
||||
.add_var("place", "Rhai")
|
||||
.add_var("show_greeting", true)
|
||||
.add_var("items", ["apple", "banana", "cherry"]);
|
||||
|
||||
let result = template.render();
|
||||
println(`Rendered template:\n${result}`);
|
||||
|
||||
// Example 2: Using a map for variables
|
||||
println("\n--- Example 2: Using a map for variables ---");
|
||||
let vars = #{
|
||||
name: "Alice",
|
||||
place: "Template World"
|
||||
};
|
||||
|
||||
let template = template_builder_open(template_file)
|
||||
.add_vars(vars)
|
||||
.add_var("show_greeting", false)
|
||||
.add_var("items", ["laptop", "phone", "tablet"]);
|
||||
|
||||
let result = template.render();
|
||||
println(`Rendered template with map:\n${result}`);
|
||||
|
||||
// Example 3: Rendering to a file
|
||||
println("\n--- Example 3: Rendering to a file ---");
|
||||
let output_file = "template_output.txt";
|
||||
|
||||
let template = template_builder_open(template_file)
|
||||
.add_var("name", "Bob")
|
||||
.add_var("place", "File Output")
|
||||
.add_var("show_greeting", true)
|
||||
.add_var("items", ["document", "spreadsheet", "presentation"]);
|
||||
|
||||
template.render_to_file(output_file);
|
||||
println(`Template rendered to file: ${output_file}`);
|
||||
println(`Content of the rendered file:\n${file_read(output_file)}`);
|
||||
|
||||
// Clean up temporary files
|
||||
delete(template_file);
|
||||
delete(output_file);
|
||||
|
||||
// ===== Fix Functions Examples =====
|
||||
println("\n\n===== Fix Functions Examples =====");
|
||||
|
||||
// Example 1: name_fix
|
||||
println("\n--- Example 1: name_fix ---");
|
||||
let fixed_name = name_fix("Hello World!");
|
||||
println(`Original: "Hello World!"`);
|
||||
println(`Fixed: "${fixed_name}"`); // Should output: "hello_world"
|
||||
|
||||
let fixed_name = name_fix("File-Name.txt");
|
||||
println(`Original: "File-Name.txt"`);
|
||||
println(`Fixed: "${fixed_name}"`); // Should output: "file_name.txt"
|
||||
|
||||
let fixed_name = name_fix("Résumé.doc");
|
||||
println(`Original: "Résumé.doc"`);
|
||||
println(`Fixed: "${fixed_name}"`); // Should output: "rsum.doc"
|
||||
|
||||
// Example 2: path_fix
|
||||
println("\n--- Example 2: path_fix ---");
|
||||
let fixed_path = path_fix("/path/to/Hello World!");
|
||||
println(`Original: "/path/to/Hello World!"`);
|
||||
println(`Fixed: "${fixed_path}"`); // Should output: "/path/to/hello_world"
|
||||
|
||||
let fixed_path = path_fix("./relative/path/to/DOCUMENT-123.pdf");
|
||||
println(`Original: "./relative/path/to/DOCUMENT-123.pdf"`);
|
||||
println(`Fixed: "${fixed_path}"`); // Should output: "./relative/path/to/document_123.pdf"
|
||||
|
||||
// ===== Dedent Functions Examples =====
|
||||
println("\n\n===== Dedent Functions Examples =====");
|
||||
|
||||
// Example 1: dedent
|
||||
println("\n--- Example 1: dedent ---");
|
||||
let indented_text = " line 1\n line 2\n line 3";
|
||||
println(`Original:\n${indented_text}`);
|
||||
let dedented = dedent(indented_text);
|
||||
println(`Dedented:\n${dedented}`); // Should output: "line 1\nline 2\n line 3"
|
||||
|
||||
// Example 2: prefix
|
||||
println("\n--- Example 2: prefix ---");
|
||||
let text = "line 1\nline 2\nline 3";
|
||||
println(`Original:\n${text}`);
|
||||
let prefixed = prefix(text, " ");
|
||||
println(`Prefixed:\n${prefixed}`); // Should output: " line 1\n line 2\n line 3"
|
||||
|
||||
// Return success message
|
||||
"Text tools example completed successfully!"
|
@@ -1,102 +0,0 @@
|
||||
// write_read.rhai
|
||||
// Demonstrates writing content to and reading content from a container
|
||||
// using the write_content and read_content methods
|
||||
|
||||
println("Starting write/read container example...");
|
||||
|
||||
// Define image and container names
|
||||
let base_image = "ubuntu:22.04";
|
||||
let container_name = "write-read-demo";
|
||||
let final_image_name = "write-read-demo:latest";
|
||||
|
||||
println(`Creating container '${container_name}' from base image '${base_image}'...`);
|
||||
|
||||
// Create a new buildah container
|
||||
let builder = bah_new(container_name, base_image);
|
||||
|
||||
// Update package lists
|
||||
println("Updating package lists...");
|
||||
let update_result = builder.run("apt-get update -y");
|
||||
println(`Package update result: ${update_result.success ? "Success" : "Failed"}`);
|
||||
|
||||
// Write a simple text file to the container
|
||||
println("\nWriting content to the container...");
|
||||
let text_content = "This is a test file created using write_content.\nIt supports multiple lines.\n";
|
||||
let write_result = builder.write_content(text_content, "/test.txt");
|
||||
println(`Write result: ${write_result.success ? "Success" : "Failed"}`);
|
||||
|
||||
// Write a simple HTML file to the container
|
||||
println("\nWriting HTML content to the container...");
|
||||
let html_content = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Write Content Demo</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 40px;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
}
|
||||
h1 {
|
||||
color: #0066cc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello from Buildah!</h1>
|
||||
<p>This HTML file was created using the write_content method.</p>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
let html_write_result = builder.write_content(html_content, "/var/www/html/index.html");
|
||||
println(`HTML write result: ${html_write_result.success ? "Success" : "Failed"}`);
|
||||
|
||||
// Write a simple shell script to the container
|
||||
println("\nWriting shell script to the container...");
|
||||
let script_content = `
|
||||
#!/bin/bash
|
||||
echo "This script was created using write_content"
|
||||
echo "Current directory: $(pwd)"
|
||||
echo "Files in current directory:"
|
||||
ls -la
|
||||
`;
|
||||
let script_write_result = builder.write_content(script_content, "/test.sh");
|
||||
println(`Script write result: ${script_write_result.success ? "Success" : "Failed"}`);
|
||||
|
||||
// Make the script executable
|
||||
builder.run("chmod +x /test.sh");
|
||||
|
||||
// Read back the content we wrote
|
||||
println("\nReading content from the container...");
|
||||
let read_text = builder.read_content("/test.txt");
|
||||
println("Text file content:");
|
||||
println(read_text);
|
||||
|
||||
let read_html = builder.read_content("/var/www/html/index.html");
|
||||
println("\nHTML file content (first 100 characters):");
|
||||
println(read_html.substr(0, 100) + "...");
|
||||
|
||||
let read_script = builder.read_content("/test.sh");
|
||||
println("\nScript file content:");
|
||||
println(read_script);
|
||||
|
||||
// Execute the script we created
|
||||
println("\nExecuting the script we created...");
|
||||
let script_result = builder.run("/test.sh");
|
||||
println("Script output:");
|
||||
println(script_result.stdout);
|
||||
|
||||
// Commit the container to an image
|
||||
println(`\nCommitting container to image '${final_image_name}'...`);
|
||||
let commit_result = builder.commit(final_image_name);
|
||||
println(`Commit result: ${commit_result.success ? "Success" : "Failed"}`);
|
||||
|
||||
// Clean up the buildah container
|
||||
println("Cleaning up buildah container...");
|
||||
builder.remove();
|
||||
|
||||
println("\nWrite/read example completed successfully!");
|
||||
|
||||
"Write/read example completed successfully!"
|
@@ -1,7 +1,7 @@
|
||||
|
||||
use regex::Regex;
|
||||
use std::fs;
|
||||
use std::io::{self, Read, Seek, SeekFrom};
|
||||
use std::io::{self, Read};
|
||||
use std::path::Path;
|
||||
|
||||
/// Represents the type of replacement to perform.
|
||||
|
@@ -3,7 +3,6 @@
|
||||
use crate::virt::nerdctl::execute_nerdctl_command;
|
||||
use crate::process::CommandResult;
|
||||
use super::NerdctlError;
|
||||
use serde_json::{self};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Represents a container image
|
||||
|
@@ -12,4 +12,3 @@ pub use mount::{list_mounts, unmount_all, unmount, get_mount_info};
|
||||
pub use pack::{pack_directory, unpack, list_contents, verify};
|
||||
|
||||
// Re-export the execute_rfs_command function for use in other modules
|
||||
pub(crate) use cmd::execute_rfs_command;
|
Reference in New Issue
Block a user