From 4e17170c54c3e8bbff9cee1937dd6ab3b2001857 Mon Sep 17 00:00:00 2001
From: Artem Kryvokrysenko <krivokrisenko@live.com>
Date: Wed, 19 Jan 2022 00:59:44 -0800
Subject: [PATCH] rustdoc: auto create output directory when "--output-format
 json"

This PR allows rustdoc to automatically create output directory in case
it does not exist (when run with `--output-format json`).

This fixes rustdoc crash:

````
$ rustdoc --output-format json -Z unstable-options src/main.rs
error: couldn't generate documentation: No such file or directory (os error 2)
  |
  = note: failed to create or modify "doc/main.json"

error: aborting due to previous error
````

With this fix behavior of `rustdoc --output-format json` becomes consistent
with `rustdoc --output-format html` (which already auto-creates output
directory if it's missing)
---
 src/librustdoc/json/mod.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 81fbfd9fdbd16..f9e9fe0d3cf20 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -7,7 +7,7 @@
 mod conversions;
 
 use std::cell::RefCell;
-use std::fs::File;
+use std::fs::{create_dir_all, File};
 use std::path::PathBuf;
 use std::rc::Rc;
 
@@ -18,13 +18,14 @@ use rustc_session::Session;
 
 use rustdoc_json_types as types;
 
-use crate::clean;
 use crate::clean::types::{ExternalCrate, ExternalLocation};
 use crate::config::RenderOptions;
+use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
 use crate::json::conversions::{from_item_id, IntoWithTcx};
+use crate::{clean, try_err};
 
 #[derive(Clone)]
 crate struct JsonRenderer<'tcx> {
@@ -256,10 +257,13 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                 .collect(),
             format_version: types::FORMAT_VERSION,
         };
-        let mut p = self.out_path.clone();
+        let out_dir = self.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 file = File::create(&p).map_err(|error| Error { error: error.to_string(), file: p })?;
+        let file = try_err!(File::create(&p), p);
         serde_json::ser::to_writer(&file, &output).unwrap();
         Ok(())
     }