From 4be9445702c7cd895ceeac636eb0c612457770f8 Mon Sep 17 00:00:00 2001 From: despiegk Date: Sat, 5 Apr 2025 09:56:10 +0200 Subject: [PATCH] ... --- Cargo.toml | 1 + src/examples/template_example.rs | 66 ++++++++++++++++++++++++++++++ src/rhai/buildah.rs | 20 +++++++-- src/text/mod.rs | 4 +- src/text/template.rs | 21 +++++----- src/virt/buildah/builder.rs | 15 +++++++ src/virt/buildah/content.rs | 70 ++++++++++++++++++++++++++++++++ src/virt/buildah/mod.rs | 4 +- 8 files changed, 185 insertions(+), 16 deletions(-) create mode 100644 src/examples/template_example.rs create mode 100644 src/virt/buildah/content.rs diff --git a/Cargo.toml b/Cargo.toml index 07fa450..d607ded 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ categories = ["os", "filesystem", "api-bindings"] readme = "README.md" [dependencies] +tera = "1.19.0" # Template engine for text rendering # Cross-platform functionality libc = "0.2" cfg-if = "1.0" diff --git a/src/examples/template_example.rs b/src/examples/template_example.rs new file mode 100644 index 0000000..6474b7b --- /dev/null +++ b/src/examples/template_example.rs @@ -0,0 +1,66 @@ +use std::collections::HashMap; +use std::error::Error; +use std::fs::File; +use std::io::Write; +use tempfile::NamedTempFile; + +use sal::text::TemplateBuilder; + +fn main() -> Result<(), Box> { + // Create a temporary template file for our examples + let temp_file = NamedTempFile::new()?; + let template_content = "Hello, {{ name }}! Welcome to {{ place }}.\n\ +{% if show_greeting %}Glad to have you here!{% endif %}\n\ +Your items:\n\ +{% for item in items %} - {{ item }}{% if not loop.last %}\n{% endif %}{% endfor %}\n"; + std::fs::write(temp_file.path(), template_content)?; + + println!("Created temporary template at: {}", temp_file.path().display()); + + // Example 1: Simple variable replacement + println!("\n--- Example 1: Simple variable replacement ---"); + let mut builder = TemplateBuilder::open(temp_file.path())?; + builder = builder + .add_var("name", "John") + .add_var("place", "Rust") + .add_var("show_greeting", true) + .add_var("items", vec!["apple", "banana", "cherry"]); + + let result = builder.render()?; + println!("Rendered template:\n{}", result); + + // Example 2: Using a HashMap for variables + println!("\n--- Example 2: Using a HashMap for variables ---"); + let mut vars = HashMap::new(); + vars.insert("name", "Alice"); + vars.insert("place", "Template World"); + + let mut builder = TemplateBuilder::open(temp_file.path())?; + builder = builder + .add_vars(vars) + .add_var("show_greeting", false) + .add_var("items", vec!["laptop", "phone", "tablet"]); + + let result = builder.render()?; + println!("Rendered template with HashMap:\n{}", result); + + // Example 3: Rendering to a file + println!("\n--- Example 3: Rendering to a file ---"); + let output_file = NamedTempFile::new()?; + + let mut builder = TemplateBuilder::open(temp_file.path())?; + builder = builder + .add_var("name", "Bob") + .add_var("place", "File Output") + .add_var("show_greeting", true) + .add_var("items", vec!["document", "spreadsheet", "presentation"]); + + builder.render_to_file(output_file.path())?; + println!("Template rendered to file: {}", output_file.path().display()); + + // Read the output file to verify + let output_content = std::fs::read_to_string(output_file.path())?; + println!("Content of the rendered file:\n{}", output_content); + + Ok(()) +} \ No newline at end of file diff --git a/src/rhai/buildah.rs b/src/rhai/buildah.rs index e0c7487..34fec7f 100644 --- a/src/rhai/buildah.rs +++ b/src/rhai/buildah.rs @@ -4,7 +4,7 @@ use rhai::{Engine, EvalAltResult, Array, Dynamic, Map}; use std::collections::HashMap; -use crate::virt::buildah::{self, BuildahError, Image, Builder}; +use crate::virt::buildah::{self, BuildahError, Image, Builder, ContentOperations}; use crate::process::CommandResult; /// Register Buildah module functions with the Rhai engine @@ -150,12 +150,26 @@ pub fn builder_config(builder: &mut Builder, options: Map) -> Result Result> { - bah_error_to_rhai_error(builder.write_content(content, dest_path)) + if let Some(container_id) = builder.container_id() { + bah_error_to_rhai_error(ContentOperations::write_content(container_id, content, dest_path)) + } else { + Err(Box::new(EvalAltResult::ErrorRuntime( + "No container ID available".into(), + rhai::Position::NONE + ))) + } } /// Read content from a file in the container pub fn builder_read_content(builder: &mut Builder, source_path: &str) -> Result> { - bah_error_to_rhai_error(builder.read_content(source_path)) + if let Some(container_id) = builder.container_id() { + bah_error_to_rhai_error(ContentOperations::read_content(container_id, source_path)) + } else { + Err(Box::new(EvalAltResult::ErrorRuntime( + "No container ID available".into(), + rhai::Position::NONE + ))) + } } // Builder static methods diff --git a/src/text/mod.rs b/src/text/mod.rs index fceb8ed..584aab4 100644 --- a/src/text/mod.rs +++ b/src/text/mod.rs @@ -1,7 +1,9 @@ mod dedent; mod fix; mod replace; +mod template; pub use dedent::*; pub use fix::*; -pub use replace::*; \ No newline at end of file +pub use replace::*; +pub use template::*; \ No newline at end of file diff --git a/src/text/template.rs b/src/text/template.rs index 49652de..3c88963 100644 --- a/src/text/template.rs +++ b/src/text/template.rs @@ -210,9 +210,9 @@ mod tests { #[test] fn test_template_rendering() -> Result<(), Box> { // Create a temporary template file - let mut temp_file = NamedTempFile::new()?; - writeln!(temp_file, "Hello, {{ name }}! Welcome to {{ place }}.")?; - temp_file.flush()?; + let temp_file = NamedTempFile::new()?; + let template_content = "Hello, {{ name }}! Welcome to {{ place }}.\n"; + fs::write(temp_file.path(), template_content)?; // Create a template builder and add variables let mut builder = TemplateBuilder::open(temp_file.path())?; @@ -230,10 +230,9 @@ mod tests { #[test] fn test_template_with_multiple_vars() -> Result<(), Box> { // Create a temporary template file - let mut temp_file = NamedTempFile::new()?; - writeln!(temp_file, "{% if show_greeting %}Hello, {{ name }}!{% endif %}")?; - writeln!(temp_file, "{% for item in items %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}")?; - temp_file.flush()?; + let temp_file = NamedTempFile::new()?; + let template_content = "{% if show_greeting %}Hello, {{ name }}!{% endif %}\n{% for item in items %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}\n"; + fs::write(temp_file.path(), template_content)?; // Create a template builder and add variables let mut builder = TemplateBuilder::open(temp_file.path())?; @@ -273,13 +272,13 @@ mod tests { Ok(()) } - #[test] fn test_render_to_file() -> Result<(), Box> { // Create a temporary template file - let mut temp_file = NamedTempFile::new()?; - writeln!(temp_file, "{{ message }}")?; - temp_file.flush()?; + let temp_file = NamedTempFile::new()?; + let template_content = "{{ message }}\n"; + fs::write(temp_file.path(), template_content)?; + // Create an output file let output_file = NamedTempFile::new()?; diff --git a/src/virt/buildah/builder.rs b/src/virt/buildah/builder.rs index 9eb3cbb..e480f0d 100644 --- a/src/virt/buildah/builder.rs +++ b/src/virt/buildah/builder.rs @@ -11,6 +11,8 @@ pub struct Builder { container_id: Option, /// Base image image: String, + /// Debug mode + debug: bool, } impl Builder { @@ -37,6 +39,7 @@ impl Builder { name: name.to_string(), container_id: Some(container_id), image: image.to_string(), + debug: false, }) }, Err(BuildahError::CommandFailed(error_msg)) => { @@ -58,6 +61,7 @@ impl Builder { name: name.to_string(), container_id: Some(container_id), image: image.to_string(), + debug: false, }) } else { // Couldn't extract container ID @@ -85,6 +89,17 @@ impl Builder { &self.name } + /// Get the debug mode + pub fn debug(&self) -> bool { + self.debug + } + + /// Set the debug mode + pub fn set_debug(&mut self, debug: bool) -> &mut Self { + self.debug = debug; + self + } + /// Get the base image pub fn image(&self) -> &str { &self.image diff --git a/src/virt/buildah/content.rs b/src/virt/buildah/content.rs new file mode 100644 index 0000000..e6811ee --- /dev/null +++ b/src/virt/buildah/content.rs @@ -0,0 +1,70 @@ +use crate::process::CommandResult; +use crate::virt::buildah::{execute_buildah_command, BuildahError}; +use std::fs::File; +use std::io::{Read, Write}; +use tempfile::NamedTempFile; + +/// Functions for working with file content in buildah containers +pub struct ContentOperations; + +impl ContentOperations { + /// Write content to a file in the container + /// + /// # Arguments + /// + /// * `container_id` - The container ID + /// * `content` - The content to write + /// * `dest_path` - Destination path in the container + /// + /// # Returns + /// + /// * `Result` - Command result or error + pub fn write_content(container_id: &str, content: &str, dest_path: &str) -> Result { + // Create a temporary file + let mut temp_file = NamedTempFile::new() + .map_err(|e| BuildahError::Other(format!("Failed to create temporary file: {}", e)))?; + + // Write content to the temporary file + temp_file.write_all(content.as_bytes()) + .map_err(|e| BuildahError::Other(format!("Failed to write to temporary file: {}", e)))?; + + // Flush the file to ensure content is written + temp_file.flush() + .map_err(|e| BuildahError::Other(format!("Failed to flush temporary file: {}", e)))?; + + // Copy the temporary file to the container + let temp_path = temp_file.path().to_string_lossy().to_string(); + execute_buildah_command(&["copy", container_id, &temp_path, dest_path]) + } + + /// Read content from a file in the container + /// + /// # Arguments + /// + /// * `container_id` - The container ID + /// * `source_path` - Source path in the container + /// + /// # Returns + /// + /// * `Result` - File content or error + pub fn read_content(container_id: &str, source_path: &str) -> Result { + // Create a temporary file + let temp_file = NamedTempFile::new() + .map_err(|e| BuildahError::Other(format!("Failed to create temporary file: {}", e)))?; + + let temp_path = temp_file.path().to_string_lossy().to_string(); + + // Copy the file from the container to the temporary file + execute_buildah_command(&["copy", container_id, source_path, &temp_path])?; + + // Read the content from the temporary file + let mut file = File::open(temp_file.path()) + .map_err(|e| BuildahError::Other(format!("Failed to open temporary file: {}", e)))?; + + let mut content = String::new(); + file.read_to_string(&mut content) + .map_err(|e| BuildahError::Other(format!("Failed to read from temporary file: {}", e)))?; + + Ok(content) + } +} \ No newline at end of file diff --git a/src/virt/buildah/mod.rs b/src/virt/buildah/mod.rs index 4bf641b..619fa19 100644 --- a/src/virt/buildah/mod.rs +++ b/src/virt/buildah/mod.rs @@ -2,6 +2,7 @@ mod containers; mod images; mod cmd; mod builder; +mod content; #[cfg(test)] mod containers_test; @@ -52,4 +53,5 @@ pub use builder::Builder; pub use containers::*; #[deprecated(since = "0.2.0", note = "Use Builder methods instead")] pub use images::*; -pub use cmd::*; \ No newline at end of file +pub use cmd::*; +pub use content::ContentOperations; \ No newline at end of file