Load error codes via build script instead of JSON parsing

This scans the tree for `error_codes.rs` and loads all of them.
This commit is contained in:
Mark Rousskov 2019-08-19 18:04:25 -04:00
parent 29a54035c7
commit 99ce39b30a
4 changed files with 84 additions and 31 deletions

View File

@ -946,6 +946,7 @@ name = "error_index_generator"
version = "0.0.0"
dependencies = [
"rustdoc",
"walkdir",
]
[[package]]

View File

@ -3,10 +3,14 @@ authors = ["The Rust Project Developers"]
name = "error_index_generator"
version = "0.0.0"
edition = "2018"
build = "build.rs"
[dependencies]
rustdoc = { path = "../../librustdoc" }
[build-dependencies]
walkdir = "2"
[[bin]]
name = "error_index_generator"
path = "main.rs"

View File

@ -0,0 +1,64 @@
use walkdir::WalkDir;
use std::path::PathBuf;
use std::{env, fs};
fn main() {
// The src directory (we are in src/tools/error_index_generator)
// Note that we could skip one of the .. but this ensures we at least loosely find the right
// directory.
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let dest = out_dir.join("error_codes.rs");
let mut idx = 0;
for entry in WalkDir::new("../../../src") {
let entry = entry.unwrap();
if entry.file_name() == "error_codes.rs" {
println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap());
let file = fs::read_to_string(entry.path()).unwrap()
.replace("use syntax::{register_diagnostics, register_long_diagnostics};", "")
.replace("use syntax::register_diagnostics;", "")
.replace("use syntax::register_long_diagnostics;", "");
let contents = format!("(|| {{\n{}\n}})();", file);
fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap();
idx += 1;
}
}
let mut all = String::new();
all.push_str("fn register_all() -> Vec<(&'static str, Option<&'static str>)> {\n");
all.push_str("let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();\n");
all.push_str(r#"
macro_rules! register_diagnostics {
($($code:tt),*) => {{
long_codes.extend([$(
stringify!($code),
)*].iter().cloned().map(|s| (s, None)).collect::<Vec<_>>());
}};
($($code:tt),*,) => {{
long_codes.extend([$(
stringify!($code),
)*].iter().cloned().map(|s| (s, None)));
}}
}
macro_rules! register_long_diagnostics {
($($code:tt: $description:tt),*) => {
{long_codes.extend([$(
(stringify!($code), Some(stringify!($description))),
)*].iter());}
};
($($code:tt: $description:tt),*,) => {
{long_codes.extend([$(
(stringify!($code), Some(stringify!($description))),
)*].iter());}
}
}"#);
for idx in 0..idx {
all.push_str(&format!(r#"include!(concat!(env!("OUT_DIR"), "/error_{}.rs"));"#, idx));
}
all.push_str("\nlong_codes\n");
all.push_str("}\n");
fs::write(&dest, all).unwrap();
}

View File

@ -2,22 +2,20 @@
extern crate env_logger;
extern crate syntax;
extern crate serialize as rustc_serialize;
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fs::{self, read_dir, File};
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::cell::RefCell;
use syntax::edition::DEFAULT_EDITION;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
use syntax::diagnostics::metadata::{ErrorMetadataMap, ErrorMetadata};
use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, Playground};
use rustc_serialize::json;
enum OutputFormat {
HTML(HTMLFormatter),
@ -80,11 +78,7 @@ impl Formatter for HTMLFormatter {
Some(_) => "error-described",
None => "error-undescribed",
};
let use_desc = match info.use_site {
Some(_) => "error-used",
None => "error-unused",
};
write!(output, "<div class=\"{} {}\">", desc_desc, use_desc)?;
write!(output, "<div class=\"{}\">", desc_desc)?;
// Error title (with self-link).
write!(output,
@ -199,25 +193,6 @@ impl Formatter for MarkdownFormatter {
}
}
/// Loads all the metadata files from `metadata_dir` into an in-memory map.
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<dyn Error>> {
let mut all_errors = BTreeMap::new();
for entry in read_dir(metadata_dir)? {
let path = entry?.path();
let metadata_str = fs::read_to_string(&path)?;
let some_errors: ErrorMetadataMap = json::decode(&metadata_str)?;
for (err_code, info) in some_errors {
all_errors.insert(err_code, info);
}
}
Ok(all_errors)
}
/// Output an HTML page for the errors in `err_map` to `output_path`.
fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
formatter: T) -> Result<(), Box<dyn Error>> {
@ -234,9 +209,16 @@ fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Pat
}
fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<dyn Error>> {
let build_arch = env::var("CFG_BUILD")?;
let metadata_dir = get_metadata_dir(&build_arch);
let err_map = load_all_errors(&metadata_dir)?;
let long_codes = register_all();
let mut err_map = BTreeMap::new();
for (code, desc) in long_codes {
err_map.insert(code.to_string(), ErrorMetadata {
description: desc.map(String::from),
// FIXME: this indicates that the error code is not used, which may not be true.
// We currently do not use this information.
use_site: None,
});
}
match format {
OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
@ -272,3 +254,5 @@ fn main() {
panic!("{}", e.description());
}
}
include!(concat!(env!("OUT_DIR"), "/error_codes.rs"));