11//! Filesystem utilities and helpers.
22
33use anyhow:: { Context , Result } ;
4- use std:: fs:: { self , File } ;
5- use std:: io:: Write ;
4+ use std:: fs;
65use std:: path:: { Component , Path , PathBuf } ;
7- use tracing:: { debug, trace } ;
6+ use tracing:: debug;
87
9- /// Write the given data to a file, creating it first if necessary
10- pub fn write_file < P : AsRef < Path > > ( build_dir : & Path , filename : P , content : & [ u8 ] ) -> Result < ( ) > {
11- let path = build_dir. join ( filename) ;
8+ /// Reads a file into a string.
9+ ///
10+ /// Equivalent to [`std::fs::read_to_string`] with better error messages.
11+ pub fn read_to_string < P : AsRef < Path > > ( path : P ) -> Result < String > {
12+ let path = path. as_ref ( ) ;
13+ fs:: read_to_string ( path) . with_context ( || format ! ( "failed to read `{}`" , path. display( ) ) )
14+ }
1215
13- create_file ( & path) ?. write_all ( content) . map_err ( Into :: into)
16+ /// Writes a file to disk.
17+ ///
18+ /// Equivalent to [`std::fs::write`] with better error messages. This will
19+ /// also create the parent directory if it doesn't exist.
20+ pub fn write < P : AsRef < Path > , C : AsRef < [ u8 ] > > ( path : P , contents : C ) -> Result < ( ) > {
21+ let path = path. as_ref ( ) ;
22+ debug ! ( "Writing `{}`" , path. display( ) ) ;
23+ if let Some ( parent) = path. parent ( ) {
24+ create_dir_all ( parent) ?;
25+ }
26+ fs:: write ( path, contents. as_ref ( ) )
27+ . with_context ( || format ! ( "failed to write `{}`" , path. display( ) ) )
28+ }
29+
30+ /// Equivalent to [`std::fs::create_dir_all`] with better error messages.
31+ pub fn create_dir_all ( p : impl AsRef < Path > ) -> Result < ( ) > {
32+ let p = p. as_ref ( ) ;
33+ fs:: create_dir_all ( p)
34+ . with_context ( || format ! ( "failed to create directory `{}`" , p. display( ) ) ) ?;
35+ Ok ( ( ) )
1436}
1537
1638/// Takes a path and returns a path containing just enough `../` to point to
@@ -48,30 +70,19 @@ pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String {
4870 } )
4971}
5072
51- /// This function creates a file and returns it. But before creating the file
52- /// it checks every directory in the path to see if it exists,
53- /// and if it does not it will be created.
54- pub fn create_file ( path : & Path ) -> Result < File > {
55- debug ! ( "Creating {}" , path. display( ) ) ;
56-
57- // Construct path
58- if let Some ( p) = path. parent ( ) {
59- trace ! ( "Parent directory is: {:?}" , p) ;
60-
61- fs:: create_dir_all ( p) ?;
62- }
63-
64- File :: create ( path) . map_err ( Into :: into)
65- }
66-
67- /// Removes all the content of a directory but not the directory itself
73+ /// Removes all the content of a directory but not the directory itself.
6874pub fn remove_dir_content ( dir : & Path ) -> Result < ( ) > {
69- for item in fs:: read_dir ( dir) ?. flatten ( ) {
75+ for item in fs:: read_dir ( dir)
76+ . with_context ( || format ! ( "failed to read directory `{}`" , dir. display( ) ) ) ?
77+ . flatten ( )
78+ {
7079 let item = item. path ( ) ;
7180 if item. is_dir ( ) {
72- fs:: remove_dir_all ( item) ?;
81+ fs:: remove_dir_all ( & item)
82+ . with_context ( || format ! ( "failed to remove `{}`" , item. display( ) ) ) ?;
7383 } else {
74- fs:: remove_file ( item) ?;
84+ fs:: remove_file ( & item)
85+ . with_context ( || format ! ( "failed to remove `{}`" , item. display( ) ) ) ?;
7586 }
7687 }
7788 Ok ( ( ) )
@@ -162,7 +173,7 @@ fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
162173 use std:: fs:: OpenOptions ;
163174 use std:: os:: unix:: fs:: { OpenOptionsExt , PermissionsExt } ;
164175
165- let mut reader = File :: open ( from) ?;
176+ let mut reader = std :: fs :: File :: open ( from) ?;
166177 let metadata = reader. metadata ( ) ?;
167178 if !metadata. is_file ( ) {
168179 anyhow:: bail!(
@@ -198,8 +209,9 @@ fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
198209
199210#[ cfg( test) ]
200211mod tests {
201- use super :: copy_files_except_ext;
202- use std:: { fs, io:: Result , path:: Path } ;
212+ use super :: * ;
213+ use std:: io:: Result ;
214+ use std:: path:: Path ;
203215
204216 #[ cfg( target_os = "windows" ) ]
205217 fn symlink < P : AsRef < Path > , Q : AsRef < Path > > ( src : P , dst : Q ) -> Result < ( ) > {
@@ -219,38 +231,18 @@ mod tests {
219231 } ;
220232
221233 // Create a couple of files
222- if let Err ( err) = fs:: File :: create ( tmp. path ( ) . join ( "file.txt" ) ) {
223- panic ! ( "Could not create file.txt: {err}" ) ;
224- }
225- if let Err ( err) = fs:: File :: create ( tmp. path ( ) . join ( "file.md" ) ) {
226- panic ! ( "Could not create file.md: {err}" ) ;
227- }
228- if let Err ( err) = fs:: File :: create ( tmp. path ( ) . join ( "file.png" ) ) {
229- panic ! ( "Could not create file.png: {err}" ) ;
230- }
231- if let Err ( err) = fs:: create_dir ( tmp. path ( ) . join ( "sub_dir" ) ) {
232- panic ! ( "Could not create sub_dir: {err}" ) ;
233- }
234- if let Err ( err) = fs:: File :: create ( tmp. path ( ) . join ( "sub_dir/file.png" ) ) {
235- panic ! ( "Could not create sub_dir/file.png: {err}" ) ;
236- }
237- if let Err ( err) = fs:: create_dir ( tmp. path ( ) . join ( "sub_dir_exists" ) ) {
238- panic ! ( "Could not create sub_dir_exists: {err}" ) ;
239- }
240- if let Err ( err) = fs:: File :: create ( tmp. path ( ) . join ( "sub_dir_exists/file.txt" ) ) {
241- panic ! ( "Could not create sub_dir_exists/file.txt: {err}" ) ;
242- }
234+ write ( tmp. path ( ) . join ( "file.txt" ) , "" ) . unwrap ( ) ;
235+ write ( tmp. path ( ) . join ( "file.md" ) , "" ) . unwrap ( ) ;
236+ write ( tmp. path ( ) . join ( "file.png" ) , "" ) . unwrap ( ) ;
237+ write ( tmp. path ( ) . join ( "sub_dir/file.png" ) , "" ) . unwrap ( ) ;
238+ write ( tmp. path ( ) . join ( "sub_dir_exists/file.txt" ) , "" ) . unwrap ( ) ;
243239 if let Err ( err) = symlink ( tmp. path ( ) . join ( "file.png" ) , tmp. path ( ) . join ( "symlink.png" ) ) {
244240 panic ! ( "Could not symlink file.png: {err}" ) ;
245241 }
246242
247243 // Create output dir
248- if let Err ( err) = fs:: create_dir ( tmp. path ( ) . join ( "output" ) ) {
249- panic ! ( "Could not create output: {err}" ) ;
250- }
251- if let Err ( err) = fs:: create_dir ( tmp. path ( ) . join ( "output/sub_dir_exists" ) ) {
252- panic ! ( "Could not create output/sub_dir_exists: {err}" ) ;
253- }
244+ create_dir_all ( tmp. path ( ) . join ( "output" ) ) . unwrap ( ) ;
245+ create_dir_all ( tmp. path ( ) . join ( "output/sub_dir_exists" ) ) . unwrap ( ) ;
254246
255247 if let Err ( e) =
256248 copy_files_except_ext ( tmp. path ( ) , & tmp. path ( ) . join ( "output" ) , true , None , & [ "md" ] )
0 commit comments