5
5
6
6
use anyhow:: { Context , Result } ;
7
7
use camino:: Utf8Path ;
8
+ use fn_error_context:: context;
8
9
use serde:: { Deserialize , Serialize } ;
9
- use std:: fs ;
10
+ use std:: { fs , io :: Write } ;
10
11
use xshell:: { cmd, Shell } ;
11
12
12
13
/// Represents a CLI option extracted from the JSON dump
@@ -50,10 +51,22 @@ pub struct CliPositional {
50
51
}
51
52
52
53
/// Extract CLI structure by running the JSON dump command
54
+ #[ context( "Extracting CLI" ) ]
53
55
pub 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" ) ?;
57
70
58
71
let cli_structure: CliCommand =
59
72
serde_json:: from_str ( & json_output) . context ( "Parsing CLI JSON output" ) ?;
@@ -253,14 +266,15 @@ pub fn update_markdown_with_options(
253
266
}
254
267
255
268
/// Discover man page files and infer their command paths from filenames
269
+ #[ context( "Querying man page mappings" ) ]
256
270
fn discover_man_page_mappings (
257
271
cli_structure : & CliCommand ,
258
272
) -> Result < Vec < ( String , Option < Vec < String > > ) > > {
259
273
let man_dir = Utf8Path :: new ( "docs/src/man" ) ;
260
274
let mut mappings = Vec :: new ( ) ;
261
275
262
276
// 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" ) ? {
264
278
let entry = entry?;
265
279
let path = entry. path ( ) ;
266
280
@@ -278,7 +292,7 @@ fn discover_man_page_mappings(
278
292
. ok_or_else ( || anyhow:: anyhow!( "Invalid filename" ) ) ?;
279
293
280
294
// 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:?}" ) ) ?;
282
296
if !content. contains ( "<!-- BEGIN GENERATED OPTIONS -->" )
283
297
&& !content. contains ( "<!-- BEGIN GENERATED SUBCOMMANDS -->" )
284
298
{
@@ -331,6 +345,7 @@ fn find_command_path_for_filename(
331
345
}
332
346
333
347
/// Sync all man pages with their corresponding CLI commands
348
+ #[ context( "Syncing man pages" ) ]
334
349
pub fn sync_all_man_pages ( sh : & Shell ) -> Result < ( ) > {
335
350
let cli_structure = extract_cli_json ( sh) ?;
336
351
@@ -382,12 +397,14 @@ pub fn sync_all_man_pages(sh: &Shell) -> Result<()> {
382
397
}
383
398
384
399
/// Generate man pages from hand-written markdown sources
400
+ #[ context( "Generating manpages" ) ]
385
401
pub fn generate_man_pages ( sh : & Shell ) -> Result < ( ) > {
386
402
let man_src_dir = Utf8Path :: new ( "docs/src/man" ) ;
387
403
let man_output_dir = Utf8Path :: new ( "target/man" ) ;
388
404
389
405
// 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}" ) ) ?;
391
408
392
409
// First, sync the markdown files with current CLI options
393
410
sync_all_man_pages ( sh) ?;
@@ -396,7 +413,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
396
413
let version = get_package_version ( ) ?;
397
414
398
415
// 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" ) ? {
400
417
let entry = entry?;
401
418
let path = entry. path ( ) ;
402
419
@@ -421,7 +438,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
421
438
let output_file = man_output_dir. join ( format ! ( "{}.{}" , base_name, section) ) ;
422
439
423
440
// 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:?}" ) ) ?;
425
442
let content_with_version = content. replace ( "<!-- VERSION PLACEHOLDER -->" , & version) ;
426
443
427
444
// 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<()> {
437
454
438
455
if should_regenerate {
439
456
// 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 ( ) ;
442
460
443
- cmd ! ( sh, "go-md2man -in {temp_path } -out {output_file}" )
461
+ cmd ! ( sh, "go-md2man -in {tmpf } -out {output_file}" )
444
462
. run ( )
445
463
. with_context ( || format ! ( "Converting {} to man page" , path. display( ) ) ) ?;
446
464
447
- // Clean up temporary file
448
- fs:: remove_file ( & temp_path) ?;
449
-
450
465
println ! ( "Generated {}" , output_file) ;
451
466
}
452
467
}
@@ -458,6 +473,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> {
458
473
}
459
474
460
475
/// Get version from Cargo.toml
476
+ #[ context( "Querying package version" ) ]
461
477
fn get_package_version ( ) -> Result < String > {
462
478
let cargo_toml =
463
479
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.
596
612
}
597
613
598
614
/// Apply post-processing fixes to generated man pages
615
+ #[ context( "Fixing man pages" ) ]
599
616
fn apply_man_page_fixes ( sh : & Shell , dir : & Utf8Path ) -> Result < ( ) > {
600
617
// Fix apostrophe rendering issue
601
618
for entry in fs:: read_dir ( dir) ? {
@@ -608,7 +625,7 @@ fn apply_man_page_fixes(sh: &Shell, dir: &Utf8Path) -> Result<()> {
608
625
. map_or ( false , |e| e. chars ( ) . all ( |c| c. is_numeric ( ) ) )
609
626
{
610
627
// 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:?}" ) ) ?;
612
629
if content. starts_with ( ".ds Aq \\ (aq\n " ) {
613
630
// Already fixed, skip
614
631
continue ;
0 commit comments