Simplify exclusion logic

This commit is contained in:
Aleksey Kladov 2020-07-18 16:40:10 +02:00
parent fd6717799c
commit 46ac9ff5e3
7 changed files with 120 additions and 141 deletions

View file

@ -6,9 +6,7 @@
//!
//! Hopefully, one day a reliable file watching/walking crate appears on
//! crates.io, and we can reduce this to trivial glue code.
mod include;
use std::convert::{TryFrom, TryInto};
use std::convert::TryFrom;
use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
@ -16,8 +14,6 @@ use paths::{AbsPath, AbsPathBuf};
use vfs::loader;
use walkdir::WalkDir;
use crate::include::Include;
#[derive(Debug)]
pub struct NotifyHandle {
// Relative order of fields below is significant.
@ -53,7 +49,7 @@ type NotifyEvent = notify::Result<notify::Event>;
struct NotifyActor {
sender: loader::Sender,
config: Vec<(AbsPathBuf, Include, bool)>,
watched_entries: Vec<loader::Entry>,
// Drop order is significant.
watcher: Option<(RecommendedWatcher, Receiver<NotifyEvent>)>,
}
@ -66,7 +62,7 @@ enum Event {
impl NotifyActor {
fn new(sender: loader::Sender) -> NotifyActor {
NotifyActor { sender, config: Vec::new(), watcher: None }
NotifyActor { sender, watched_entries: Vec::new(), watcher: None }
}
fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver);
@ -93,15 +89,17 @@ impl NotifyActor {
let n_total = config.load.len();
self.send(loader::Message::Progress { n_total, n_done: 0 });
self.config.clear();
self.watched_entries.clear();
for (i, entry) in config.load.into_iter().enumerate() {
let watch = config.watch.contains(&i);
if watch {
self.watched_entries.push(entry.clone())
}
let files = self.load_entry(entry, watch);
self.send(loader::Message::Loaded { files });
self.send(loader::Message::Progress { n_total, n_done: i + 1 });
}
self.config.sort_by(|x, y| x.0.cmp(&y.0));
}
Message::Invalidate(path) => {
let contents = read(path.as_path());
@ -116,34 +114,27 @@ impl NotifyActor {
.into_iter()
.map(|path| AbsPathBuf::try_from(path).unwrap())
.filter_map(|path| {
let is_dir = path.is_dir();
let is_file = path.is_file();
let config_idx =
match self.config.binary_search_by(|it| it.0.cmp(&path)) {
Ok(it) => it,
Err(it) => it.saturating_sub(1),
};
let include = self.config.get(config_idx).and_then(|it| {
let rel_path = path.strip_prefix(&it.0)?;
Some((rel_path, &it.1))
});
if let Some((rel_path, include)) = include {
if is_dir && include.exclude_dir(&rel_path)
|| is_file && !include.include_file(&rel_path)
{
return None;
}
}
if is_dir {
if path.is_dir()
&& self
.watched_entries
.iter()
.any(|entry| entry.contains_dir(&path))
{
self.watch(path);
return None;
}
if !is_file {
if !path.is_file() {
return None;
}
if !self
.watched_entries
.iter()
.any(|entry| entry.contains_file(&path))
{
return None;
}
let contents = read(&path);
Some((path, contents))
})
@ -170,43 +161,42 @@ impl NotifyActor {
(file, contents)
})
.collect::<Vec<_>>(),
loader::Entry::Directory { path, include } => {
let include = Include::new(include);
self.config.push((path.clone(), include.clone(), watch));
loader::Entry::Directories(dirs) => {
let mut res = Vec::new();
let files = WalkDir::new(&path)
.into_iter()
.filter_entry(|entry| {
let abs_path: &AbsPath = entry.path().try_into().unwrap();
match abs_path.strip_prefix(&path) {
Some(rel_path) => {
!(entry.file_type().is_dir() && include.exclude_dir(rel_path))
}
None => false,
for root in dirs.include.iter() {
let walkdir = WalkDir::new(root).into_iter().filter_entry(|entry| {
if !entry.file_type().is_dir() {
return true;
}
})
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
let path = AbsPath::assert(entry.path());
root == path
|| dirs.exclude.iter().chain(&dirs.include).all(|it| it != path)
});
let files = walkdir.filter_map(|it| it.ok()).filter_map(|entry| {
let is_dir = entry.file_type().is_dir();
let is_file = entry.file_type().is_file();
let abs_path = AbsPathBuf::try_from(entry.into_path()).unwrap();
let abs_path = AbsPathBuf::assert(entry.into_path());
if is_dir && watch {
self.watch(abs_path.clone());
}
let rel_path = abs_path.strip_prefix(&path)?;
if is_file && include.include_file(&rel_path) {
Some(abs_path)
} else {
None
if !is_file {
return None;
}
let ext = abs_path.extension().unwrap_or_default();
if dirs.extensions.iter().all(|it| it.as_str() != ext) {
return None;
}
Some(abs_path)
});
files
.map(|file| {
res.extend(files.map(|file| {
let contents = read(file.as_path());
(file, contents)
})
.collect()
}));
}
res
}
}
}