]> git.proxmox.com Git - rustc.git/blob - src/tools/error_index_generator/main.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / tools / error_index_generator / main.rs
1 // Copyright 2015 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.
4 //
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.
10
11 #![feature(rustc_private, rustdoc)]
12 #![feature(question_mark)]
13
14 extern crate syntax;
15 extern crate rustdoc;
16 extern crate serialize as rustc_serialize;
17
18 use std::collections::BTreeMap;
19 use std::env;
20 use std::error::Error;
21 use std::fs::{read_dir, File};
22 use std::io::{Read, Write};
23 use std::path::Path;
24 use std::path::PathBuf;
25
26 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
27
28 use rustdoc::html::markdown::Markdown;
29 use rustc_serialize::json;
30
31 enum OutputFormat {
32 HTML(HTMLFormatter),
33 Markdown(MarkdownFormatter),
34 Unknown(String),
35 }
36
37 impl OutputFormat {
38 fn from(format: &str) -> OutputFormat {
39 match &*format.to_lowercase() {
40 "html" => OutputFormat::HTML(HTMLFormatter),
41 "markdown" => OutputFormat::Markdown(MarkdownFormatter),
42 s => OutputFormat::Unknown(s.to_owned()),
43 }
44 }
45 }
46
47 trait Formatter {
48 fn header(&self, output: &mut Write) -> Result<(), Box<Error>>;
49 fn title(&self, output: &mut Write) -> Result<(), Box<Error>>;
50 fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
51 err_code: &str) -> Result<(), Box<Error>>;
52 fn footer(&self, output: &mut Write) -> Result<(), Box<Error>>;
53 }
54
55 struct HTMLFormatter;
56 struct MarkdownFormatter;
57
58 impl Formatter for HTMLFormatter {
59 fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
60 write!(output, r##"<!DOCTYPE html>
61 <html>
62 <head>
63 <title>Rust Compiler Error Index</title>
64 <meta charset="utf-8">
65 <!-- Include rust.css after main.css so its rules take priority. -->
66 <link rel="stylesheet" type="text/css" href="main.css"/>
67 <link rel="stylesheet" type="text/css" href="rust.css"/>
68 <style>
69 .error-undescribed {{
70 display: none;
71 }}
72 </style>
73 </head>
74 <body>
75 "##)?;
76 Ok(())
77 }
78
79 fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
80 write!(output, "<h1>Rust Compiler Error Index</h1>\n")?;
81 Ok(())
82 }
83
84 fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
85 err_code: &str) -> Result<(), Box<Error>> {
86 // Enclose each error in a div so they can be shown/hidden en masse.
87 let desc_desc = match info.description {
88 Some(_) => "error-described",
89 None => "error-undescribed",
90 };
91 let use_desc = match info.use_site {
92 Some(_) => "error-used",
93 None => "error-unused",
94 };
95 write!(output, "<div class=\"{} {}\">", desc_desc, use_desc)?;
96
97 // Error title (with self-link).
98 write!(output,
99 "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
100 err_code)?;
101
102 // Description rendered as markdown.
103 match info.description {
104 Some(ref desc) => write!(output, "{}", Markdown(desc))?,
105 None => write!(output, "<p>No description.</p>\n")?,
106 }
107
108 write!(output, "</div>\n")?;
109 Ok(())
110 }
111
112 fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
113 write!(output, "</body>\n</html>")?;
114 Ok(())
115 }
116 }
117
118 impl Formatter for MarkdownFormatter {
119 #[allow(unused_variables)]
120 fn header(&self, output: &mut Write) -> Result<(), Box<Error>> {
121 Ok(())
122 }
123
124 fn title(&self, output: &mut Write) -> Result<(), Box<Error>> {
125 write!(output, "# Rust Compiler Error Index\n")?;
126 Ok(())
127 }
128
129 fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
130 err_code: &str) -> Result<(), Box<Error>> {
131 Ok(match info.description {
132 Some(ref desc) => write!(output, "## {}\n{}\n", err_code, desc)?,
133 None => (),
134 })
135 }
136
137 #[allow(unused_variables)]
138 fn footer(&self, output: &mut Write) -> Result<(), Box<Error>> {
139 Ok(())
140 }
141 }
142
143 /// Load all the metadata files from `metadata_dir` into an in-memory map.
144 fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<Error>> {
145 let mut all_errors = BTreeMap::new();
146
147 for entry in read_dir(metadata_dir)? {
148 let path = entry?.path();
149
150 let mut metadata_str = String::new();
151 File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str))?;
152
153 let some_errors: ErrorMetadataMap = json::decode(&metadata_str)?;
154
155 for (err_code, info) in some_errors {
156 all_errors.insert(err_code, info);
157 }
158 }
159
160 Ok(all_errors)
161 }
162
163 /// Output an HTML page for the errors in `err_map` to `output_path`.
164 fn render_error_page<T: Formatter>(err_map: &ErrorMetadataMap, output_path: &Path,
165 formatter: T) -> Result<(), Box<Error>> {
166 let mut output_file = File::create(output_path)?;
167
168 formatter.header(&mut output_file)?;
169 formatter.title(&mut output_file)?;
170
171 for (err_code, info) in err_map {
172 formatter.error_code_block(&mut output_file, info, err_code)?;
173 }
174
175 formatter.footer(&mut output_file)
176 }
177
178 fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box<Error>> {
179 let build_arch = env::var("CFG_BUILD")?;
180 let metadata_dir = get_metadata_dir(&build_arch);
181 let err_map = load_all_errors(&metadata_dir)?;
182 match format {
183 OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s),
184 OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?,
185 OutputFormat::Markdown(m) => render_error_page(&err_map, dst, m)?,
186 }
187 Ok(())
188 }
189
190 fn parse_args() -> (OutputFormat, PathBuf) {
191 let mut args = env::args().skip(1);
192 let format = args.next().map(|a| OutputFormat::from(&a))
193 .unwrap_or(OutputFormat::from("html"));
194 let dst = args.next().map(PathBuf::from).unwrap_or_else(|| {
195 match format {
196 OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"),
197 OutputFormat::Markdown(..) => PathBuf::from("doc/error-index.md"),
198 OutputFormat::Unknown(..) => PathBuf::from("<nul>"),
199 }
200 });
201 (format, dst)
202 }
203
204 fn main() {
205 let (format, dst) = parse_args();
206 if let Err(e) = main_with_result(format, &dst) {
207 panic!("{}", e.description());
208 }
209 }