]> git.lizzy.rs Git - rust.git/commitdiff
Handle fs errors through errors::Handler instead of eprintln and panic
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Sun, 26 May 2019 12:54:50 +0000 (14:54 +0200)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Fri, 21 Jun 2019 10:00:49 +0000 (12:00 +0200)
Cargo.lock
src/librustdoc/docfs.rs
src/librustdoc/html/render.rs

index cf448937e031d012968e9503d6b58938cee1ea22..40b8cf507e97c5b95ec70ca58237359ead967f37 100644 (file)
@@ -3254,6 +3254,7 @@ dependencies = [
  "minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
index eddd426a920a93fa0e14fc213bec2d08bfc16337..96399b8e36f0664788fd489ca19c6dfdc4ce9546 100644 (file)
@@ -9,9 +9,14 @@
 //! needs to read-after-write from a file, then it would be added to this
 //! abstraction.
 
+use errors;
+
+use std::cell::RefCell;
 use std::fs;
 use std::io;
 use std::path::Path;
+use std::sync::Arc;
+use std::sync::mpsc::{channel, Receiver, Sender};
 
 macro_rules! try_err {
     ($e:expr, $file:expr) => {{
@@ -26,14 +31,45 @@ pub trait PathError {
     fn new<P: AsRef<Path>>(e: io::Error, path: P) -> Self;
 }
 
+pub struct ErrorStorage {
+    sender: Sender<Option<String>>,
+    receiver: Receiver<Option<String>>,
+}
+
+impl ErrorStorage {
+    pub fn new() -> ErrorStorage {
+        let (sender, receiver) = channel();
+        ErrorStorage {
+            sender,
+            receiver,
+        }
+    }
+
+    /// Prints all stored errors. Returns the number of printed errors.
+    pub fn write_errors(&self, diag: &errors::Handler) -> usize {
+        let mut printed = 0;
+        drop(self.sender);
+
+        for msg in self.receiver.iter() {
+            if let Some(ref error) = msg {
+                diag.struct_err(&error).emit();
+                printed += 1;
+            }
+        }
+        printed
+    }
+}
+
 pub struct DocFS {
     sync_only: bool,
+    errors: Arc<ErrorStorage>,
 }
 
 impl DocFS {
-    pub fn new() -> DocFS {
+    pub fn new(errors: &Arc<ErrorStorage>) -> DocFS {
         DocFS {
             sync_only: false,
+            errors: Arc::clone(errors),
         }
     }
 
@@ -59,16 +95,19 @@ pub fn write<P, C, E>(&self, path: P, contents: C) -> Result<(), E>
             // be to create the file sync so errors are reported eagerly.
             let contents = contents.as_ref().to_vec();
             let path = path.as_ref().to_path_buf();
-            rayon::spawn(move ||
+            let sender = self.errors.sender.clone();
+            rayon::spawn(move || {
                 match fs::write(&path, &contents) {
-                    Ok(_) => (),
+                    Ok(_) => {
+                        sender.send(None)
+                            .expect(&format!("failed to send error on \"{}\"", path.display()));
+                    }
                     Err(e) => {
-                        // In principle these should get displayed at the top
-                        // level, but just in case, send to stderr as well.
-                        eprintln!("\"{}\": {}", path.display(), e);
-                        panic!("\"{}\": {}", path.display(), e);
+                        sender.send(Some(format!("\"{}\": {}", path.display(), e)))
+                            .expect(&format!("failed to send non-error on \"{}\"", path.display()));
                     }
-                });
+                }
+            });
             Ok(())
         } else {
             Ok(try_err!(fs::write(&path, contents), path))
index 8b514cb09ae190667dbc4945c198c406bae712c6..fe5fb4d73d8e4b53a8c290684f5295042456bb48 100644 (file)
@@ -61,7 +61,7 @@
 
 use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability};
 use crate::config::RenderOptions;
-use crate::docfs::{DocFS, PathError};
+use crate::docfs::{DocFS, ErrorStorage, PathError};
 use crate::doctree;
 use crate::fold::DocFolder;
 use crate::html::escape::Escape;
@@ -104,7 +104,12 @@ fn description(&self) -> &str {
 
 impl Display for Error {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
-        write!(f, "\"{}\": {}", self.file.display(), self.error)
+        let file = self.file.display().to_string();
+        if file.is_empty() {
+            write!(f, "{}", self.error)
+        } else {
+            write!(f, "\"{}\": {}", self.file.display(), self.error)
+        }
     }
 }
 
@@ -547,6 +552,7 @@ pub fn run(mut krate: clean::Crate,
         },
         _ => PathBuf::new(),
     };
+    let errors = Arc::new(ErrorStorage::new());
     let mut scx = SharedContext {
         src_root,
         passes,
@@ -567,7 +573,7 @@ pub fn run(mut krate: clean::Crate,
         static_root_path,
         generate_search_filter,
         generate_redirect_pages,
-        fs: DocFS::new(),
+        fs: DocFS::new(&errors),
     };
 
     // If user passed in `--playground-url` arg, we fill in crate name here
@@ -715,7 +721,15 @@ pub fn run(mut krate: clean::Crate,
     Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
 
     // And finally render the whole crate's documentation
-    cx.krate(krate)
+    let ret = cx.krate(krate);
+    let nb_errors = errors.write_errors(diag);
+    if ret.is_err() {
+        ret
+    } else if nb_errors > 0 {
+        Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
+    } else {
+        Ok(())
+    }
 }
 
 /// Builds the search index from the collected metadata