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