11use anyhow:: { Context , Error , Result } ;
22use std:: {
3- fs:: { create_dir , OpenOptions } ,
4- io:: { self , Write } ,
3+ fs:: { self , create_dir } ,
4+ io,
55} ;
66
77use crate :: info_file:: ExerciseInfo ;
88
99/// Contains all embedded files.
1010pub static EMBEDDED_FILES : EmbeddedFiles = rustlings_macros:: include_files!( ) ;
1111
12- #[ derive( Clone , Copy ) ]
13- pub enum WriteStrategy {
14- IfNotExists ,
15- Overwrite ,
16- }
17-
18- impl WriteStrategy {
19- fn write ( self , path : & str , content : & [ u8 ] ) -> Result < ( ) > {
20- let file = match self {
21- Self :: IfNotExists => OpenOptions :: new ( ) . create_new ( true ) . write ( true ) . open ( path) ,
22- Self :: Overwrite => OpenOptions :: new ( )
23- . create ( true )
24- . write ( true )
25- . truncate ( true )
26- . open ( path) ,
27- } ;
28-
29- file. with_context ( || format ! ( "Failed to open the file `{path}` in write mode" ) ) ?
30- . write_all ( content)
31- . with_context ( || format ! ( "Failed to write the file {path}" ) )
32- }
33- }
34-
3512// Files related to one exercise.
3613struct ExerciseFiles {
3714 // The content of the exercise file.
@@ -42,6 +19,16 @@ struct ExerciseFiles {
4219 dir_ind : usize ,
4320}
4421
22+ fn create_dir_if_not_exists ( path : & str ) -> Result < ( ) > {
23+ if let Err ( e) = create_dir ( path) {
24+ if e. kind ( ) != io:: ErrorKind :: AlreadyExists {
25+ return Err ( Error :: from ( e) . context ( format ! ( "Failed to create the directory {path}" ) ) ) ;
26+ }
27+ }
28+
29+ Ok ( ( ) )
30+ }
31+
4532// A directory in the `exercises/` directory.
4633pub struct ExerciseDir {
4734 pub name : & ' static str ,
@@ -55,21 +42,13 @@ impl ExerciseDir {
5542 let mut dir_path = String :: with_capacity ( 20 + self . name . len ( ) ) ;
5643 dir_path. push_str ( "exercises/" ) ;
5744 dir_path. push_str ( self . name ) ;
58-
59- if let Err ( e) = create_dir ( & dir_path) {
60- if e. kind ( ) == io:: ErrorKind :: AlreadyExists {
61- return Ok ( ( ) ) ;
62- }
63-
64- return Err (
65- Error :: from ( e) . context ( format ! ( "Failed to create the directory {dir_path}" ) )
66- ) ;
67- }
45+ create_dir_if_not_exists ( & dir_path) ?;
6846
6947 let mut readme_path = dir_path;
7048 readme_path. push_str ( "/README.md" ) ;
7149
72- WriteStrategy :: Overwrite . write ( & readme_path, self . readme )
50+ fs:: write ( & readme_path, self . readme )
51+ . with_context ( || format ! ( "Failed to write the file {readme_path}" ) )
7352 }
7453}
7554
@@ -86,17 +65,31 @@ impl EmbeddedFiles {
8665 pub fn init_exercises_dir ( & self , exercise_infos : & [ ExerciseInfo ] ) -> Result < ( ) > {
8766 create_dir ( "exercises" ) . context ( "Failed to create the directory `exercises`" ) ?;
8867
89- WriteStrategy :: IfNotExists . write (
68+ fs :: write (
9069 "exercises/README.md" ,
9170 include_bytes ! ( "../exercises/README.md" ) ,
92- ) ?;
71+ )
72+ . context ( "Failed to write the file exercises/README.md" ) ?;
9373
9474 for dir in self . exercise_dirs {
9575 dir. init_on_disk ( ) ?;
9676 }
9777
78+ let mut exercise_path = String :: with_capacity ( 64 ) ;
79+ let prefix = "exercises/" ;
80+ exercise_path. push_str ( prefix) ;
81+
9882 for ( exercise_info, exercise_files) in exercise_infos. iter ( ) . zip ( self . exercise_files ) {
99- WriteStrategy :: IfNotExists . write ( & exercise_info. path ( ) , exercise_files. exercise ) ?;
83+ let dir = & self . exercise_dirs [ exercise_files. dir_ind ] ;
84+
85+ exercise_path. truncate ( prefix. len ( ) ) ;
86+ exercise_path. push_str ( dir. name ) ;
87+ exercise_path. push ( '/' ) ;
88+ exercise_path. push_str ( & exercise_info. name ) ;
89+ exercise_path. push_str ( ".rs" ) ;
90+
91+ fs:: write ( & exercise_path, exercise_files. exercise )
92+ . with_context ( || format ! ( "Failed to write the exercise file {exercise_path}" ) ) ?;
10093 }
10194
10295 Ok ( ( ) )
@@ -107,7 +100,8 @@ impl EmbeddedFiles {
107100 let dir = & self . exercise_dirs [ exercise_files. dir_ind ] ;
108101
109102 dir. init_on_disk ( ) ?;
110- WriteStrategy :: Overwrite . write ( path, exercise_files. exercise )
103+ fs:: write ( path, exercise_files. exercise )
104+ . with_context ( || format ! ( "Failed to write the exercise file {path}" ) )
111105 }
112106
113107 /// Write the solution file to disk and return its path.
@@ -116,19 +110,25 @@ impl EmbeddedFiles {
116110 exercise_ind : usize ,
117111 exercise_name : & str ,
118112 ) -> Result < String > {
113+ create_dir_if_not_exists ( "solutions" ) ?;
114+
119115 let exercise_files = & self . exercise_files [ exercise_ind] ;
120116 let dir = & self . exercise_dirs [ exercise_files. dir_ind ] ;
121117
122118 // 14 = 10 + 1 + 3
123119 // solutions/ + / + .rs
124- let mut solution_path = String :: with_capacity ( 14 + dir. name . len ( ) + exercise_name. len ( ) ) ;
125- solution_path. push_str ( "solutions/" ) ;
126- solution_path. push_str ( dir. name ) ;
120+ let mut dir_path = String :: with_capacity ( 14 + dir. name . len ( ) + exercise_name. len ( ) ) ;
121+ dir_path. push_str ( "solutions/" ) ;
122+ dir_path. push_str ( dir. name ) ;
123+ create_dir_if_not_exists ( & dir_path) ?;
124+
125+ let mut solution_path = dir_path;
127126 solution_path. push ( '/' ) ;
128127 solution_path. push_str ( exercise_name) ;
129128 solution_path. push_str ( ".rs" ) ;
130129
131- WriteStrategy :: Overwrite . write ( & solution_path, exercise_files. solution ) ?;
130+ fs:: write ( & solution_path, exercise_files. solution )
131+ . with_context ( || format ! ( "Failed to write the solution file {solution_path}" ) ) ?;
132132
133133 Ok ( solution_path)
134134 }
0 commit comments