Skip to content

Commit 42c01d7

Browse files
Improve error handling by providing Error struct with Path information
1 parent 8aa621a commit 42c01d7

File tree

1 file changed

+107
-64
lines changed

1 file changed

+107
-64
lines changed

src/librustdoc/html/render.rs

Lines changed: 107 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ use std::cell::RefCell;
3939
use std::cmp::Ordering;
4040
use std::collections::{BTreeMap, HashMap, HashSet};
4141
use std::default::Default;
42-
use std::fmt;
42+
use std::error;
43+
use std::fmt::{self, Display, Formatter};
4344
use std::fs::{self, File};
4445
use std::io::prelude::*;
4546
use std::io::{self, BufWriter, BufReader};
@@ -144,6 +145,42 @@ impl Impl {
144145
}
145146
}
146147

148+
#[derive(Debug)]
149+
pub struct Error {
150+
file: PathBuf,
151+
error: io::Error,
152+
}
153+
154+
impl error::Error for Error {
155+
fn description(&self) -> &str {
156+
self.error.description()
157+
}
158+
}
159+
160+
impl Display for Error {
161+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
162+
write!(f, "\"{}\": {}", self.file.display(), self.error)
163+
}
164+
}
165+
166+
impl Error {
167+
pub fn new(e: io::Error, file: &Path) -> Error {
168+
Error {
169+
file: file.to_path_buf(),
170+
error: e,
171+
}
172+
}
173+
}
174+
175+
macro_rules! try_err {
176+
($e:expr, $file:expr) => ({
177+
match $e {
178+
Ok(e) => e,
179+
Err(e) => return Err(Error::new(e, $file)),
180+
}
181+
})
182+
}
183+
147184
/// This cache is used to store information about the `clean::Crate` being
148185
/// rendered in order to provide more useful documentation. This contains
149186
/// information like all implementors of a trait, all traits a type implements,
@@ -309,7 +346,7 @@ thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> =
309346
pub fn run(mut krate: clean::Crate,
310347
external_html: &ExternalHtml,
311348
dst: PathBuf,
312-
passes: HashSet<String>) -> io::Result<()> {
349+
passes: HashSet<String>) -> Result<(), Error> {
313350
let src_root = match krate.src.parent() {
314351
Some(p) => p.to_path_buf(),
315352
None => PathBuf::new(),
@@ -332,7 +369,7 @@ pub fn run(mut krate: clean::Crate,
332369
issue_tracker_base_url: None,
333370
};
334371

335-
try!(mkdir(&cx.dst));
372+
try_err!(mkdir(&cx.dst), &cx.dst);
336373

337374
// Crawl the crate attributes looking for attributes which control how we're
338375
// going to emit HTML
@@ -434,7 +471,7 @@ pub fn run(mut krate: clean::Crate,
434471
krate = cache.fold_crate(krate);
435472

436473
// Build our search index
437-
let index = try!(build_index(&krate, &mut cache));
474+
let index = build_index(&krate, &mut cache);
438475

439476
// Freeze the cache now that the index has been built. Put an Arc into TLS
440477
// for future parallelization opportunities
@@ -449,7 +486,7 @@ pub fn run(mut krate: clean::Crate,
449486
cx.krate(krate)
450487
}
451488

452-
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> {
489+
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
453490
// Build the search index from the collected metadata
454491
let mut nodeid_to_pathid = HashMap::new();
455492
let mut pathid_to_nodeid = Vec::new();
@@ -476,7 +513,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> {
476513
},
477514
None => {}
478515
}
479-
};
516+
}
480517

481518
// Reduce `NodeId` in paths into smaller sequential numbers,
482519
// and prune the paths that do not appear in the index.
@@ -497,7 +534,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> {
497534

498535
// Collect the index into a string
499536
let mut w = io::Cursor::new(Vec::new());
500-
try!(write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name));
537+
write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name).unwrap();
501538

