55
66use anyhow:: { Context , Result } ;
77use camino:: Utf8Path ;
8+ use fn_error_context:: context;
89use serde:: { Deserialize , Serialize } ;
9- use std:: fs ;
10+ use std:: { fs , io :: Write } ;
1011use xshell:: { cmd, Shell } ;
1112
1213/// Represents a CLI option extracted from the JSON dump
@@ -50,10 +51,22 @@ pub struct CliPositional {
5051}
5152
5253/// Extract CLI structure by running the JSON dump command
54+ #[ context( "Extracting CLI" ) ]
5355pub fn extract_cli_json ( sh : & Shell ) -> Result < CliCommand > {
54- let json_output = cmd ! ( sh, "cargo run --features=docgen -- internals dump-cli-json" )
55- . read ( )
56- . context ( "Running CLI JSON dump command" ) ?;
56+ // If we have a release binary, assume that we should compile
57+ // in release mode as hopefully we'll have incremental compilation
58+ // enabled.
59+ let releasebin = Utf8Path :: new ( "target/release/bootc" ) ;
60+ let release = releasebin
61+ . try_exists ( )
62+ . context ( "Querying release bin" ) ?
63+ . then_some ( "--release" ) ;
64+ let json_output = cmd ! (
65+ sh,
66+ "cargo run {release...} --features=docgen -- internals dump-cli-json"
67+ )
68+ . read ( )
69+ . context ( "Running CLI JSON dump command" ) ?;
5770
5871 let cli_structure: CliCommand =
5972 serde_json:: from_str ( & json_output) . context ( "Parsing CLI JSON output" ) ?;
@@ -253,14 +266,15 @@ pub fn update_markdown_with_options(
253266}
254267
255268/// Discover man page files and infer their command paths from filenames
269+ #[ context( "Querying man page mappings" ) ]
256270fn discover_man_page_mappings (
257271 cli_structure : & CliCommand ,
258272) -> Result < Vec < ( String , Option < Vec < String > > ) > > {
259273 let man_dir = Utf8Path :: new ( "docs/src/man" ) ;
260274 let mut mappings = Vec :: new ( ) ;
261275
262276 // Read all .md files in the man directory
263- for entry in fs:: read_dir ( man_dir) ? {
277+ for entry in fs:: read_dir ( man_dir) . context ( "Reading docs/src/man" ) ? {
264278 let entry = entry?;
265279 let path = entry. path ( ) ;
266280
@@ -278,7 +292,7 @@ fn discover_man_page_mappings(
278292 . ok_or_else ( || anyhow:: anyhow!( "Invalid filename" ) ) ?;
279293
280294 // Check if the file contains generation markers
281- let content = fs:: read_to_string ( & path) ?;
295+ let content = fs:: read_to_string ( & path) . with_context ( || format ! ( "Reading {path:?}" ) ) ?;
282296 if !content. contains ( "<!-- BEGIN GENERATED OPTIONS -->" )
283297 && !content. contains ( "<!-- BEGIN GENERATED SUBCOMMANDS -->" )
284298 {
@@ -331,6 +345,7 @@ fn find_command_path_for_filename(
331345}
332346
333347/// Sync all man pages with their corresponding CLI commands
348+ #[ context( "Syncing man pages" ) ]
334349pub fn sync_all_man_pages ( sh : & Shell ) -> Result < ( ) > {
335350 let cli_structure = extract_cli_json ( sh) ?;
336351
@@ -382,12 +397,14 @@ pub fn sync_all_man_pages(sh: &Shell) -> Result<()> {
382397}
383398
384399/// Generate man pages from hand-written markdown sources
400+ #[ context( "Generating manpages" ) ]
385401pub fn generate_man_pages ( sh : & Shell ) -> Result < ( ) > {
386402 let man_src_dir = Utf8Path :: new ( "docs/src/man" ) ;
387403 let man_output_dir = Utf8Path :: new ( "target/man" ) ;
388404
389405 // Ensure output directory exists
390- sh. create_dir ( man_output_dir) ?;
406+ sh. create_dir ( man_output_dir)
407+ . with_context ( || format ! ( "Creating {man_output_dir}" ) ) ?;
391408
392409 // First, sync the markdown files with current CLI options
393410 sync_all_man_pages ( sh) ?;
@@ -396,7 +413,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
396413 let version = get_package_version ( ) ?;
397414
398415 // Convert each markdown file to man page format
399- for entry in fs:: read_dir ( man_src_dir) ? {
416+ for entry in fs:: read_dir ( man_src_dir) . context ( "Reading manpages" ) ? {
400417 let entry = entry?;
401418 let path = entry. path ( ) ;
402419
@@ -421,7 +438,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
421438 let output_file = man_output_dir. join ( format ! ( "{}.{}" , base_name, section) ) ;
422439
423440 // Read markdown content and replace version placeholders
424- let content = fs:: read_to_string ( & path) ?;
441+ let content = fs:: read_to_string ( & path) . with_context ( || format ! ( "Reading {path:?}" ) ) ?;
425442 let content_with_version = content. replace ( "<!-- VERSION PLACEHOLDER -->" , & version) ;
426443
427444 // Check if we need to regenerate by comparing input and output modification times
@@ -437,16 +454,14 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
437454
438455 if should_regenerate {
439456 // Create temporary file with version-replaced content
440- let temp_path = format ! ( "{}.tmp" , path. display( ) ) ;
441- fs:: write ( & temp_path, content_with_version) ?;
457+ let mut tmpf = tempfile:: NamedTempFile :: new_in ( path. parent ( ) . unwrap ( ) ) ?;
458+ tmpf. write_all ( content_with_version. as_bytes ( ) ) ?;
459+ let tmpf = tmpf. path ( ) ;
442460
443- cmd ! ( sh, "go-md2man -in {temp_path } -out {output_file}" )
461+ cmd ! ( sh, "go-md2man -in {tmpf } -out {output_file}" )
444462 . run ( )
445463 . with_context ( || format ! ( "Converting {} to man page" , path. display( ) ) ) ?;
446464
447- // Clean up temporary file
448- fs:: remove_file ( & temp_path) ?;
449-
450465 println ! ( "Generated {}" , output_file) ;
451466 }
452467 }
@@ -458,6 +473,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
458473}
459474
460475/// Get version from Cargo.toml
476+ #[ context( "Querying package version" ) ]
461477fn get_package_version ( ) -> Result < String > {
462478 let cargo_toml =
463479 fs:: read_to_string ( "crates/lib/Cargo.toml" ) . context ( "Reading crates/lib/Cargo.toml" ) ?;
@@ -596,6 +612,7 @@ TODO: Add practical examples showing how to use this command.
596612}
597613
598614/// Apply post-processing fixes to generated man pages
615+ #[ context( "Fixing man pages" ) ]
599616fn apply_man_page_fixes ( sh : & Shell , dir : & Utf8Path ) -> Result < ( ) > {
600617 // Fix apostrophe rendering issue
601618 for entry in fs:: read_dir ( dir) ? {
@@ -608,7 +625,7 @@ fn apply_man_page_fixes(sh: &Shell, dir: &Utf8Path) -> Result<()> {
608625 . map_or ( false , |e| e. chars ( ) . all ( |c| c. is_numeric ( ) ) )
609626 {
610627 // Check if the file already has the fix applied
611- let content = fs:: read_to_string ( & path) ?;
628+ let content = fs:: read_to_string ( & path) . with_context ( || format ! ( "Reading {path:?}" ) ) ?;
612629 if content. starts_with ( ".ds Aq \\ (aq\n " ) {
613630 // Already fixed, skip
614631 continue ;
0 commit comments