forge_tree/generator/file_generator.rs
1//! File and directory creation utilities
2//!
3//! This module handles the actual filesystem operations for creating
4//! directories and files, with support for force overwrite mode.
5
6use crate::{Result, ForgeTreeError};
7use std::fs;
8use std::path::Path;
9
10/// Handles creation of files and directories on the filesystem
11///
12/// FileGenerator provides safe file operations with configurable
13/// overwrite behavior and proper error handling.
14pub struct FileGenerator {
15 /// Whether to overwrite existing files without error
16 force_overwrite: bool,
17}
18
19impl FileGenerator {
20 /// Create a new FileGenerator with default settings (no force overwrite)
21 pub fn new() -> Self {
22 Self {
23 force_overwrite: false,
24 }
25 }
26
27 /// Configure whether existing files should be overwritten
28 ///
29 /// When force_overwrite is true, existing files will be replaced.
30 /// When false, attempting to create existing files will return an error.
31 pub fn with_force_overwrite(mut self, force: bool) -> Self {
32 self.force_overwrite = force;
33 self
34 }
35
36 /// Create a directory and all necessary parent directories
37 ///
38 /// This method:
39 /// - Creates the directory and any missing parent directories
40 /// - Handles the case where the path already exists as a directory
41 /// - Returns an error if the path exists but is not a directory
42 pub fn create_directory<P: AsRef<Path>>(&self, path: P) -> Result<()> {
43 let path = path.as_ref();
44
45 // Check if path exists and is not a directory (e.g., it's a file)
46 if path.exists() && !path.is_dir() {
47 return Err(ForgeTreeError::InvalidPath(
48 format!("Path exists but is not a directory: {}", path.display())
49 ));
50 }
51
52 // create_dir_all is idempotent - it won't error if directory already exists
53 fs::create_dir_all(path)?;
54 Ok(())
55 }
56
57 /// Create a file with the specified content
58 ///
59 /// This method:
60 /// - Checks for existing files and respects the force_overwrite setting
61 /// - Creates parent directories if they don't exist
62 /// - Writes the content to the file (overwrites if file exists and force is true)
63 pub fn create_file<P: AsRef<Path>>(&self, path: P, content: &str) -> Result<()> {
64 let path = path.as_ref();
65
66 // Check if file already exists and we're not in force mode
67 if path.exists() && !self.force_overwrite {
68 return Err(ForgeTreeError::FileExists(path.display().to_string()));
69 }
70
71 // Ensure the parent directory exists before creating the file
72 if let Some(parent) = path.parent() {
73 self.create_directory(parent)?;
74 }
75
76 // fs::write automatically creates or overwrites the file
77 fs::write(path, content)?;
78 Ok(())
79 }
80}
81
82impl Default for FileGenerator {
83 fn default() -> Self {
84 Self::new()
85 }
86}