From 39f5322c22ea7261514bfa7261cdbd64eecaf17a Mon Sep 17 00:00:00 2001 From: Justin Schneck Date: Wed, 28 Jan 2026 14:19:07 -0500 Subject: [PATCH 1/2] add support for copying folders on create --- src/commands/stone/create.rs | 87 +++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/src/commands/stone/create.rs b/src/commands/stone/create.rs index 674740d..d2f8278 100644 --- a/src/commands/stone/create.rs +++ b/src/commands/stone/create.rs @@ -260,18 +260,19 @@ fn process_image( } } - // Only copy the image file if it's a String type (input file) + // Only copy the image file/directory if it's a String type (input file/dir) // Object types represent generated output files that don't exist yet match image { crate::manifest::Image::String(filename) => { - // This is an input file that should be copied + // This is an input file or directory that should be copied match find_file_in_dirs(filename, input_dirs) { Some(input_path) => { let output_path = output_dir.join(filename); - copy_file(&input_path, &output_path, verbose) + // Use copy_path to handle both files and directories + copy_path(&input_path, &output_path, verbose) } None => Err(format!( - "Image file '{filename}' for image '{image_name}' not found in any input directory" + "Image file/directory '{filename}' for image '{image_name}' not found in any input directory" )), } } @@ -299,14 +300,88 @@ fn process_file_entry( match find_file_in_dirs(input_filename, input_dirs) { Some(input_path) => { let output_path = output_dir.join(input_filename); - copy_file(&input_path, &output_path, verbose) + // Use copy_path to handle both files and directories + copy_path(&input_path, &output_path, verbose) } None => Err(format!( - "File '{input_filename}' not found in any input directory" + "File/directory '{input_filename}' not found in any input directory" )), } } +/// Copy a file or directory recursively from input to output path +fn copy_path(input_path: &Path, output_path: &Path, verbose: bool) -> Result<(), String> { + // Check if input exists + if !input_path.exists() { + return Err(format!("Input path '{}' not found.", input_path.display())); + } + + if input_path.is_dir() { + // Recursively copy directory contents + copy_directory(input_path, output_path, verbose) + } else { + // Copy single file + copy_file(input_path, output_path, verbose) + } +} + +/// Recursively copy a directory and all its contents +fn copy_directory(input_dir: &Path, output_dir: &Path, verbose: bool) -> Result<(), String> { + // Create output directory + if let Err(e) = fs::create_dir_all(output_dir) { + return Err(format!( + "Failed to create output directory '{}': {}", + output_dir.display(), + e + )); + } + + if verbose { + log_debug(&format!( + "Copying directory:\n {}\n {}", + input_dir.display(), + output_dir.display() + )); + } + + // Read directory entries + let entries = fs::read_dir(input_dir) + .map_err(|e| format!("Failed to read directory '{}': {}", input_dir.display(), e))?; + + let mut file_count = 0; + for entry in entries { + let entry = entry.map_err(|e| { + format!( + "Failed to read directory entry in '{}': {}", + input_dir.display(), + e + ) + })?; + + let input_child = entry.path(); + let output_child = output_dir.join(entry.file_name()); + + if input_child.is_dir() { + // Recursively copy subdirectory + copy_directory(&input_child, &output_child, verbose)?; + } else { + // Copy file + copy_file(&input_child, &output_child, verbose)?; + file_count += 1; + } + } + + if verbose { + log_debug(&format!( + "Copied {} files from directory '{}'", + file_count, + input_dir.display() + )); + } + + Ok(()) +} + fn copy_file(input_path: &Path, output_path: &Path, verbose: bool) -> Result<(), String> { // Check if input file exists if !input_path.exists() { From 0fe8229d30440e4705d31c14e59aba865f7738ce Mon Sep 17 00:00:00 2001 From: Justin Schneck Date: Wed, 28 Jan 2026 14:19:16 -0500 Subject: [PATCH 2/2] 1.9.0 release --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4231a02..750f680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -532,7 +532,7 @@ checksum = "9d26fcce2f397e5488affdf681b20c030aa9faa877b92b1825e5d66b08d2fc33" [[package]] name = "stone" -version = "1.8.2" +version = "1.9.0" dependencies = [ "assert_cmd", "clap", diff --git a/Cargo.toml b/Cargo.toml index 56c6e3f..a45e5d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stone" -version = "1.8.2" +version = "1.9.0" edition = "2024" description = "A CLI for managing Avocado stones." homepage = "https://github.com/avocado-linux/stone"