@@ -3,6 +3,7 @@ use crate::{
33 document:: DocumentContent , helpers:: merge_toml_table,
44} ;
55use alloy_primitives:: map:: HashMap ;
6+ use eyre:: { Context , Result } ;
67use forge_fmt:: { FormatterConfig , Visitable } ;
78use foundry_compilers:: { compilers:: solc:: SOLC_EXTENSIONS , utils:: source_files_iter} ;
89use foundry_config:: { DocConfig , filter:: expand_globs} ;
@@ -22,24 +23,23 @@ use toml::value;
2223#[ derive( Debug ) ]
2324pub struct DocBuilder {
2425 /// The project root
25- pub root : PathBuf ,
26+ root : PathBuf ,
2627 /// Path to Solidity source files.
27- pub sources : PathBuf ,
28+ sources : PathBuf ,
2829 /// Paths to external libraries.
29- pub libraries : Vec < PathBuf > ,
30+ libraries : Vec < PathBuf > ,
3031 /// Flag whether to build mdbook.
31- pub should_build : bool ,
32+ should_build : bool ,
3233 /// Documentation configuration.
33- pub config : DocConfig ,
34+ config : DocConfig ,
3435 /// The array of preprocessors to apply.
35- pub preprocessors : Vec < Box < dyn Preprocessor > > ,
36+ preprocessors : Vec < Box < dyn Preprocessor > > ,
3637 /// The formatter config.
37- pub fmt : FormatterConfig ,
38+ fmt : FormatterConfig ,
3839 /// Whether to include libraries to the output.
39- pub include_libraries : bool ,
40+ include_libraries : bool ,
4041}
4142
42- // TODO: consider using `tfio`
4343impl DocBuilder {
4444 pub ( crate ) const SRC : & ' static str = "src" ;
4545 const SOL_EXT : & ' static str = "sol" ;
@@ -90,12 +90,15 @@ impl DocBuilder {
9090 }
9191
9292 /// Get the output directory
93- pub fn out_dir ( & self ) -> PathBuf {
94- self . root . join ( & self . config . out )
93+ pub fn out_dir ( & self ) -> Result < PathBuf > {
94+ Ok ( self . root . join ( & self . config . out ) . canonicalize ( ) ? )
9595 }
9696
9797 /// Parse the sources and build the documentation.
9898 pub fn build ( self ) -> eyre:: Result < ( ) > {
99+ fs:: create_dir_all ( self . root . join ( & self . config . out ) )
100+ . wrap_err ( "failed to create output directory" ) ?;
101+
99102 // Expand ignore globs
100103 let ignored = expand_globs ( & self . root , self . config . ignore . iter ( ) ) ?;
101104
@@ -121,6 +124,7 @@ impl DocBuilder {
121124 . chain ( library_sources. iter ( ) . map ( |path| ( path, true ) ) )
122125 . collect :: < Vec < _ > > ( ) ;
123126
127+ let out_dir = self . out_dir ( ) ?;
124128 let documents = combined_sources
125129 . par_iter ( )
126130 . enumerate ( )
@@ -181,7 +185,8 @@ impl DocBuilder {
181185 . into_iter ( )
182186 . map ( |item| {
183187 let relative_path = path. strip_prefix ( & self . root ) ?. join ( item. filename ( ) ) ;
184- let target_path = self . config . out . join ( Self :: SRC ) . join ( relative_path) ;
188+
189+ let target_path = out_dir. join ( Self :: SRC ) . join ( relative_path) ;
185190 let ident = item. source . ident ( ) ;
186191 Ok ( Document :: new (
187192 path. clone ( ) ,
@@ -206,7 +211,7 @@ impl DocBuilder {
206211 name
207212 } ;
208213 let relative_path = path. strip_prefix ( & self . root ) ?. join ( filename) ;
209- let target_path = self . config . out . join ( Self :: SRC ) . join ( relative_path) ;
214+ let target_path = out_dir . join ( Self :: SRC ) . join ( relative_path) ;
210215
211216 let identity = match filestem {
212217 Some ( stem) if stem. to_lowercase ( ) . contains ( "constants" ) => stem. to_owned ( ) ,
@@ -230,7 +235,8 @@ impl DocBuilder {
230235 for ( ident, funcs) in overloaded {
231236 let filename = funcs. first ( ) . expect ( "no overloaded functions" ) . filename ( ) ;
232237 let relative_path = path. strip_prefix ( & self . root ) ?. join ( filename) ;
233- let target_path = self . config . out . join ( Self :: SRC ) . join ( relative_path) ;
238+
239+ let target_path = out_dir. join ( Self :: SRC ) . join ( relative_path) ;
234240 files. push (
235241 Document :: new (
236242 path. clone ( ) ,
@@ -267,7 +273,7 @@ impl DocBuilder {
267273
268274 // Build the book if requested
269275 if self . should_build {
270- MDBook :: load ( self . out_dir ( ) )
276+ MDBook :: load ( self . out_dir ( ) . wrap_err ( "failed to construct output directory" ) ? )
271277 . and_then ( |book| book. build ( ) )
272278 . map_err ( |err| eyre:: eyre!( "failed to build book: {err:?}" ) ) ?;
273279 }
@@ -276,7 +282,7 @@ impl DocBuilder {
276282 }
277283
278284 fn write_mdbook ( & self , documents : Vec < Document > ) -> eyre:: Result < ( ) > {
279- let out_dir = self . out_dir ( ) ;
285+ let out_dir = self . out_dir ( ) . wrap_err ( "failed to construct output directory" ) ? ;
280286 let out_dir_src = out_dir. join ( Self :: SRC ) ;
281287 fs:: create_dir_all ( & out_dir_src) ?;
282288
@@ -321,11 +327,11 @@ impl DocBuilder {
321327 fs:: write ( out_dir. join ( "book.css" ) , include_str ! ( "../static/book.css" ) ) ?;
322328
323329 // Write book config
324- fs:: write ( self . out_dir ( ) . join ( "book.toml" ) , self . book_config ( ) ?) ?;
330+ fs:: write ( out_dir. join ( "book.toml" ) , self . book_config ( ) ?) ?;
325331
326332 // Write .gitignore
327333 let gitignore = "book/" ;
328- fs:: write ( self . out_dir ( ) . join ( ".gitignore" ) , gitignore) ?;
334+ fs:: write ( out_dir. join ( ".gitignore" ) , gitignore) ?;
329335
330336 // Write doc files
331337 for document in documents {
@@ -427,15 +433,14 @@ impl DocBuilder {
427433 }
428434 } ) ;
429435
436+ let out_dir = self . out_dir ( ) . wrap_err ( "failed to construct output directory" ) ?;
430437 let mut readme = BufWriter :: new ( "\n \n # Contents\n " ) ;
431438 for ( path, files) in grouped {
432439 if path. extension ( ) . map ( |ext| ext == Self :: SOL_EXT ) . unwrap_or_default ( ) {
433440 for file in files {
434441 let ident = & file. identity ;
435442
436- let summary_path = file
437- . target_path
438- . strip_prefix ( self . out_dir ( ) . strip_prefix ( & self . root ) ?. join ( Self :: SRC ) ) ?;
443+ let summary_path = & file. target_path . strip_prefix ( out_dir. join ( Self :: SRC ) ) ?;
439444 summary. write_link_list_item (
440445 ident,
441446 & summary_path. display ( ) . to_string ( ) ,
@@ -458,7 +463,7 @@ impl DocBuilder {
458463 if !readme. is_empty ( )
459464 && let Some ( path) = base_path
460465 {
461- let path = self . out_dir ( ) . join ( Self :: SRC ) . join ( path) ;
466+ let path = out_dir. join ( Self :: SRC ) . join ( path) ;
462467 fs:: create_dir_all ( & path) ?;
463468 fs:: write ( path. join ( Self :: README ) , readme. finish ( ) ) ?;
464469 }
0 commit comments