# Buildah Debug Implementation Plan ## Current State 1. The `Builder` struct already has a `debug` field and methods to get and set it (`debug()` and `set_debug()`). 2. There's a thread-local `DEBUG` variable with functions to get and set it. 3. The `execute_buildah_command` function checks the thread-local debug flag and outputs some debug information. 4. There's an unused `execute_buildah_command_with_debug` function that takes a `Builder` reference. ## Requirements 1. Use only the Builder's debug flag, not the thread-local debug flag. 2. When debug is true, output stdout/stderr regardless of whether the command succeeds or fails. 3. If debug is false but there's an error, still output all information. ## Implementation Plan ### 1. Keep the Existing Thread-Local DEBUG Variable We'll keep the existing thread-local DEBUG variable that's already in the code: ```rust // Thread-local storage for debug flag thread_local! { static DEBUG: std::cell::RefCell = std::cell::RefCell::new(false); } ``` ### 2. Modify the Builder Methods to Set/Clear the Thread-Local Debug Flag We'll modify each Builder method to set the thread-local debug flag from the Builder's debug flag before calling `execute_buildah_command` and restore it afterward: ```rust pub fn run(&self, command: &str) -> Result { if let Some(container_id) = &self.container_id { // Save the current debug flag let previous_debug = thread_local_debug(); // Set the thread-local debug flag from the Builder's debug flag set_thread_local_debug(self.debug); // Execute the command let result = execute_buildah_command(&["run", container_id, "sh", "-c", command]); // Restore the previous debug flag set_thread_local_debug(previous_debug); result } else { Err(BuildahError::Other("No container ID available".to_string())) } } ``` ### 3. Keep the Existing execute_buildah_command Function The existing `execute_buildah_command` function already checks the thread-local debug flag, so we don't need to modify it: ```rust pub fn execute_buildah_command(args: &[&str]) -> Result { // Get the debug flag from thread-local storage let debug = thread_local_debug(); if debug { println!("Executing buildah command: buildah {}", args.join(" ")); } // ... rest of the function ... } ``` ### 4. Update the execute_buildah_command Function to Output stdout/stderr We need to modify the `execute_buildah_command` function to output stdout/stderr when debug is true, regardless of success/failure: ```rust pub fn execute_buildah_command(args: &[&str]) -> Result { // Get the debug flag from thread-local storage let debug = thread_local_debug(); if debug { println!("Executing buildah command: buildah {}", args.join(" ")); } let output = Command::new("buildah") .args(args) .output(); match output { Ok(output) => { let stdout = String::from_utf8_lossy(&output.stdout).to_string(); let stderr = String::from_utf8_lossy(&output.stderr).to_string(); let result = CommandResult { stdout, stderr, success: output.status.success(), code: output.status.code().unwrap_or(-1), }; // Always output stdout/stderr when debug is true if debug { if !result.stdout.is_empty() { println!("Command stdout: {}", result.stdout); } if !result.stderr.is_empty() { println!("Command stderr: {}", result.stderr); } if result.success { println!("Command succeeded with code {}", result.code); } else { println!("Command failed with code {}", result.code); } } if result.success { Ok(result) } else { // If command failed and debug is false, output stderr if !debug { println!("Command failed with code {}: {}", result.code, result.stderr.trim()); } Err(BuildahError::CommandFailed(format!("Command failed with code {}: {}", result.code, result.stderr.trim()))) } }, Err(e) => { // Always output error information println!("Command execution failed: {}", e); Err(BuildahError::CommandExecutionFailed(e)) } } } ``` ### 5. Handle Static Methods For static methods, we'll just call `execute_buildah_command` directly, which will use the thread-local debug flag: ```rust pub fn images() -> Result, BuildahError> { let result = execute_buildah_command(&["images", "--json"])?; // Rest of the method... } ``` If we want to support debugging in static methods, we could add an optional debug parameter: ```rust pub fn images(debug: bool) -> Result, BuildahError> { // Save the current debug flag let previous_debug = thread_local_debug(); // Set the thread-local debug flag set_thread_local_debug(debug); // Execute the command let result = execute_buildah_command(&["images", "--json"]); // Restore the previous debug flag set_thread_local_debug(previous_debug); // Process the result match result { Ok(cmd_result) => { // Parse JSON and return images... }, Err(e) => Err(e), } } // Backward compatibility method pub fn images() -> Result, BuildahError> { Self::images(false) } ``` ### 6. Update Rhai Bindings We still need to update the Rhai bindings to expose the debug functionality: ```rust // Add a debug getter and setter engine.register_get("debug", |builder: &mut Builder| builder.debug()); engine.register_set("debug", |builder: &mut Builder, debug: bool| { builder.set_debug(debug); }); ``` ### 7. Remove Unused Code We can remove the unused `execute_buildah_command_with_debug` function. ## Implementation Flow 1. Modify the `execute_buildah_command` function to output stdout/stderr when debug is true 2. Update all Builder methods to set/restore the thread-local debug flag 3. Update static methods to optionally accept a debug parameter 4. Update Rhai bindings to expose the debug functionality 5. Remove unused code ## Benefits 1. Minimal changes to the existing codebase 2. No changes to function signatures 3. Backward compatibility with existing code 4. Improved debugging capabilities