Merge pull request #2157 from ehuss/macos-notify-copy
Add workaround for macOS notify problem.
This commit is contained in:
commit
7849d55b99
|
@ -37,7 +37,7 @@ toml = "0.5.11" # Do not update, see https://github.com/rust-lang/mdBook/issues/
|
||||||
topological-sort = "0.2.2"
|
topological-sort = "0.2.2"
|
||||||
|
|
||||||
# Watch feature
|
# Watch feature
|
||||||
notify = { version = "6.0.1", optional = true, features = ["macos_kqueue"] }
|
notify = { version = "6.0.1", optional = true }
|
||||||
notify-debouncer-mini = { version = "0.3.0", optional = true }
|
notify-debouncer-mini = { version = "0.3.0", optional = true }
|
||||||
ignore = { version = "0.4.20", optional = true }
|
ignore = { version = "0.4.20", optional = true }
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ pub fn copy_files_except_ext(
|
||||||
.expect("a file should have a file name...")
|
.expect("a file should have a file name...")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
fs::copy(
|
copy(
|
||||||
entry.path(),
|
entry.path(),
|
||||||
&to.join(
|
&to.join(
|
||||||
entry
|
entry
|
||||||
|
@ -180,6 +180,62 @@ pub fn copy_files_except_ext(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copies a file.
|
||||||
|
fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
|
||||||
|
let from = from.as_ref();
|
||||||
|
let to = to.as_ref();
|
||||||
|
return copy_inner(from, to)
|
||||||
|
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()));
|
||||||
|
|
||||||
|
// This is a workaround for an issue with the macOS file watcher.
|
||||||
|
// Rust's `std::fs::copy` function uses `fclonefileat`, which creates
|
||||||
|
// clones on APFS. Unfortunately fs events seem to trigger on both
|
||||||
|
// sides of the clone, and there doesn't seem to be a way to differentiate
|
||||||
|
// which side it is.
|
||||||
|
// https://github.com/notify-rs/notify/issues/465#issuecomment-1657261035
|
||||||
|
// contains more information.
|
||||||
|
//
|
||||||
|
// This is essentially a copy of the simple copy code path in Rust's
|
||||||
|
// standard library.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn copy_inner(from: &Path, to: &Path) -> Result<()> {
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
|
||||||
|
|
||||||
|
let mut reader = File::open(from)?;
|
||||||
|
let metadata = reader.metadata()?;
|
||||||
|
if !metadata.is_file() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"expected a file, `{}` appears to be {:?}",
|
||||||
|
from.display(),
|
||||||
|
metadata.file_type()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let perm = metadata.permissions();
|
||||||
|
let mut writer = OpenOptions::new()
|
||||||
|
.mode(perm.mode())
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(to)?;
|
||||||
|
let writer_metadata = writer.metadata()?;
|
||||||
|
if writer_metadata.is_file() {
|
||||||
|
// Set the correct file permissions, in case the file already existed.
|
||||||
|
// Don't set the permissions on already existing non-files like
|
||||||
|
// pipes/FIFOs or device nodes.
|
||||||
|
writer.set_permissions(perm)?;
|
||||||
|
}
|
||||||
|
std::io::copy(&mut reader, &mut writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
fn copy_inner(from: &Path, to: &Path) -> Result<()> {
|
||||||
|
fs::copy(from, to)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_404_output_file(input_404: &Option<String>) -> String {
|
pub fn get_404_output_file(input_404: &Option<String>) -> String {
|
||||||
input_404
|
input_404
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
Loading…
Reference in New Issue