502539
let mut lastpath = "".to_string();
503540
for (i, item) in cache.search_index.iter().enumerate() {
@@ -511,58 +548,61 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> {
511548
};
512549

513550
if i > 0 {
514-
try!(write!(&mut w, ","));
551+
write!(&mut w, ",").unwrap();
515552
}
516-
try!(write!(&mut w, r#"[{},"{}","{}",{}"#,
517-
item.ty as usize, item.name, path,
518-
item.desc.to_json().to_string()));
553+
write!(&mut w, r#"[{},"{}","{}",{}"#,
554+
item.ty as usize, item.name, path,
555+
item.desc.to_json().to_string()).unwrap();
519556
match item.parent {
520557
Some(nodeid) => {
521558
let pathid = *nodeid_to_pathid.get(&nodeid).unwrap();
522-
try!(write!(&mut w, ",{}", pathid));
559+
write!(&mut w, ",{}", pathid).unwrap();
523560
}
524-
None => try!(write!(&mut w, ",null"))
561+
None => write!(&mut w, ",null").unwrap()
525562
}
526563
match item.search_type {
527-
Some(ref t) => try!(write!(&mut w, ",{}", t)),
528-
None => try!(write!(&mut w, ",null"))
564+
Some(ref t) => write!(&mut w, ",{}", t).unwrap(),
565+
None => write!(&mut w, ",null").unwrap()
529566
}
530-
try!(write!(&mut w, "]"));
567+
write!(&mut w, "]").unwrap();
531568
}
532569

