diff options
Diffstat (limited to 'vendor/mdbook/src/cmd')
-rw-r--r-- | vendor/mdbook/src/cmd/watch.rs | 73 |
1 files changed, 63 insertions, 10 deletions
diff --git a/vendor/mdbook/src/cmd/watch.rs b/vendor/mdbook/src/cmd/watch.rs index e9806e1cd..80b9ff1b1 100644 --- a/vendor/mdbook/src/cmd/watch.rs +++ b/vendor/mdbook/src/cmd/watch.rs @@ -4,6 +4,7 @@ use ignore::gitignore::Gitignore; use mdbook::errors::Result; use mdbook::utils; use mdbook::MDBook; +use pathdiff::diff_paths; use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; use std::thread::sleep; @@ -86,12 +87,21 @@ fn find_gitignore(book_root: &Path) -> Option<PathBuf> { .find(|p| p.exists()) } +// Note: The usage of `canonicalize` may encounter occasional failures on the Windows platform, presenting a potential risk. +// For more details, refer to [Pull Request #2229](https://github.com/rust-lang/mdBook/pull/2229#discussion_r1408665981). fn filter_ignored_files(ignore: Gitignore, paths: &[PathBuf]) -> Vec<PathBuf> { + let ignore_root = ignore + .path() + .canonicalize() + .expect("ignore root canonicalize error"); + paths .iter() .filter(|path| { + let relative_path = + diff_paths(&path, &ignore_root).expect("One of the paths should be an absolute"); !ignore - .matched_path_or_any_parents(path, path.is_dir()) + .matched_path_or_any_parents(&relative_path, relative_path.is_dir()) .is_ignore() }) .map(|path| path.to_path_buf()) @@ -108,8 +118,7 @@ where // Create a channel to receive the events. let (tx, rx) = channel(); - let mut debouncer = match notify_debouncer_mini::new_debouncer(Duration::from_secs(1), None, tx) - { + let mut debouncer = match notify_debouncer_mini::new_debouncer(Duration::from_secs(1), tx) { Ok(d) => d, Err(e) => { error!("Error while trying to watch the files:\n\n\t{:?}", e); @@ -130,11 +139,16 @@ where let _ = watcher.watch(&book.root.join("book.toml"), NonRecursive); for dir in &book.config.build.extra_watch_dirs { - let path = dir.canonicalize().unwrap(); - if let Err(e) = watcher.watch(&path, Recursive) { + let path = book.root.join(dir); + let canonical_path = path.canonicalize().unwrap_or_else(|e| { + error!("Error while watching extra directory {path:?}:\n {e}"); + std::process::exit(1); + }); + + if let Err(e) = watcher.watch(&canonical_path, Recursive) { error!( "Error while watching extra directory {:?}:\n {:?}", - path, e + canonical_path, e ); std::process::exit(1); } @@ -152,10 +166,8 @@ where let paths: Vec<_> = all_events .filter_map(|event| match event { Ok(events) => Some(events), - Err(errors) => { - for error in errors { - log::warn!("error while watching for changes: {error}"); - } + Err(error) => { + log::warn!("error while watching for changes: {error}"); None } }) @@ -174,3 +186,44 @@ where } } } + +#[cfg(test)] +mod tests { + use super::*; + use ignore::gitignore::GitignoreBuilder; + use std::env; + + #[test] + fn test_filter_ignored_files() { + let current_dir = env::current_dir().unwrap(); + + let ignore = GitignoreBuilder::new(¤t_dir) + .add_line(None, "*.html") + .unwrap() + .build() + .unwrap(); + let should_remain = current_dir.join("record.text"); + let should_filter = current_dir.join("index.html"); + + let remain = filter_ignored_files(ignore, &[should_remain.clone(), should_filter]); + assert_eq!(remain, vec![should_remain]) + } + + #[test] + fn filter_ignored_files_should_handle_parent_dir() { + let current_dir = env::current_dir().unwrap(); + + let ignore = GitignoreBuilder::new(¤t_dir) + .add_line(None, "*.html") + .unwrap() + .build() + .unwrap(); + + let parent_dir = current_dir.join(".."); + let should_remain = parent_dir.join("record.text"); + let should_filter = parent_dir.join("index.html"); + + let remain = filter_ignored_files(ignore, &[should_remain.clone(), should_filter]); + assert_eq!(remain, vec![should_remain]) + } +} |