@@ -21,13 +21,15 @@ extern mod syntax;
21
21
extern mod rustc;
22
22
extern mod extra;
23
23
24
- use extra:: serialize:: Encodable ;
25
- use extra:: time;
26
- use extra:: getopts:: groups;
27
24
use std:: cell:: Cell ;
28
- use std:: rt:: io;
29
25
use std:: rt:: io:: Writer ;
30
26
use std:: rt:: io:: file:: FileInfo ;
27
+ use std:: rt:: io;
28
+ use extra:: getopts;
29
+ use extra:: getopts:: groups;
30
+ use extra:: json;
31
+ use extra:: serialize:: { Decodable , Encodable } ;
32
+ use extra:: time;
31
33
32
34
pub mod clean;
33
35
pub mod core;
@@ -70,9 +72,7 @@ static DEFAULT_PASSES: &'static [&'static str] = &[
70
72
71
73
local_data_key ! ( pub ctxtkey: @core:: DocContext )
72
74
73
- enum OutputFormat {
74
- HTML , JSON
75
- }
75
+ type Output = ( clean:: Crate , ~[ plugins:: PluginJson ] ) ;
76
76
77
77
pub fn main ( ) {
78
78
std:: os:: set_exit_status ( main_args ( std:: os:: args ( ) ) ) ;
@@ -81,6 +81,12 @@ pub fn main() {
81
81
pub fn opts ( ) -> ~[ groups:: OptGroup ] {
82
82
use extra:: getopts:: groups:: * ;
83
83
~[
84
+ optflag ( "h" , "help" , "show this help message" ) ,
85
+ optopt ( "r" , "input-format" , "the input type of the specified file" ,
86
+ "[rust|json]" ) ,
87
+ optopt ( "w" , "output-format" , "the output type to write" ,
88
+ "[html|json]" ) ,
89
+ optopt ( "o" , "output" , "where to place the output" , "PATH" ) ,
84
90
optmulti ( "L" , "library-path" , "directory to add to crate search path" ,
85
91
"DIR" ) ,
86
92
optmulti ( "" , "plugin-path" , "directory to load plugins from" , "DIR" ) ,
@@ -89,32 +95,22 @@ pub fn opts() -> ~[groups::OptGroup] {
89
95
"PASSES" ) ,
90
96
optmulti ( "" , "plugins" , "space separated list of plugins to also load" ,
91
97
"PLUGINS" ) ,
92
- optflag ( "h" , "help" , "show this help message" ) ,
93
98
optflag ( "" , "nodefaults" , "don't run the default passes" ) ,
94
- optopt ( "o" , "output" , "where to place the output" , "PATH" ) ,
95
99
]
96
100
}
97
101
98
102
pub fn usage ( argv0 : & str ) {
99
- println ( groups:: usage ( format ! ( "{} [options] [html|json] <crate>" ,
100
- argv0) , opts ( ) ) ) ;
103
+ println ( groups:: usage ( format ! ( "{} [options] <input>" , argv0) , opts ( ) ) ) ;
101
104
}
102
105
103
106
pub fn main_args ( args : & [ ~str ] ) -> int {
104
- //use extra::getopts::groups::*;
105
-
106
107
let matches = groups:: getopts ( args. tail ( ) , opts ( ) ) . unwrap ( ) ;
107
-
108
108
if matches. opt_present ( "h" ) || matches. opt_present ( "help" ) {
109
109
usage ( args[ 0 ] ) ;
110
110
return 0 ;
111
111
}
112
112
113
- let mut default_passes = !matches. opt_present ( "nodefaults" ) ;
114
- let mut passes = matches. opt_strs ( "passes" ) ;
115
- let mut plugins = matches. opt_strs ( "plugins" ) ;
116
-
117
- if passes == ~[ ~"list"] {
113
+ if matches. opt_strs ( "passes" ) == ~[ ~"list"] {
118
114
println ( "Available passes for running rustdoc:" ) ;
119
115
for & ( name, _, description) in PASSES . iter ( ) {
120
116
println ! ( "{:>20s} - {}" , name, description) ;
@@ -126,25 +122,68 @@ pub fn main_args(args: &[~str]) -> int {
126
122
return 0 ;
127
123
}
128
124
129
- let ( format, cratefile) = match matches. free . clone ( ) {
130
- [ ~"json", crate ] => ( JSON , crate ) ,
131
- [ ~"html", crate ] => ( HTML , crate ) ,
132
- [ s, _] => {
133
- println ! ( "Unknown output format: `{}`" , s) ;
134
- usage ( args[ 0 ] ) ;
125
+ let ( crate , res) = match acquire_input ( & matches) {
126
+ Ok ( pair) => pair,
127
+ Err ( s) => {
128
+ println ! ( "input error: {}" , s) ;
135
129
return 1 ;
136
130
}
137
- [ _, .._] => {
138
- println ! ( "Expected exactly one crate to process" ) ;
139
- usage ( args[ 0 ] ) ;
140
- return 1 ;
131
+ } ;
132
+
133
+ info2 ! ( "going to format" ) ;
134
+ let started = time:: precise_time_ns ( ) ;
135
+ let output = matches. opt_str ( "o" ) . map ( |s| Path ( * s) ) ;
136
+ match matches. opt_str ( "w" ) {
137
+ Some ( ~"html") | None => {
138
+ html:: render:: run ( crate , output. unwrap_or ( Path ( "doc" ) ) )
141
139
}
142
- _ => {
143
- println ! ( "Expected an output format and then one crate" ) ;
144
- usage ( args[ 0 ] ) ;
140
+ Some ( ~"json") => {
141
+ json_output ( crate , res, output. unwrap_or ( Path ( "doc.json" ) ) )
142
+ }
143
+ Some ( s) => {
144
+ println ! ( "unknown output format: {}" , s) ;
145
145
return 1 ;
146
146
}
147
- } ;
147
+ }
148
+ let ended = time:: precise_time_ns ( ) ;
149
+ info2 ! ( "Took {:.03f}s" , ( ended as f64 - started as f64 ) / 1000000000f64 ) ;
150
+
151
+ return 0 ;
152
+ }
153
+
154
+ /// Looks inside the command line arguments to extract the relevant input format
155
+ /// and files and then generates the necessary rustdoc output for formatting.
156
+ fn acquire_input ( matches : & getopts:: Matches ) -> Result < Output , ~str > {
157
+ if matches. free . len ( ) == 0 {
158
+ return Err ( ~"expected an input file to act on") ;
159
+ } if matches. free . len ( ) > 1 {
160
+ return Err ( ~"only one input file may be specified") ;
161
+ }
162
+
163
+ let input = matches. free [ 0 ] . as_slice ( ) ;
164
+ match matches. opt_str ( "r" ) {
165
+ Some ( ~"rust") => Ok ( rust_input ( input, matches) ) ,
166
+ Some ( ~"json") => json_input ( input) ,
167
+ Some ( s) => Err ( "unknown input format: " + s) ,
168
+ None => {
169
+ if input. ends_with ( ".json" ) {
170
+ json_input ( input)
171
+ } else {
172
+ Ok ( rust_input ( input, matches) )
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ /// Interprets the input file as a rust source file, passing it through the
179
+ /// compiler all the way through the analysis passes. The rustdoc output is then
180
+ /// generated from the cleaned AST of the crate.
181
+ ///
182
+ /// This form of input will run all of the plug/cleaning passes
183
+ fn rust_input ( cratefile : & str , matches : & getopts:: Matches ) -> Output {
184
+ let mut default_passes = !matches. opt_present ( "nodefaults" ) ;
185
+ let mut passes = matches. opt_strs ( "passes" ) ;
186
+ let mut plugins = matches. opt_strs ( "plugins" ) ;
148
187
149
188
// First, parse the crate and extract all relevant information.
150
189
let libs = Cell :: new ( matches. opt_strs ( "L" ) . map ( |s| Path ( * s) ) ) ;
@@ -206,45 +245,73 @@ pub fn main_args(args: &[~str]) -> int {
206
245
207
246
// Run everything!
208
247
info2 ! ( "Executing passes/plugins" ) ;
209
- let ( crate , res) = pm. run_plugins ( crate ) ;
248
+ return pm. run_plugins ( crate ) ;
249
+ }
210
250
211
- info2 ! ( "going to format" ) ;
212
- let started = time:: precise_time_ns ( ) ;
213
- let output = matches. opt_str ( "o" ) . map ( |s| Path ( * s) ) ;
214
- match format {
215
- HTML => { html:: render:: run ( crate , output. unwrap_or ( Path ( "doc" ) ) ) }
216
- JSON => { jsonify ( crate , res, output. unwrap_or ( Path ( "doc.json" ) ) ) }
251
+ /// This input format purely deserializes the json output file. No passes are
252
+ /// run over the deserialized output.
253
+ fn json_input( input : & str ) -> Result < Output , ~str > {
254
+ let input = match :: std:: io:: file_reader ( & Path ( input) ) {
255
+ Ok ( i) => i,
256
+ Err ( s) => return Err ( s) ,
257
+ } ;
258
+ match json:: from_reader ( input) {
259
+ Err ( s) => Err ( s. to_str ( ) ) ,
260
+ Ok ( json:: Object ( obj) ) => {
261
+ let mut obj = obj;
262
+ // Make sure the schema is what we expect
263
+ match obj. pop ( & ~"schema") {
264
+ Some ( json:: String ( version) ) => {
265
+ if version. as_slice ( ) != SCHEMA_VERSION {
266
+ return Err ( format ! ( "sorry, but I only understand \
267
+ version {}", SCHEMA_VERSION ) )
268
+ }
269
+ }
270
+ Some ( * ) => return Err ( ~"malformed json") ,
271
+ None => return Err ( ~"expected a schema version") ,
272
+ }
273
+ let crate = match obj. pop ( & ~"crate ") {
274
+ Some(json) => {
275
+ let mut d = json::Decoder(json);
276
+ Decodable::decode(&mut d)
277
+ }
278
+ None => return Err(~" malformed json") ,
279
+ } ;
280
+ // XXX: this should read from the "plugins" field, but currently
281
+ // Json doesn't implement decodable...
282
+ let plugin_output = ~[ ] ;
283
+ Ok ( ( crate , plugin_output) )
284
+ }
285
+ Ok ( * ) => Err ( ~"malformed json input: expected an object at the top") ,
217
286
}
218
- let ended = time:: precise_time_ns ( ) ;
219
- info2 ! ( "Took {:.03f}s" , ( ended as f64 - started as f64 ) / 1000000000f64 ) ;
220
-
221
- return 0 ;
222
287
}
223
288
224
- fn jsonify ( crate : clean:: Crate , res : ~[ plugins:: PluginJson ] , dst : Path ) {
289
+ /// Outputs the crate/plugin json as a giant json blob at the specified
290
+ /// destination.
291
+ fn json_output ( crate : clean:: Crate , res: ~[ plugins:: PluginJson ] , dst: Path ) {
225
292
// {
226
293
// "schema": version,
227
294
// "crate": { parsed crate ... },
228
295
// "plugins": { output of plugins ... }
229
296
// }
230
297
let mut json = ~extra:: treemap:: TreeMap :: new ( ) ;
231
- json. insert ( ~"schema", extra :: json:: String ( SCHEMA_VERSION . to_owned ( ) ) ) ;
298
+ json. insert ( ~"schema", json:: String ( SCHEMA_VERSION . to_owned ( ) ) ) ;
232
299
let plugins_json = ~res. move_iter ( ) . filter_map ( |opt| opt) . collect ( ) ;
233
300
234
301
// FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
235
302
// straight to the Rust JSON representation.
236
303
let crate_json_str = do std:: io:: with_str_writer |w| {
237
- crate . encode ( & mut extra :: json:: Encoder ( w) ) ;
304
+ crate . encode ( & mut json:: Encoder ( w) ) ;
238
305
} ;
239
- let crate_json = match extra :: json:: from_str ( crate_json_str) {
306
+ let crate_json = match json:: from_str ( crate_json_str) {
240
307
Ok ( j) => j,
241
308
Err ( _) => fail ! ( "Rust generated JSON is invalid??" )
242
309
} ;
243
310
244
311
json. insert ( ~"crate ", crate_json);
245
- json.insert(~" plugins", extra :: json:: Object ( plugins_json) ) ;
312
+ json.insert(~" plugins", json:: Object ( plugins_json) ) ;
246
313
247
314
let mut file = dst. open_writer ( io:: Create ) . unwrap ( ) ;
248
- let output = extra :: json:: Object ( json) . to_str ( ) ;
315
+ let output = json:: Object ( json) . to_str ( ) ;
249
316
file. write ( output. as_bytes ( ) ) ;
250
317
}
0 commit comments