1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #[link(name = "rustdoc_ng",
13 uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6",
14 url = "https://github.com/mozilla/rust/tree/master/src/rustdoc_ng")];
16 #[desc = "rustdoc, the Rust documentation extractor"];
17 #[license = "MIT/ASL2"];
18 #[crate_type = "lib"];
24 use extra::serialize::Encodable;
28 use std::rt::io::Writer;
29 use std::rt::io::file::FileInfo;
45 pub static SCHEMA_VERSION: &'static str = "0.8.0";
47 local_data_key!(pub ctxtkey: @core::DocContext)
54 main_args(std::os::args());
57 pub fn main_args(args: &[~str]) {
58 use extra::getopts::groups::*;
61 optmulti("L", "library-path", "directory to add to crate search path",
63 optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
64 optmulti("", "passes", "space separated list of passes to also run",
66 optmulti("", "plugins", "space separated list of plugins to also load",
68 optflag("h", "help", "show this help message"),
69 optflag("", "nodefaults", "don't run the default passes"),
70 optopt("o", "output", "where to place the output", "PATH"),
73 let matches = getopts(args.tail(), opts).unwrap();
76 println(usage(format!("{} [options] [html|json] <crate>", args[0]), opts));
79 if matches.opt_present("h") || matches.opt_present("help") {
84 let (format, cratefile) = match matches.free.clone() {
85 [~"json", crate] => (JSON, crate),
86 [~"html", crate] => (HTML, crate),
88 println!("Unknown output format: `{}`", s);
93 println!("Expected exactly one crate to process");
98 println!("Expected an output format and then one crate");
104 // First, parse the crate and extract all relevant information.
105 let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
106 let cr = Cell::new(Path(cratefile));
107 info2!("starting to run rustc");
108 let crate = do std::task::try {
110 core::run_core(libs.take(), &cr)
112 info2!("finished with rustc");
114 // Process all of the crate attributes, extracting plugin metadata along
115 // with the passes which we are supposed to run.
116 let mut default_passes = !matches.opt_present("nodefaults");
117 let mut passes = matches.opt_strs("passes");
118 let mut plugins = matches.opt_strs("plugins");
119 match crate.module.get_ref().doc_list() {
121 for inner in nested.iter() {
123 clean::Word(~"no_default_passes") => {
124 default_passes = false;
126 clean::NameValue(~"passes", ref value) => {
127 for pass in value.word_iter() {
128 passes.push(pass.to_owned());
131 clean::NameValue(~"plugins", ref value) => {
132 for p in value.word_iter() {
133 plugins.push(p.to_owned());
143 passes.unshift(~"collapse-docs");
144 passes.unshift(~"unindent-comments");
147 // Load all plugins/passes into a PluginManager
148 let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
149 for pass in passes.iter() {
150 let plugin = match pass.as_slice() {
151 "strip-hidden" => passes::strip_hidden,
152 "unindent-comments" => passes::unindent_comments,
153 "collapse-docs" => passes::collapse_docs,
154 "collapse-privacy" => passes::collapse_privacy,
155 s => { error!("unknown pass %s, skipping", s); loop },
157 pm.add_plugin(plugin);
159 info2!("loading plugins...");
160 for pname in plugins.move_iter() {
161 pm.load_plugin(pname);
165 info2!("Executing passes/plugins");
166 let (crate, res) = pm.run_plugins(crate);
168 info2!("going to format");
169 let started = time::precise_time_ns();
170 let output = matches.opt_str("o").map(|s| Path(*s));
172 HTML => { html::render::run(crate, output.unwrap_or(Path("doc"))) }
173 JSON => { jsonify(crate, res, output.unwrap_or(Path("doc.json"))) }
175 let ended = time::precise_time_ns();
176 info2!("Took {:.03f}s", (ended as f64 - started as f64) / 1000000000f64);
179 fn jsonify(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) {
181 // "schema": version,
182 // "crate": { parsed crate ... },
183 // "plugins": { output of plugins ... }
185 let mut json = ~extra::treemap::TreeMap::new();
186 json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
187 let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
189 // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
190 // straight to the Rust JSON representation.
191 let crate_json_str = do std::io::with_str_writer |w| {
192 crate.encode(&mut extra::json::Encoder(w));
194 let crate_json = match extra::json::from_str(crate_json_str) {
196 Err(_) => fail!("Rust generated JSON is invalid??")
199 json.insert(~"crate", crate_json);
200 json.insert(~"plugins", extra::json::Object(plugins_json));
202 let mut file = dst.open_writer(io::Create).unwrap();
203 let output = extra::json::Object(json).to_str();
204 file.write(output.as_bytes());
207 fn exit(status: int) -> ! {
208 #[fixed_stack_segment]; #[inline(never)];
210 unsafe { libc::exit(status as libc::c_int) }