From 18d62008d4196630da20c91f3ee95e93816d613d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 11 Aug 2024 11:49:47 +0200 Subject: [PATCH] Add possibility to generate rustdoc JSON output to stdout --- src/librustdoc/config.rs | 15 ++++++++---- src/librustdoc/json/mod.rs | 47 +++++++++++++++++++++++++------------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 9c7a9f8467f..cd2892e7a25 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -286,6 +286,9 @@ pub(crate) struct RenderOptions { pub(crate) no_emit_shared: bool, /// If `true`, HTML source code pages won't be generated. 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)] @@ -548,16 +551,17 @@ fn println_condition(condition: Condition) { dcx.fatal("the `--test` flag must be passed to enable `--no-run`"); } + let mut output_to_stdout = false; let test_builder_wrappers = 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 = matches.opt_str("output").map(|s| PathBuf::from(&s)); - let output = match (out_dir, output) { + let output = match (matches.opt_str("out-dir"), matches.opt_str("output")) { (Some(_), Some(_)) => { dcx.fatal("cannot use both 'out-dir' and 'output' at once"); } - (Some(out_dir), None) => out_dir, - (None, Some(output)) => output, + (Some(out_dir), None) | (None, Some(out_dir)) => { + output_to_stdout = out_dir == "-"; + PathBuf::from(out_dir) + } (None, None) => PathBuf::from("doc"), }; @@ -816,6 +820,7 @@ fn println_condition(condition: Condition) { call_locations, no_emit_shared: false, html_no_source, + output_to_stdout, }; Some((options, render_options)) } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index ea191dc89cf..860672443f2 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::fs::{create_dir_all, File}; -use std::io::{BufWriter, Write}; +use std::io::{stdout, BufWriter, Write}; use std::path::PathBuf; use std::rc::Rc; @@ -37,7 +37,7 @@ pub(crate) struct JsonRenderer<'tcx> { /// level field of the JSON blob. index: Rc>>, /// The directory where the blob will be written to. - out_path: PathBuf, + out_path: Option, cache: Rc, imported_items: DefIdSet, } @@ -97,6 +97,20 @@ fn get_impls(&mut self, id: DefId) -> Vec { }) .unwrap_or_default() } + + fn write( + &self, + output: types::Crate, + mut writer: BufWriter, + 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> { @@ -120,7 +134,7 @@ fn init( JsonRenderer { tcx, 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), imported_items, }, @@ -264,20 +278,21 @@ fn after_krate(&mut self) -> Result<(), Error> { .collect(), format_version: types::FORMAT_VERSION, }; - let out_dir = self.out_path.clone(); - try_err!(create_dir_all(&out_dir), out_dir); + if let Some(ref out_path) = self.out_path { + let out_dir = out_path.clone(); + try_err!(create_dir_all(&out_dir), out_dir); - let mut p = out_dir; - p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); - p.set_extension("json"); - let mut file = BufWriter::new(try_err!(File::create(&p), p)); - self.tcx - .sess - .time("rustdoc_json_serialization", || serde_json::ser::to_writer(&mut file, &output)) - .unwrap(); - try_err!(file.flush(), p); - - Ok(()) + let mut p = out_dir; + p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); + p.set_extension("json"); + self.write( + output, + BufWriter::new(try_err!(File::create(&p), p)), + &p.display().to_string(), + ) + } else { + self.write(output, BufWriter::new(stdout()), "") + } } fn cache(&self) -> &Cache {