33use crate :: core_types:: { Action , CreateStatus } ;
44use crate :: errors:: ProcessError ;
55use std:: fs;
6+ use std:: io; // Import io for ErrorKind
67use std:: path:: Path ;
78
89/// Creates or overwrites a file with the provided content.
@@ -19,6 +20,7 @@ pub(crate) fn process_create(
1920 . ok_or_else ( || ProcessError :: Internal ( "Missing content for create action" . to_string ( ) ) ) ?;
2021
2122 // Ensure parent directory exists and is a directory
23+ // This might return ParentIsNotDirectory if parent exists as file or if creation fails
2224 ensure_parent_directory ( resolved_full_path, resolved_base) ?;
2325
2426 let mut status = CreateStatus :: Created ; // Default optimistic status
@@ -54,7 +56,23 @@ pub(crate) fn process_create(
5456
5557 // Write the file content (as bytes to preserve line endings)
5658 fs:: write ( resolved_full_path, content. as_bytes ( ) )
57- . map_err ( |e| ProcessError :: Io { source : e } ) ?;
59+ . map_err ( |e| {
60+ // Check if the write failed because the parent path component is a file
61+ if e. kind ( ) == io:: ErrorKind :: NotADirectory {
62+ // Map this specific IO error to our more descriptive error
63+ let parent_path = resolved_full_path. parent ( ) . unwrap_or ( resolved_full_path) . to_path_buf ( ) ;
64+ // *** DEBUG LOG ***
65+ eprintln ! ( "[DEBUG] fs::write failed with NotADirectory, mapping to ParentIsNotDirectory for path: {}" , resolved_full_path. display( ) ) ;
66+ ProcessError :: ParentIsNotDirectory {
67+ path : resolved_full_path. to_path_buf ( ) ,
68+ parent_path, // Report the parent path
69+ }
70+ } else {
71+ // *** DEBUG LOG ***
72+ eprintln ! ( "[DEBUG] fs::write failed with other IO error: {:?}, mapping to Io for path: {}" , e. kind( ) , resolved_full_path. display( ) ) ;
73+ ProcessError :: Io { source : e }
74+ }
75+ } ) ?;
5876
5977 Ok ( status)
6078}
@@ -63,21 +81,59 @@ pub(crate) fn process_create(
6381/// Also checks if the parent path itself is unexpectedly a file.
6482fn ensure_parent_directory ( target_path : & Path , resolved_base : & Path ) -> Result < ( ) , ProcessError > {
6583 if let Some ( parent_dir) = target_path. parent ( ) {
66- if parent_dir == resolved_base || parent_dir. exists ( ) {
67- // If parent exists, ensure it's a directory
68- if !parent_dir. is_dir ( ) {
69- return Err ( ProcessError :: ParentIsNotDirectory {
70- path : target_path. to_path_buf ( ) ,
71- parent_path : parent_dir. to_path_buf ( ) ,
72- } ) ;
84+ // Avoid checking the base directory itself if it's the parent
85+ if parent_dir == resolved_base || parent_dir. as_os_str ( ) . is_empty ( ) {
86+ return Ok ( ( ) ) ; // Base directory is guaranteed to exist and be a dir, or path is in root
87+ }
88+
89+ match fs:: metadata ( parent_dir) {
90+ Ok ( metadata) => {
91+ // Parent exists, check if it's a directory
92+ if !metadata. is_dir ( ) {
93+ // *** DEBUG LOG ***
94+ eprintln ! ( "[DEBUG] Parent metadata exists but is not dir, returning ParentIsNotDirectory for parent: {}" , parent_dir. display( ) ) ;
95+ return Err ( ProcessError :: ParentIsNotDirectory {
96+ path : target_path. to_path_buf ( ) ,
97+ parent_path : parent_dir. to_path_buf ( ) ,
98+ } ) ;
99+ }
100+ // Parent exists and is a directory, all good.
101+ }
102+ Err ( ref e) if e. kind ( ) == io:: ErrorKind :: NotFound => {
103+ // Parent does not exist, try to create it
104+ let relative_parent_dir =
105+ parent_dir. strip_prefix ( resolved_base) . unwrap_or ( parent_dir) ;
106+ println ! ( " Creating directory: {}" , relative_parent_dir. display( ) ) ;
107+
108+ if let Err ( create_err) = fs:: create_dir_all ( parent_dir) {
109+ // Check if the error is specifically "Not a directory"
110+ // This often indicates an intermediate path component was a file during creation attempt.
111+ if create_err. kind ( ) == io:: ErrorKind :: NotADirectory {
112+ // *** DEBUG LOG ***
113+ eprintln ! ( "[DEBUG] create_dir_all failed with NotADirectory, returning ParentIsNotDirectory for parent: {}" , parent_dir. display( ) ) ;
114+ // Map this specific IO error to our more descriptive error
115+ return Err ( ProcessError :: ParentIsNotDirectory {
116+ path : target_path. to_path_buf ( ) ,
117+ // Report the parent directory we *failed* to create
118+ parent_path : parent_dir. to_path_buf ( ) ,
119+ } ) ;
120+ } else {
121+ // *** DEBUG LOG ***
122+ eprintln ! ( "[DEBUG] create_dir_all failed with other IO error: {:?}, returning Io for parent: {}" , create_err. kind( ) , parent_dir. display( ) ) ;
123+ // Other I/O error during creation
124+ return Err ( ProcessError :: Io { source : create_err } ) ;
125+ }
126+ }
127+ // Creation successful
128+ }
129+ Err ( e) => {
130+ // *** DEBUG LOG ***
131+ eprintln ! ( "[DEBUG] fs::metadata failed with other IO error: {:?}, returning Io for parent: {}" , e. kind( ) , parent_dir. display( ) ) ;
132+ // Other error getting metadata (permissions?)
133+ return Err ( ProcessError :: Io { source : e } ) ;
73134 }
74- } else {
75- // Parent does not exist, create it
76- let relative_parent_dir = parent_dir. strip_prefix ( resolved_base) . unwrap_or ( parent_dir) ;
77- println ! ( " Creating directory: {}" , relative_parent_dir. display( ) ) ;
78- fs:: create_dir_all ( parent_dir) . map_err ( |e| ProcessError :: Io { source : e } ) ?;
79135 }
80136 }
81- // If no parent (e.g., root directory ), assume it's okay.
137+ // If no parent (e.g., file directly in base ), assume it's okay.
82138 Ok ( ( ) )
83139}
0 commit comments