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.
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.
11 #![feature(rustc_private, rustdoc)]
15 extern crate serialize
as rustc_serialize
;
17 use std
::collections
::BTreeMap
;
19 use std
::error
::Error
;
20 use std
::fs
::{read_dir, File}
;
21 use std
::io
::{Read, Write}
;
23 use std
::path
::PathBuf
;
25 use syntax
::diagnostics
::metadata
::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}
;
27 use rustdoc
::html
::markdown
::Markdown
;
28 use rustc_serialize
::json
;
32 Markdown(MarkdownFormatter
),
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()),
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
>>;
55 struct MarkdownFormatter
;
57 impl Formatter
for HTMLFormatter
{
58 fn header(&self, output
: &mut Write
) -> Result
<(), Box
<Error
>> {
59 write
!(output
, r
##"<!DOCTYPE html>
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"/>
78 fn title(&self, output
: &mut Write
) -> Result
<(), Box
<Error
>> {
79 write
!(output
, "<h1>Rust Compiler Error Index</h1>\n")?
;
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",
90 let use_desc
= match info
.use_site
{
91 Some(_
) => "error-used",
92 None
=> "error-unused",
94 write
!(output
, "<div class=\"{} {}\">", desc_desc
, use_desc
)?
;
96 // Error title (with self-link).
98 "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
101 // Description rendered as markdown.
102 match info
.description
{
103 Some(ref desc
) => write
!(output
, "{}", Markdown(desc
))?
,
104 None
=> write
!(output
, "<p>No description.</p>\n")?
,
107 write
!(output
, "</div>\n")?
;
111 fn footer(&self, output
: &mut Write
) -> Result
<(), Box
<Error
>> {
112 write
!(output
, "</body>\n</html>")?
;
117 impl Formatter
for MarkdownFormatter
{
118 #[allow(unused_variables)]
119 fn header(&self, output
: &mut Write
) -> Result
<(), Box
<Error
>> {
123 fn title(&self, output
: &mut Write
) -> Result
<(), Box
<Error
>> {
124 write
!(output
, "# Rust Compiler Error Index\n")?
;
128 fn error_code_block(&self, output
: &mut Write
, info
: &ErrorMetadata
,
129 err_code
: &str) -> Result
<(), Box
<Error
>> {
130 Ok(match info
.description
{
131 Some(ref desc
) => write
!(output
, "## {}\n{}\n", err_code
, desc
)?
,
136 #[allow(unused_variables)]
137 fn footer(&self, output
: &mut Write
) -> Result
<(), Box
<Error
>> {
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();
146 for entry
in read_dir(metadata_dir
)?
{
147 let path
= entry?
.path();
149 let mut metadata_str
= String
::new();
150 File
::open(&path
).and_then(|mut f
| f
.read_to_string(&mut metadata_str
))?
;
152 let some_errors
: ErrorMetadataMap
= json
::decode(&metadata_str
)?
;
154 for (err_code
, info
) in some_errors
{
155 all_errors
.insert(err_code
, info
);
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
>> {
165 let mut output_file
= File
::create(output_path
)?
;
167 formatter
.header(&mut output_file
)?
;
168 formatter
.title(&mut output_file
)?
;
170 for (err_code
, info
) in err_map
{
171 formatter
.error_code_block(&mut output_file
, info
, err_code
)?
;
174 formatter
.footer(&mut output_file
)
177 fn main_with_result(format
: OutputFormat
, dst
: &Path
) -> Result
<(), Box
<Error
>> {
178 let build_arch
= env
::var("CFG_BUILD")?
;
179 let metadata_dir
= get_metadata_dir(&build_arch
);
180 let err_map
= load_all_errors(&metadata_dir
)?
;
182 OutputFormat
::Unknown(s
) => panic
!("Unknown output format: {}", s
),
183 OutputFormat
::HTML(h
) => render_error_page(&err_map
, dst
, h
)?
,
184 OutputFormat
::Markdown(m
) => render_error_page(&err_map
, dst
, m
)?
,
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(|| {
195 OutputFormat
::HTML(..) => PathBuf
::from("doc/error-index.html"),
196 OutputFormat
::Markdown(..) => PathBuf
::from("doc/error-index.md"),
197 OutputFormat
::Unknown(..) => PathBuf
::from("<nul>"),
204 let (format
, dst
) = parse_args();
205 if let Err(e
) = main_with_result(format
, &dst
) {
206 panic
!("{}", e
.description());