Skip to content

Commit

Permalink
fix(File watching): Allow glob patterns to be excluded
Browse files Browse the repository at this point in the history
  • Loading branch information
nokome committed May 15, 2021
1 parent f4c0308 commit 37a33c3
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 12 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/Cargo.toml
Expand Up @@ -92,6 +92,7 @@ dirs-next = "2.0.0"
eyre = "0.6.5"
futures = "0.3.14"
gitignore = "1.0.7"
glob = "0.3.0"
handlebars = { version = "3.5.5", optional = true }
humantime = { version = "2.1.0", optional = true }
ignore = "0.4.17"
Expand Down
61 changes: 52 additions & 9 deletions rust/src/files.rs
Expand Up @@ -488,7 +488,7 @@ pub struct Files {

impl Files {
/// Load files from a folder
pub fn load(folder: &str, watch: bool) -> Result<Files> {
pub fn load(folder: &str, watch: bool, watch_exclude_patterns: Vec<String>) -> Result<Files> {
let path = Path::new(folder).canonicalize()?;

// Create a registry of the files
Expand All @@ -506,15 +506,58 @@ impl Files {
let mut watcher = watcher(watcher_sender, Duration::from_secs(1))?;
watcher.watch(&path, RecursiveMode::Recursive).unwrap();

let handle_event = |event| {
let registry = &mut *registry.lock().unwrap();
match event {
DebouncedEvent::Create(path) => registry.created(&path),
DebouncedEvent::Remove(path) => registry.removed(&path),
DebouncedEvent::Rename(from, to) => registry.renamed(&from, &to),
DebouncedEvent::Write(path) => registry.modified(&path),
_ => {}
let exclude_globs: Vec<glob::Pattern> = watch_exclude_patterns
.iter()
.filter_map(|pattern| match glob::Pattern::new(pattern) {
Ok(glob) => Some(glob),
Err(error) => {
tracing::warn!(
"Invalid watch exclude glob pattern; will ignore: {} : {}",
pattern,
error
);
None
}
})
.collect();

let should_include = |event_path: &PathBuf| {
if let Ok(event_path) = event_path.strip_prefix(&path) {
for glob in &exclude_globs {
if glob.matches(&event_path.display().to_string()) {
return false;
}
}
}
true
};

let handle_event = |event| match event {
DebouncedEvent::Create(path) => {
if should_include(&path) {
let registry = &mut *registry.lock().unwrap();
registry.created(&path)
}
}
DebouncedEvent::Remove(path) => {
if should_include(&path) {
let registry = &mut *registry.lock().unwrap();
registry.modified(&path)
}
}
DebouncedEvent::Rename(from, to) => {
if should_include(&from) || should_include(&to) {
let registry = &mut *registry.lock().unwrap();
registry.renamed(&from, &to);
}
}
DebouncedEvent::Write(path) => {
if should_include(&path) {
let registry = &mut *registry.lock().unwrap();
registry.modified(&path)
}
}
_ => {}
};

let project = path.display().to_string();
Expand Down
30 changes: 27 additions & 3 deletions rust/src/projects.rs
Expand Up @@ -45,6 +45,14 @@ pub struct Project {
/// configuration settings.
theme: Option<String>,

/// Glob patterns for paths to be excluded from file watching
///
/// As a performance optimization, paths that match these patterns are
/// excluded from file watching updates.
/// If not specified, will default to the patterns in the
/// configuration settings.
watch_exclude_patterns: Option<Vec<String>>,

// The following properties are derived from the filesystem
// and should never be read from, or written to, the `project.json` file
/// The filesystem path of the project folder
Expand Down Expand Up @@ -141,8 +149,14 @@ impl Project {
pub fn open(folder: &str, config: &config::ProjectsConfig, watch: bool) -> Result<Project> {
let mut project = Project::read(folder)?;

// Watch exclude patterns default to the configured defaults
let watch_exclude_patterns = project
.watch_exclude_patterns
.clone()
.unwrap_or_else(|| config.watch_exclude_patterns.clone());

// Get all the files in the project
project.files = Files::load(folder, watch)?;
project.files = Files::load(folder, watch, watch_exclude_patterns)?;

// Resolve the main file path first as some of the other project properties
// may be defined there (e.g. in the YAML header of a Markdown file)
Expand Down Expand Up @@ -265,8 +279,8 @@ impl Projects {

/// Open a project
///
/// This function `loads` a project, stores it, watches the project folder,
/// updates the project on changes and publishes the updates on the "projects"
/// This function `loads` a project, stores it, optionally watches the project folder,
/// updates the project on changes and publishes the updates on the "project"
/// pubsub topic channel.
pub fn open(
&mut self,
Expand Down Expand Up @@ -319,6 +333,16 @@ pub mod config {
/// Will be applied to all projects that do not specify a theme
#[def = r#"String::from("stencila")"#]
pub theme: String,

/// Default glob patterns for paths to be excluded from file watching
///
/// Used for projects that do not specify their own watch exclude patterns.
/// As a performance optimization, paths that match these patterns are
/// excluded from file watching updates.
/// The default list includes common directories that often have many files
/// that are often updated.
#[def = r#"vec!["*/.git".to_string(), "^*/node_modules".to_string()]"#]
pub watch_exclude_patterns: Vec<String>,
}
}

Expand Down

0 comments on commit 37a33c3

Please sign in to comment.