]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/docfs.rs
Add DocFS layer to rustdoc
[rust.git] / src / librustdoc / docfs.rs
1 //! Rustdoc's FileSystem abstraction module.
2 //!
3 //! On Windows this indirects IO into threads to work around performance issues
4 //! with Defender (and other similar virus scanners that do blocking operations).
5 //! On other platforms this is a thin shim to fs.
6 //!
7 //! Only calls needed to permit this workaround have been abstracted: thus
8 //! fs::read is still done directly via the fs module; if in future rustdoc
9 //! needs to read-after-write from a file, then it would be added to this
10 //! abstraction.
11
12 use std::fs;
13 use std::io;
14 use std::path::Path;
15
16 macro_rules! try_err {
17     ($e:expr, $file:expr) => {{
18         match $e {
19             Ok(e) => e,
20             Err(e) => return Err(E::new(e, $file)),
21         }
22     }};
23 }
24
25 pub trait PathError {
26     fn new<P: AsRef<Path>>(e: io::Error, path: P) -> Self;
27 }
28
29 pub struct DocFS {
30     sync_only: bool,
31 }
32
33 impl DocFS {
34     pub fn new() -> DocFS {
35         DocFS {
36             sync_only: false,
37         }
38     }
39
40     pub fn set_sync_only(&mut self, sync_only: bool) {
41         self.sync_only = sync_only;
42     }
43
44     pub fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
45         // For now, dir creation isn't a huge time consideration, do it
46         // synchronously, which avoids needing ordering between write() actions
47         // and directory creation.
48         fs::create_dir_all(path)
49     }
50
51     pub fn write<P, C, E>(&self, path: P, contents: C) -> Result<(), E>
52     where
53         P: AsRef<Path>,
54         C: AsRef<[u8]>,
55         E: PathError,
56     {
57         if !self.sync_only && cfg!(windows) {
58             // A possible future enhancement after more detailed profiling would
59             // be to create the file sync so errors are reported eagerly.
60             let contents = contents.as_ref().to_vec();
61             let path = path.as_ref().to_path_buf();
62             rayon::spawn(move ||
63                 match fs::write(&path, &contents) {
64                     Ok(_) => (),
65                     Err(e) => {
66                         // In principle these should get displayed at the top
67                         // level, but just in case, send to stderr as well.
68                         eprintln!("\"{}\": {}", path.display(), e);
69                         panic!("\"{}\": {}", path.display(), e);
70                     }
71                 });
72             Ok(())
73         } else {
74             Ok(try_err!(fs::write(&path, contents), path))
75         }
76     }
77 }