1 //! Rustdoc's FileSystem abstraction module.
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.
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
15 use std
::sync
::mpsc
::{channel, Receiver, Sender}
;
18 macro_rules
! try_err
{
19 ($e
:expr
, $file
:expr
) => {{
22 Err(e
) => return Err(E
::new(e
, $file
)),
28 fn new
<P
: AsRef
<Path
>>(e
: io
::Error
, path
: P
) -> Self;
31 pub struct ErrorStorage
{
32 sender
: Option
<Sender
<Option
<String
>>>,
33 receiver
: Receiver
<Option
<String
>>,
37 pub fn new() -> ErrorStorage
{
38 let (sender
, receiver
) = channel();
39 ErrorStorage { sender: Some(sender), receiver }
42 /// Prints all stored errors. Returns the number of printed errors.
43 pub fn write_errors(&mut self, diag
: &rustc_errors
::Handler
) -> usize {
45 // In order to drop the sender part of the channel.
48 for msg
in self.receiver
.iter() {
49 if let Some(ref error
) = msg
{
50 diag
.struct_err(&error
).emit();
60 errors
: Arc
<ErrorStorage
>,
64 pub fn new(errors
: &Arc
<ErrorStorage
>) -> DocFS
{
65 DocFS { sync_only: false, errors: Arc::clone(errors) }
68 pub fn set_sync_only(&mut self, sync_only
: bool
) {
69 self.sync_only
= sync_only
;
72 pub fn create_dir_all
<P
: AsRef
<Path
>>(&self, path
: P
) -> io
::Result
<()> {
73 // For now, dir creation isn't a huge time consideration, do it
74 // synchronously, which avoids needing ordering between write() actions
75 // and directory creation.
76 fs
::create_dir_all(path
)
79 pub fn write
<P
, C
, E
>(&self, path
: P
, contents
: C
) -> Result
<(), E
>
85 if !self.sync_only
&& cfg
!(windows
) {
86 // A possible future enhancement after more detailed profiling would
87 // be to create the file sync so errors are reported eagerly.
88 let contents
= contents
.as_ref().to_vec();
89 let path
= path
.as_ref().to_path_buf();
90 let sender
= self.errors
.sender
.clone().unwrap();
91 rayon
::spawn(move || match fs
::write(&path
, &contents
) {
93 sender
.send(None
).unwrap_or_else(|_
| {
94 panic
!("failed to send error on \"{}\"", path
.display())
98 sender
.send(Some(format
!("\"{}\": {}", path
.display(), e
))).unwrap_or_else(
99 |_
| panic
!("failed to send non-error on \"{}\"", path
.display()),
105 Ok(try_err
!(fs
::write(&path
, contents
), path
))