1+ use crate :: types:: Context ;
2+ use anyhow:: Result ;
3+ use std:: path:: PathBuf ;
4+ use std:: process:: Command ;
5+
6+ #[ derive( Debug , clap:: Args ) ]
7+ /// Build documentation using docserver for publishable crates
8+ pub struct Args {
9+ /// Build docs for only these crates (must be publishable)
10+ #[ clap( long = "crate" ) ]
11+ pub crates : Vec < String > ,
12+
13+ /// Output directory for generated documentation
14+ #[ clap( short, long) ]
15+ pub output : PathBuf ,
16+ }
17+
18+ pub fn run ( ctx : & Context , args : Args ) -> Result < ( ) > {
19+ let crates_to_build = if args. crates . is_empty ( ) {
20+ // Build docs for all publishable crates
21+ ctx. crates
22+ . iter ( )
23+ . filter ( |( _, crate_info) | crate_info. publish )
24+ . map ( |( crate_id, _) | crate_id. clone ( ) )
25+ . collect ( )
26+ } else {
27+ // Build docs for specific crates (only if they are publishable)
28+ let mut crates = Vec :: new ( ) ;
29+ for crate_name in & args. crates {
30+ if !ctx. crates . contains_key ( crate_name) {
31+ anyhow:: bail!( "Crate '{}' not found" , crate_name) ;
32+ }
33+ let crate_info = & ctx. crates [ crate_name] ;
34+ if !crate_info. publish {
35+ println ! ( "⚠️ Skipping non-publishable crate: {}" , crate_name) ;
36+ continue ;
37+ }
38+ crates. push ( crate_name. clone ( ) ) ;
39+ }
40+ crates
41+ } ;
42+
43+ if crates_to_build. is_empty ( ) {
44+ println ! ( "No publishable crates found to build documentation for." ) ;
45+ return Ok ( ( ) ) ;
46+ }
47+
48+ let mut success_count = 0 ;
49+ let mut failed_crates = Vec :: new ( ) ;
50+ let mut is_first_invocation = true ;
51+
52+ for crate_id in & crates_to_build {
53+ let crate_info = & ctx. crates [ crate_id] ;
54+ let input_path = & crate_info. path ;
55+ let output_path = args. output . join ( "crates" ) . join ( crate_id) . join ( "git.zup" ) ;
56+
57+ println ! ( "Building docs for crate: {}" , crate_id) ;
58+
59+ let mut cmd = Command :: new ( "docserver" ) ;
60+ cmd. arg ( "build" )
61+ . arg ( "-i" )
62+ . arg ( input_path)
63+ . arg ( "-o" )
64+ . arg ( & output_path) ;
65+
66+ // Add --output-static for the first docserver invocation
67+ if is_first_invocation {
68+ let static_output = args. output . join ( "static" ) ;
69+ cmd. arg ( "--output-static" ) . arg ( & static_output) ;
70+ is_first_invocation = false ;
71+ }
72+
73+ match cmd. status ( ) {
74+ Ok ( status) if status. success ( ) => {
75+ println ! ( "✅ Successfully built docs for {}" , crate_id) ;
76+ success_count += 1 ;
77+ }
78+ Ok ( status) => {
79+ eprintln ! ( "❌ Failed to build docs for {} (exit code: {:?})" , crate_id, status. code( ) ) ;
80+ failed_crates. push ( crate_id. clone ( ) ) ;
81+ }
82+ Err ( e) => {
83+ eprintln ! ( "❌ Failed to run docserver for {}: {}" , crate_id, e) ;
84+ failed_crates. push ( crate_id. clone ( ) ) ;
85+ }
86+ }
87+ }
88+
89+ println ! ( "\n Summary:" ) ;
90+ println ! ( "✅ Successfully built docs for {} crates" , success_count) ;
91+
92+ if !failed_crates. is_empty ( ) {
93+ println ! ( "❌ Failed to build docs for {} crates:" , failed_crates. len( ) ) ;
94+ for crate_name in & failed_crates {
95+ println ! ( " - {}" , crate_name) ;
96+ }
97+ anyhow:: bail!( "Failed to build docs for {} crates" , failed_crates. len( ) ) ;
98+ }
99+
100+ Ok ( ( ) )
101+ }
0 commit comments