Support a dedicated ignore file
ref. https://github.com/passcod/cargo-watch/issues/127 This adds support for a dedicated ignore file by the name of `.ignore` a la `fd`, `ripgrep`, et. al. This purely just mimics what `Gitignore` is doing except it doesn't ignore `.git` directories. There might be more I need to tweak and the interface might be too obtuse, but this is a first pass. I've also added a `--no-ignore` flag which ignores both `.gitignore` and the dedicated `.ignore`. It might make sense to add a specific flag that ignores `.ignore` but respects `.gitignore` to support the old behaviour, but I wasn't sure what to name it.
This commit is contained in:
parent
c4ac0c0cbb
commit
e90bbcb9bd
|
@ -20,6 +20,7 @@ pub struct Args {
|
||||||
pub run_initially: bool,
|
pub run_initially: bool,
|
||||||
pub no_shell: bool,
|
pub no_shell: bool,
|
||||||
pub no_vcs_ignore: bool,
|
pub no_vcs_ignore: bool,
|
||||||
|
pub no_ignore: bool,
|
||||||
pub once: bool,
|
pub once: bool,
|
||||||
pub poll: bool,
|
pub poll: bool,
|
||||||
pub poll_interval: u32,
|
pub poll_interval: u32,
|
||||||
|
@ -122,6 +123,9 @@ where
|
||||||
.arg(Arg::with_name("no-vcs-ignore")
|
.arg(Arg::with_name("no-vcs-ignore")
|
||||||
.help("Skip auto-loading of .gitignore files for filtering")
|
.help("Skip auto-loading of .gitignore files for filtering")
|
||||||
.long("no-vcs-ignore"))
|
.long("no-vcs-ignore"))
|
||||||
|
.arg(Arg::with_name("no-ignore")
|
||||||
|
.help("Skip auto-loading of ignore files (.gitignore, .ignore, etc.) for filtering")
|
||||||
|
.long("no-ignore"))
|
||||||
.arg(Arg::with_name("no-default-ignore")
|
.arg(Arg::with_name("no-default-ignore")
|
||||||
.help("Skip auto-ignoring of commonly ignored globs")
|
.help("Skip auto-ignoring of commonly ignored globs")
|
||||||
.long("no-default-ignore"))
|
.long("no-default-ignore"))
|
||||||
|
@ -226,6 +230,7 @@ where
|
||||||
run_initially: !args.is_present("postpone"),
|
run_initially: !args.is_present("postpone"),
|
||||||
no_shell: args.is_present("no-shell"),
|
no_shell: args.is_present("no-shell"),
|
||||||
no_vcs_ignore: args.is_present("no-vcs-ignore"),
|
no_vcs_ignore: args.is_present("no-vcs-ignore"),
|
||||||
|
no_ignore: args.is_present("no-ignore"),
|
||||||
once: args.is_present("once"),
|
once: args.is_present("once"),
|
||||||
poll: args.occurrences_of("poll") > 0,
|
poll: args.occurrences_of("poll") > 0,
|
||||||
poll_interval: poll_interval,
|
poll_interval: poll_interval,
|
||||||
|
|
|
@ -0,0 +1,347 @@
|
||||||
|
extern crate globset;
|
||||||
|
|
||||||
|
use globset::{GlobBuilder, GlobSet, GlobSetBuilder};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub struct Ignore {
|
||||||
|
files: Vec<IgnoreFile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
GlobSet(globset::Error),
|
||||||
|
Io(io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IgnoreFile {
|
||||||
|
set: GlobSet,
|
||||||
|
patterns: Vec<Pattern>,
|
||||||
|
root: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Pattern {
|
||||||
|
pattern: String,
|
||||||
|
pattern_type: PatternType,
|
||||||
|
anchored: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PatternType {
|
||||||
|
Ignore,
|
||||||
|
Whitelist,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum MatchResult {
|
||||||
|
Ignore,
|
||||||
|
Whitelist,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(paths: &[PathBuf]) -> Ignore {
|
||||||
|
let mut files = vec![];
|
||||||
|
let mut checked_dirs = HashSet::new();
|
||||||
|
|
||||||
|
for path in paths {
|
||||||
|
let mut p = path.to_owned();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if !checked_dirs.contains(&p) {
|
||||||
|
checked_dirs.insert(p.clone());
|
||||||
|
|
||||||
|
let ignore_path = p.join(".ignore");
|
||||||
|
if ignore_path.exists() {
|
||||||
|
match IgnoreFile::new(&ignore_path) {
|
||||||
|
Ok(f) => {
|
||||||
|
debug!("Loaded {:?}", ignore_path);
|
||||||
|
files.push(f);
|
||||||
|
}
|
||||||
|
Err(_) => debug!("Unable to load {:?}", ignore_path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.parent().is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ignore::new(files)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ignore {
|
||||||
|
fn new(files: Vec<IgnoreFile>) -> Ignore {
|
||||||
|
Ignore { files: files }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_excluded(&self, path: &Path) -> bool {
|
||||||
|
let mut applicable_files: Vec<&IgnoreFile> = self
|
||||||
|
.files
|
||||||
|
.iter()
|
||||||
|
.filter(|f| path.starts_with(&f.root))
|
||||||
|
.collect();
|
||||||
|
applicable_files.sort_by(|l, r| l.root_len().cmp(&r.root_len()));
|
||||||
|
|
||||||
|
// TODO: add user ignores
|
||||||
|
|
||||||
|
let mut result = MatchResult::None;
|
||||||
|
|
||||||
|
for file in applicable_files {
|
||||||
|
match file.matches(path) {
|
||||||
|
MatchResult::Ignore => result = MatchResult::Ignore,
|
||||||
|
MatchResult::Whitelist => result = MatchResult::Whitelist,
|
||||||
|
MatchResult::None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result == MatchResult::Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IgnoreFile {
|
||||||
|
pub fn new(path: &Path) -> Result<IgnoreFile, Error> {
|
||||||
|
let mut file = fs::File::open(path)?;
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)?;
|
||||||
|
|
||||||
|
let lines = contents.lines().collect();
|
||||||
|
let root = path.parent().unwrap();
|
||||||
|
|
||||||
|
IgnoreFile::from_strings(lines, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_strings(strs: Vec<&str>, root: &Path) -> Result<IgnoreFile, Error> {
|
||||||
|
let mut builder = GlobSetBuilder::new();
|
||||||
|
let mut patterns = vec![];
|
||||||
|
|
||||||
|
let parsed_patterns = IgnoreFile::parse(strs);
|
||||||
|
for p in parsed_patterns {
|
||||||
|
let mut pat = String::from(p.pattern.clone());
|
||||||
|
if !p.anchored && !pat.starts_with("**/") {
|
||||||
|
pat = "**/".to_string() + &pat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pat.ends_with("/**") {
|
||||||
|
pat = pat + "/**";
|
||||||
|
}
|
||||||
|
|
||||||
|
let glob = GlobBuilder::new(&pat).literal_separator(true).build()?;
|
||||||
|
|
||||||
|
builder.add(glob);
|
||||||
|
patterns.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(IgnoreFile {
|
||||||
|
set: builder.build()?,
|
||||||
|
patterns: patterns,
|
||||||
|
root: root.to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn is_excluded(&self, path: &Path) -> bool {
|
||||||
|
self.matches(path) == MatchResult::Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(&self, path: &Path) -> MatchResult {
|
||||||
|
let stripped = path.strip_prefix(&self.root);
|
||||||
|
if !stripped.is_ok() {
|
||||||
|
return MatchResult::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let matches = self.set.matches(stripped.unwrap());
|
||||||
|
|
||||||
|
for &i in matches.iter().rev() {
|
||||||
|
let pattern = &self.patterns[i];
|
||||||
|
return match pattern.pattern_type {
|
||||||
|
PatternType::Whitelist => MatchResult::Whitelist,
|
||||||
|
PatternType::Ignore => MatchResult::Ignore,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchResult::None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_len(&self) -> usize {
|
||||||
|
self.root.as_os_str().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(contents: Vec<&str>) -> Vec<Pattern> {
|
||||||
|
contents
|
||||||
|
.iter()
|
||||||
|
.filter(|l| !l.is_empty())
|
||||||
|
.filter(|l| !l.starts_with('#'))
|
||||||
|
.map(|l| Pattern::parse(l))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pattern {
|
||||||
|
fn parse(pattern: &str) -> Pattern {
|
||||||
|
let mut normalized = String::from(pattern);
|
||||||
|
|
||||||
|
let pattern_type = if normalized.starts_with('!') {
|
||||||
|
normalized.remove(0);
|
||||||
|
PatternType::Whitelist
|
||||||
|
} else {
|
||||||
|
PatternType::Ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
let anchored = if normalized.starts_with('/') {
|
||||||
|
normalized.remove(0);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if normalized.ends_with('/') {
|
||||||
|
normalized.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if normalized.starts_with("\\#") || normalized.starts_with("\\!") {
|
||||||
|
normalized.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern {
|
||||||
|
pattern: normalized,
|
||||||
|
pattern_type: pattern_type,
|
||||||
|
anchored: anchored,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<globset::Error> for Error {
|
||||||
|
fn from(error: globset::Error) -> Error {
|
||||||
|
Error::GlobSet(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(error: io::Error) -> Error {
|
||||||
|
Error::Io(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::IgnoreFile;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn base_dir() -> PathBuf {
|
||||||
|
PathBuf::from("/home/user/dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_ignore(pattern: &str) -> IgnoreFile {
|
||||||
|
IgnoreFile::from_strings(vec![pattern], &base_dir()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_exact() {
|
||||||
|
let file = build_ignore("Cargo.toml");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("Cargo.toml")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_does_not_match() {
|
||||||
|
let file = build_ignore("Cargo.toml");
|
||||||
|
|
||||||
|
assert!(!file.is_excluded(&base_dir().join("src").join("main.rs")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_simple_wildcard() {
|
||||||
|
let file = build_ignore("targ*");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_subdir_exact() {
|
||||||
|
let file = build_ignore("target");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target/")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_matches_subdir() {
|
||||||
|
let file = build_ignore("target");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("file")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("subdir").join("file")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wildcard_with_dir() {
|
||||||
|
let file = build_ignore("target/f*");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("file")));
|
||||||
|
assert!(!file.is_excluded(&base_dir().join("target").join("subdir").join("file")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_leading_slash() {
|
||||||
|
let file = build_ignore("/*.c");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("cat-file.c")));
|
||||||
|
assert!(!file.is_excluded(&base_dir().join("mozilla-sha1").join("sha1.c")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_leading_double_wildcard() {
|
||||||
|
let file = build_ignore("**/foo");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("foo")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("foo")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("subdir").join("foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trailing_double_wildcard() {
|
||||||
|
let file = build_ignore("abc/**");
|
||||||
|
|
||||||
|
assert!(!file.is_excluded(&base_dir().join("def").join("foo")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("abc").join("foo")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("abc").join("subdir").join("foo")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sandwiched_double_wildcard() {
|
||||||
|
let file = build_ignore("a/**/b");
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("a").join("b")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("a").join("x").join("b")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("a").join("x").join("y").join("b")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_file_never_excludes() {
|
||||||
|
let file = IgnoreFile::from_strings(vec![], &base_dir()).unwrap();
|
||||||
|
|
||||||
|
assert!(!file.is_excluded(&base_dir().join("target")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_checks_all_patterns() {
|
||||||
|
let patterns = vec!["target", "target2"];
|
||||||
|
let file = IgnoreFile::from_strings(patterns, &base_dir()).unwrap();
|
||||||
|
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("foo.txt")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target2").join("bar.txt")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handles_whitelisting() {
|
||||||
|
let patterns = vec!["target", "!target/foo.txt"];
|
||||||
|
let file = IgnoreFile::from_strings(patterns, &base_dir()).unwrap();
|
||||||
|
|
||||||
|
assert!(!file.is_excluded(&base_dir().join("target").join("foo.txt")));
|
||||||
|
assert!(file.is_excluded(&base_dir().join("target").join("blah.txt")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ extern crate winapi;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod gitignore;
|
mod gitignore;
|
||||||
|
mod ignore;
|
||||||
mod notification_filter;
|
mod notification_filter;
|
||||||
pub mod pathop;
|
pub mod pathop;
|
||||||
mod process;
|
mod process;
|
||||||
|
|
|
@ -3,20 +3,23 @@ extern crate glob;
|
||||||
use error;
|
use error;
|
||||||
use gitignore::Gitignore;
|
use gitignore::Gitignore;
|
||||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||||
|
use ignore::Ignore;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct NotificationFilter {
|
pub struct NotificationFilter {
|
||||||
filters: GlobSet,
|
filters: GlobSet,
|
||||||
filter_count: usize,
|
filter_count: usize,
|
||||||
ignores: GlobSet,
|
ignores: GlobSet,
|
||||||
ignore_files: Gitignore,
|
gitignore_files: Gitignore,
|
||||||
|
ignore_files: Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotificationFilter {
|
impl NotificationFilter {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
filters: &[String],
|
filters: &[String],
|
||||||
ignores: &[String],
|
ignores: &[String],
|
||||||
ignore_files: Gitignore,
|
gitignore_files: Gitignore,
|
||||||
|
ignore_files: Ignore,
|
||||||
) -> error::Result<NotificationFilter> {
|
) -> error::Result<NotificationFilter> {
|
||||||
let mut filter_set_builder = GlobSetBuilder::new();
|
let mut filter_set_builder = GlobSetBuilder::new();
|
||||||
for f in filters {
|
for f in filters {
|
||||||
|
@ -39,6 +42,7 @@ impl NotificationFilter {
|
||||||
filters: filter_set_builder.build()?,
|
filters: filter_set_builder.build()?,
|
||||||
filter_count: filters.len(),
|
filter_count: filters.len(),
|
||||||
ignores: ignore_set_builder.build()?,
|
ignores: ignore_set_builder.build()?,
|
||||||
|
gitignore_files: gitignore_files,
|
||||||
ignore_files: ignore_files,
|
ignore_files: ignore_files,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -54,6 +58,11 @@ impl NotificationFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ignore_files.is_excluded(path) {
|
if self.ignore_files.is_excluded(path) {
|
||||||
|
debug!("Ignoring {:?}: matched ignore file", path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.gitignore_files.is_excluded(path) {
|
||||||
debug!("Ignoring {:?}: matched gitignore file", path);
|
debug!("Ignoring {:?}: matched gitignore file", path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -70,19 +79,26 @@ impl NotificationFilter {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::NotificationFilter;
|
use super::NotificationFilter;
|
||||||
use gitignore;
|
use gitignore;
|
||||||
|
use ignore;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_allows_everything_by_default() {
|
fn test_allows_everything_by_default() {
|
||||||
let filter = NotificationFilter::new(&[], &[], gitignore::load(&[])).unwrap();
|
let filter =
|
||||||
|
NotificationFilter::new(&[], &[], gitignore::load(&[]), ignore::load(&[])).unwrap();
|
||||||
|
|
||||||
assert!(!filter.is_excluded(&Path::new("foo")));
|
assert!(!filter.is_excluded(&Path::new("foo")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_filename() {
|
fn test_filename() {
|
||||||
let filter =
|
let filter = NotificationFilter::new(
|
||||||
NotificationFilter::new(&[], &["test.json".into()], gitignore::load(&[])).unwrap();
|
&[],
|
||||||
|
&["test.json".into()],
|
||||||
|
gitignore::load(&[]),
|
||||||
|
ignore::load(&[]),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(filter.is_excluded(&Path::new("/path/to/test.json")));
|
assert!(filter.is_excluded(&Path::new("/path/to/test.json")));
|
||||||
assert!(filter.is_excluded(&Path::new("test.json")));
|
assert!(filter.is_excluded(&Path::new("test.json")));
|
||||||
|
@ -91,7 +107,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiple_filters() {
|
fn test_multiple_filters() {
|
||||||
let filters = &["*.rs".into(), "*.toml".into()];
|
let filters = &["*.rs".into(), "*.toml".into()];
|
||||||
let filter = NotificationFilter::new(filters, &[], gitignore::load(&[])).unwrap();
|
let filter =
|
||||||
|
NotificationFilter::new(filters, &[], gitignore::load(&[]), ignore::load(&[])).unwrap();
|
||||||
|
|
||||||
assert!(!filter.is_excluded(&Path::new("hello.rs")));
|
assert!(!filter.is_excluded(&Path::new("hello.rs")));
|
||||||
assert!(!filter.is_excluded(&Path::new("Cargo.toml")));
|
assert!(!filter.is_excluded(&Path::new("Cargo.toml")));
|
||||||
|
@ -101,7 +118,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiple_ignores() {
|
fn test_multiple_ignores() {
|
||||||
let ignores = &["*.rs".into(), "*.toml".into()];
|
let ignores = &["*.rs".into(), "*.toml".into()];
|
||||||
let filter = NotificationFilter::new(&[], ignores, gitignore::load(&[])).unwrap();
|
let filter =
|
||||||
|
NotificationFilter::new(&[], ignores, gitignore::load(&[]), ignore::load(&[])).unwrap();
|
||||||
|
|
||||||
assert!(filter.is_excluded(&Path::new("hello.rs")));
|
assert!(filter.is_excluded(&Path::new("hello.rs")));
|
||||||
assert!(filter.is_excluded(&Path::new("Cargo.toml")));
|
assert!(filter.is_excluded(&Path::new("Cargo.toml")));
|
||||||
|
@ -111,7 +129,9 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ignores_take_precedence() {
|
fn test_ignores_take_precedence() {
|
||||||
let ignores = &["*.rs".into(), "*.toml".into()];
|
let ignores = &["*.rs".into(), "*.toml".into()];
|
||||||
let filter = NotificationFilter::new(ignores, ignores, gitignore::load(&[])).unwrap();
|
let filter =
|
||||||
|
NotificationFilter::new(ignores, ignores, gitignore::load(&[]), ignore::load(&[]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(filter.is_excluded(&Path::new("hello.rs")));
|
assert!(filter.is_excluded(&Path::new("hello.rs")));
|
||||||
assert!(filter.is_excluded(&Path::new("Cargo.toml")));
|
assert!(filter.is_excluded(&Path::new("Cargo.toml")));
|
||||||
|
|
10
src/run.rs
10
src/run.rs
|
@ -2,6 +2,7 @@ use cli::{clear_screen, Args};
|
||||||
use env_logger;
|
use env_logger;
|
||||||
use error::{Error, Result};
|
use error::{Error, Result};
|
||||||
use gitignore;
|
use gitignore;
|
||||||
|
use ignore;
|
||||||
use log;
|
use log;
|
||||||
use notification_filter::NotificationFilter;
|
use notification_filter::NotificationFilter;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
@ -87,8 +88,13 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let gitignore = gitignore::load(if args.no_vcs_ignore { &[] } else { &paths });
|
let ignore = ignore::load(if args.no_ignore { &[] } else { &paths });
|
||||||
let filter = NotificationFilter::new(&args.filters, &args.ignores, gitignore)?;
|
let gitignore = gitignore::load(if args.no_vcs_ignore || args.no_ignore {
|
||||||
|
&[]
|
||||||
|
} else {
|
||||||
|
&paths
|
||||||
|
});
|
||||||
|
let filter = NotificationFilter::new(&args.filters, &args.ignores, gitignore, ignore)?;
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let poll = args.poll.clone();
|
let poll = args.poll.clone();
|
||||||
|
|
Loading…
Reference in New Issue