533-
try!(write!(&mut w, r#"],"paths":["#));
570+
write!(&mut w, r#"],"paths":["#).unwrap();
534571

535572
for (i, &did) in pathid_to_nodeid.iter().enumerate() {
536573
let &(ref fqp, short) = cache.paths.get(&did).unwrap();
537574
if i > 0 {
538-
try!(write!(&mut w, ","));
575+
write!(&mut w, ",").unwrap();
539576
}
540-
try!(write!(&mut w, r#"[{},"{}"]"#,
541-
short as usize, *fqp.last().unwrap()));
577+
write!(&mut w, r#"[{},"{}"]"#,
578+
short as usize, *fqp.last().unwrap()).unwrap();
542579
}
543580

544-
try!(write!(&mut w, "]}};"));
581+
write!(&mut w, "]}};").unwrap();
545582

546-
Ok(String::from_utf8(w.into_inner()).unwrap())
583+
String::from_utf8(w.into_inner()).unwrap()
547584
}
548585

549586
fn write_shared(cx: &Context,
550587
krate: &clean::Crate,
551588
cache: &Cache,
552-
search_index: String) -> io::Result<()> {
589+
search_index: String) -> Result<(), Error> {
553590
// Write out the shared files. Note that these are shared among all rustdoc
554591
// docs placed in the output directory, so this needs to be a synchronized
555592
// operation with respect to all other rustdocs running around.
556-
try!(mkdir(&cx.dst));
593+
try_err!(mkdir(&cx.dst), &cx.dst);
557594
let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
558595

559596
// Add all the static files. These may already exist, but we just
560597
// overwrite them anyway to make sure that they're fresh and up-to-date.
561598
try!(write(cx.dst.join("jquery.js"),
562599
include_bytes!("static/jquery-2.1.4.min.js")));
563-
try!(write(cx.dst.join("main.js"), include_bytes!("static/main.js")));
564-
try!(write(cx.dst.join("playpen.js"), include_bytes!("static/playpen.js")));
565-
try!(write(cx.dst.join("main.css"), include_bytes!("static/main.css")));
600+
try!(write(cx.dst.join("main.js"),
601+
include_bytes!("static/main.js")));
602+
try!(write(cx.dst.join("playpen.js"),
603+
include_bytes!("static/playpen.js")));
604+
try!(write(cx.dst.join("main.css"),
605+
include_bytes!("static/main.css")));
566606
try!(write(cx.dst.join("normalize.css"),
567607
include_bytes!("static/normalize.css")));
568608
try!(write(cx.dst.join("FiraSans-Regular.woff"),
@@ -614,18 +654,18 @@ fn write_shared(cx: &Context,
614654

615655
// Update the search index
616656
let dst = cx.dst.join("search-index.js");
617-
let all_indexes = try!(collect(&dst, &krate.name, "searchIndex"));
618-
let mut w = try!(File::create(&dst));
619-
try!(writeln!(&mut w, "var searchIndex = {{}};"));
620-
try!(writeln!(&mut w, "{}", search_index));
657+
let all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
658+
let mut w = try_err!(File::create(&dst), &dst);
659+
try_err!(writeln!(&mut w, "var searchIndex = {{}};"), &dst);
660+
try_err!(writeln!(&mut w, "{}", search_index), &dst);
621661
for index in &all_indexes {
622-
try!(writeln!(&mut w, "{}", *index));
662+
try_err!(writeln!(&mut w, "{}", *index), &dst);
623663
}
624-
try!(writeln!(&mut w, "initSearch(searchIndex);"));
664+
try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst);
625665

626666
// Update the list of all implementors for traits
627667
let dst = cx.dst.join("implementors");
628-
try!(mkdir(&dst));
668+
try_err!(mkdir(&dst), &dst);
629669
for (&did, imps) in &cache.implementors {
630670
// Private modules can leak through to this phase of rustdoc, which
631671
// could contain implementations for otherwise private types. In some
@@ -642,51 +682,53 @@ fn write_shared(cx: &Context,
642682
let mut mydst = dst.clone();
643683
for part in &remote_path[..remote_path.len() - 1] {
644684
mydst.push(part);
645-
try!(mkdir(&mydst));
685+
try_err!(mkdir(&mydst), &mydst);
646686
}
647687
mydst.push(&format!("{}.{}.js",
648688
remote_item_type.to_static_str(),
649689
remote_path[remote_path.len() - 1]));
650-
let all_implementors = try!(collect(&mydst, &krate.name,
651-
"implementors"));
690+
let all_implementors = try_err!(collect(&mydst, &krate.name,
691+
"implementors"),
692+
&mydst);
652693

653-
try!(mkdir(mydst.parent().unwrap()));
654-
let mut f = BufWriter::new(try!(File::create(&mydst)));
655-
try!(writeln!(&mut f, "(function() {{var implementors = {{}};"));
694+
try_err!(mkdir(mydst.parent().unwrap()),
695+
&mydst.parent().unwrap().to_path_buf());
696+
let mut f = BufWriter::new(try_err!(File::create(&mydst), &mydst));
697+
try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst);
656698

657699
for implementor in &all_implementors {
658-
try!(write!(&mut f, "{}", *implementor));
700+
try_err!(write!(&mut f, "{}", *implementor), &mydst);
659701
}
660702

661-
try!(write!(&mut f, r"implementors['{}'] = [", krate.name));
703+
try_err!(write!(&mut f, r"implementors['{}'] = [", krate.name), &mydst);
662704
for imp in imps {
663705
// If the trait and implementation are in the same crate, then
664706
// there's no need to emit information about it (there's inlining
665707
// going on). If they're in different crates then the crate defining
666708
// the trait will be interested in our implementation.
667709
if imp.def_id.krate == did.krate { continue }
668-
try!(write!(&mut f, r#""{}","#, imp.impl_));
710+
try_err!(write!(&mut f, r#""{}","#, imp.impl_), &mydst);
669711
}
670-
try!(writeln!(&mut f, r"];"));
671-
try!(writeln!(&mut f, "{}", r"
712+
try_err!(writeln!(&mut f, r"];"), &mydst);
713+
try_err!(writeln!(&mut f, "{}", r"
672714
if (window.register_implementors) {
673715
window.register_implementors(implementors);
674716
} else {
675717
window.pending_implementors = implementors;
676718
}
677-
"));
678-
try!(writeln!(&mut f, r"}})()"));
719+
"), &mydst);
720+
try_err!(writeln!(&mut f, r"}})()"), &mydst);
679721
}
680722
Ok(())
681723
}
682724

683725
fn render_sources(cx: &mut Context,
684-
krate: clean::Crate) -> io::Result<clean::Crate> {
726+
krate: clean::Crate) -> Result<clean::Crate, Error> {
685727
info!("emitting source files");
686728
let dst = cx.dst.join("src");
687-
try!(mkdir(&dst));
729+
try_err!(mkdir(&dst), &dst);
688730
let dst = dst.join(&krate.name);
689-
try!(mkdir(&dst));
731+
try_err!(mkdir(&dst), &dst);
690732
let mut folder = SourceCollector {
691733
dst: dst,
692734
seen: HashSet::new(),
@@ -699,8 +741,8 @@ fn render_sources(cx: &mut Context,
699741

700742
/// Writes the entire contents of a string to a destination, not attempting to
701743
/// catch any errors.
702-
fn write(dst: PathBuf, contents: &[u8]) -> io::Result<()> {
703-
try!(File::create(&dst)).write_all(contents)
744+
fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> {
745+
Ok(try_err!(try_err!(File::create(&dst), &dst).write_all(contents), &dst))
704746
}
705747

706748
/// Makes a directory on the filesystem, failing the thread if an error occurs and
@@ -849,7 +891,6 @@ impl<'a> SourceCollector<'a> {
849891
fname.push(".html");
850892
cur.push(&fname[..]);
851893
let mut w = BufWriter::new(try!(File::create(&cur)));
852-
853894
let title = format!("{} -- source", cur.file_name().unwrap()
854895
.to_string_lossy());
855896
let desc = format!("Source to the Rust file `{}`.", filename);
@@ -1166,7 +1207,7 @@ impl Context {
11661207
///
11671208
/// This currently isn't parallelized, but it'd be pretty easy to add
11681209
/// parallelization to this function.
1169-
fn krate(self, mut krate: clean::Crate) -> io::Result<()> {
1210+
fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
11701211
let mut item = match krate.module.take() {
11711212
Some(i) => i,
11721213
None => return Ok(())
@@ -1192,7 +1233,7 @@ impl Context {
11921233
/// all sub-items which need to be rendered.
11931234
///
11941235
/// The rendering driver uses this closure to queue up more work.
1195-
fn item<F>(&mut self, item: clean::Item, mut f: F) -> io::Result<()> where
1236+
fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
11961237
F: FnMut(&mut Context, clean::Item),
11971238
{
11981239
fn render(w: File, cx: &Context, it: &clean::Item,
@@ -1279,9 +1320,9 @@ impl Context {
12791320
let mut item = Some(item);
12801321
self.recurse(name, |this| {
12811322
let item = item.take().unwrap();
1282-
let dst = this.dst.join("index.html");
1283-
let dst = try!(File::create(&dst));
1284-
try!(render(dst, this, &item, false));
1323+
let joint_dst = this.dst.join("index.html");
1324+
let dst = try_err!(File::create(&joint_dst), &joint_dst);
1325+
try_err!(render(dst, this, &item, false), &joint_dst);
12851326

12861327
let m = match item.inner {
12871328
clean::ModuleItem(m) => m,
@@ -1292,9 +1333,9 @@ impl Context {
12921333
{
12931334
let items = this.build_sidebar_items(&m);
12941335
let js_dst = this.dst.join("sidebar-items.js");
1295-
let mut js_out = BufWriter::new(try!(File::create(&js_dst)));
1296-
try!(write!(&mut js_out, "initSidebarItems({});",
1297-
json::as_json(&items)));
1336+
let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst));
1337+
try_err!(write!(&mut js_out, "initSidebarItems({});",
1338+
json::as_json(&items)), &js_dst);
12981339
}
12991340

13001341
for item in m.items {
@@ -1307,9 +1348,11 @@ impl Context {
13071348
// Things which don't have names (like impls) don't get special
13081349
// pages dedicated to them.
13091350
_ if item.name.is_some() => {
1310-
let dst = self.dst.join(&item_path(&item));
1311-
let dst = try!(File::create(&dst));
1312-
render(dst, self, &item, true)
1351+
let joint_dst = self.dst.join(&item_path(&item));
1352+
1353+
let dst = try_err!(File::create(&joint_dst), &joint_dst);
1354+
try_err!(render(dst, self, &item, true), &joint_dst);
1355+
Ok(())
13131356
}
13141357

13151358
_ => Ok(())

0 commit comments

Comments
 (0)