Add possibility to generate rustdoc JSON output to stdout

This commit is contained in:
Guillaume Gomez 2024-08-11 11:49:47 +02:00
parent c9bd03cb72
commit 18d62008d4
2 changed files with 41 additions and 21 deletions

View File

@ -286,6 +286,9 @@ pub(crate) struct RenderOptions {
pub(crate) no_emit_shared: bool, pub(crate) no_emit_shared: bool,
/// If `true`, HTML source code pages won't be generated. /// If `true`, HTML source code pages won't be generated.
pub(crate) html_no_source: bool, pub(crate) html_no_source: bool,
/// This field is only used for the JSON output. If it's set to true, no file will be created
/// and content will be displayed in stdout directly.
pub(crate) output_to_stdout: bool,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -548,16 +551,17 @@ fn println_condition(condition: Condition) {
dcx.fatal("the `--test` flag must be passed to enable `--no-run`"); dcx.fatal("the `--test` flag must be passed to enable `--no-run`");
} }
let mut output_to_stdout = false;
let test_builder_wrappers = let test_builder_wrappers =
matches.opt_strs("test-builder-wrapper").iter().map(PathBuf::from).collect(); matches.opt_strs("test-builder-wrapper").iter().map(PathBuf::from).collect();
let out_dir = matches.opt_str("out-dir").map(|s| PathBuf::from(&s)); let output = match (matches.opt_str("out-dir"), matches.opt_str("output")) {
let output = matches.opt_str("output").map(|s| PathBuf::from(&s));
let output = match (out_dir, output) {
(Some(_), Some(_)) => { (Some(_), Some(_)) => {
dcx.fatal("cannot use both 'out-dir' and 'output' at once"); dcx.fatal("cannot use both 'out-dir' and 'output' at once");
} }
(Some(out_dir), None) => out_dir, (Some(out_dir), None) | (None, Some(out_dir)) => {
(None, Some(output)) => output, output_to_stdout = out_dir == "-";
PathBuf::from(out_dir)
}
(None, None) => PathBuf::from("doc"), (None, None) => PathBuf::from("doc"),
}; };
@ -816,6 +820,7 @@ fn println_condition(condition: Condition) {
call_locations, call_locations,
no_emit_shared: false, no_emit_shared: false,
html_no_source, html_no_source,
output_to_stdout,
}; };
Some((options, render_options)) Some((options, render_options))
} }

View File

@ -9,7 +9,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::fs::{create_dir_all, File}; use std::fs::{create_dir_all, File};
use std::io::{BufWriter, Write}; use std::io::{stdout, BufWriter, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
@ -37,7 +37,7 @@ pub(crate) struct JsonRenderer<'tcx> {
/// level field of the JSON blob. /// level field of the JSON blob.
index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>, index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
/// The directory where the blob will be written to. /// The directory where the blob will be written to.
out_path: PathBuf, out_path: Option<PathBuf>,
cache: Rc<Cache>, cache: Rc<Cache>,
imported_items: DefIdSet, imported_items: DefIdSet,
} }
@ -97,6 +97,20 @@ fn get_impls(&mut self, id: DefId) -> Vec<types::Id> {
}) })
.unwrap_or_default() .unwrap_or_default()
} }
fn write<T: Write>(
&self,
output: types::Crate,
mut writer: BufWriter<T>,
path: &str,
) -> Result<(), Error> {
self.tcx
.sess
.time("rustdoc_json_serialization", || serde_json::ser::to_writer(&mut writer, &output))
.unwrap();
try_err!(writer.flush(), path);
Ok(())
}
} }
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
@ -120,7 +134,7 @@ fn init(
JsonRenderer { JsonRenderer {
tcx, tcx,
index: Rc::new(RefCell::new(FxHashMap::default())), index: Rc::new(RefCell::new(FxHashMap::default())),
out_path: options.output, out_path: if options.output_to_stdout { None } else { Some(options.output) },
cache: Rc::new(cache), cache: Rc::new(cache),
imported_items, imported_items,
}, },
@ -264,20 +278,21 @@ fn after_krate(&mut self) -> Result<(), Error> {
.collect(), .collect(),
format_version: types::FORMAT_VERSION, format_version: types::FORMAT_VERSION,
}; };
let out_dir = self.out_path.clone(); if let Some(ref out_path) = self.out_path {
let out_dir = out_path.clone();
try_err!(create_dir_all(&out_dir), out_dir); try_err!(create_dir_all(&out_dir), out_dir);
let mut p = out_dir; let mut p = out_dir;
p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
p.set_extension("json"); p.set_extension("json");
let mut file = BufWriter::new(try_err!(File::create(&p), p)); self.write(
self.tcx output,
.sess BufWriter::new(try_err!(File::create(&p), p)),
.time("rustdoc_json_serialization", || serde_json::ser::to_writer(&mut file, &output)) &p.display().to_string(),
.unwrap(); )
try_err!(file.flush(), p); } else {
self.write(output, BufWriter::new(stdout()), "<stdout>")
Ok(()) }
} }
fn cache(&self) -> &Cache { fn cache(&self) -> &Cache {