mirror of
https://github.com/watchexec/watchexec.git
synced 2024-11-14 08:11:11 +01:00
Redo and sketch new filter adding process
This commit is contained in:
parent
cd7d5f1fcb
commit
f16ba2dff1
3 changed files with 88 additions and 28 deletions
|
@ -29,23 +29,26 @@ async fn main() -> Result<()> {
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (init, runtime, filterer) = config::new(&args)?;
|
let mut filters = Vec::new();
|
||||||
|
|
||||||
// TODO: move into config?
|
// TODO: move into config?
|
||||||
for filter in args.values_of("filter").unwrap_or_default() {
|
for filter in args.values_of("filter").unwrap_or_default() {
|
||||||
filterer.add_filter(filter.parse()?).await?;
|
filters.push(filter.parse()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ext in args.values_of("extensions").unwrap_or_default().map(|s| s.split(',').map(|s| s.trim())).flatten() {
|
for ext in args.values_of("extensions").unwrap_or_default().map(|s| s.split(',').map(|s| s.trim())).flatten() {
|
||||||
filterer.add_filter(Filter {
|
filters.push(Filter {
|
||||||
in_path: None,
|
in_path: None,
|
||||||
on: Matcher::Path,
|
on: Matcher::Path,
|
||||||
op: Op::Glob,
|
op: Op::Glob,
|
||||||
pat: TaggedFilterer::glob(&format!("**/*.{}", ext))?,
|
pat: TaggedFilterer::glob(&format!("**/*.{}", ext))?,
|
||||||
negate: false,
|
negate: false,
|
||||||
}).await?;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (init, runtime, filterer) = config::new(&args)?;
|
||||||
|
filterer.add_filters(&filters).await?;
|
||||||
|
|
||||||
let wx = Watchexec::new(init, runtime)?;
|
let wx = Watchexec::new(init, runtime)?;
|
||||||
|
|
||||||
if !args.is_present("postpone") {
|
if !args.is_present("postpone") {
|
||||||
|
|
|
@ -20,3 +20,10 @@ impl<T: Filterer> Filterer for Arc<T> {
|
||||||
Arc::as_ref(self).check_event(event)
|
Arc::as_ref(self).check_event(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience function to check a glob pattern from a string.
|
||||||
|
///
|
||||||
|
/// This parses the glob and wraps any error with nice [miette] diagnostics.
|
||||||
|
pub fn check_glob(s: &str) -> Result<&str, ()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use dunce::canonicalize;
|
use dunce::canonicalize;
|
||||||
|
use tokio::fs::read_to_string;
|
||||||
use tracing::{debug, trace, warn};
|
use tracing::{debug, trace, warn};
|
||||||
use unicase::UniCase;
|
use unicase::UniCase;
|
||||||
|
|
||||||
|
@ -162,32 +163,74 @@ impl TaggedFilterer {
|
||||||
.map(Some)
|
.map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_filter(&self, mut filter: Filter) -> Result<(), error::TaggedFiltererError> {
|
pub async fn add_filters(&self, filters: &[Filter]) -> Result<(), error::TaggedFiltererError> {
|
||||||
debug!(?filter, "adding filter to filterer");
|
debug!(?filters, "adding filters to filterer");
|
||||||
|
|
||||||
if let Some(ctx) = &mut filter.in_path {
|
let mut recompile_globs = false;
|
||||||
*ctx = canonicalize(&ctx)?;
|
let mut recompile_not_globs = false;
|
||||||
trace!(canon=?ctx, "canonicalised in_path");
|
|
||||||
}
|
let filters = filters
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.inspect(|f| match f.op {
|
||||||
|
Op::Glob => {
|
||||||
|
recompile_globs = true;
|
||||||
|
}
|
||||||
|
Op::NotGlob => {
|
||||||
|
recompile_not_globs = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
})
|
||||||
|
.map(Filter::canonicalised)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
// TODO: use miette's related and issue canonicalisation errors for all of them
|
||||||
|
|
||||||
self.filters
|
self.filters
|
||||||
.change(|filters| {
|
.change(|fs| {
|
||||||
filters.entry(filter.on).or_default().push(filter);
|
for filter in filters {
|
||||||
|
fs.entry(filter.on).or_default().push(filter);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.map_err(|err| error::TaggedFiltererError::FilterChange { action: "add", err })?;
|
.map_err(|err| error::TaggedFiltererError::FilterChange { action: "add", err })?;
|
||||||
|
|
||||||
|
if recompile_globs {
|
||||||
|
self.recompile_globs(Op::Glob).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if recompile_not_globs {
|
||||||
|
self.recompile_globs(Op::NotGlob).await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_glob_ignore(&self, glob: &str) -> Result<(), error::TaggedFiltererError> {
|
async fn recompile_globs(&self, op_filter: Op) -> Result<(), error::TaggedFiltererError> {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
||||||
|
// globs:
|
||||||
|
// - use ignore's impl
|
||||||
|
// - after adding some filters, recompile by making a gitignorebuilder and storing the gitignore
|
||||||
|
// - use two gitignores: one for NotGlob (which is used for gitignores) and one for Glob (invert results from its matches)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_ignore_file(
|
pub async fn add_ignore_file(
|
||||||
&self,
|
&self,
|
||||||
file: &IgnoreFile,
|
file: &IgnoreFile,
|
||||||
) -> Result<(), error::TaggedFiltererError> {
|
) -> Result<(), error::TaggedFiltererError> {
|
||||||
todo!()
|
let content = read_to_string(&file.path).await?;
|
||||||
|
let lines = content.lines();
|
||||||
|
let mut ignores = Vec::with_capacity(lines.size_hint().0);
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
if line.is_empty() || line.starts_with('#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ignores.push(Filter::from_glob_ignore(file.applies_in.clone(), line));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.add_filters(&ignores).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn clear_filters(&self) -> Result<(), error::TaggedFiltererError> {
|
pub async fn clear_filters(&self) -> Result<(), error::TaggedFiltererError> {
|
||||||
|
@ -201,14 +244,6 @@ impl TaggedFilterer {
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function to check a glob pattern from a string.
|
|
||||||
///
|
|
||||||
/// This parses the glob and wraps any error with nice [miette] diagnostics.
|
|
||||||
pub fn glob(s: &str) -> Result<Pattern, error::TaggedFiltererError> {
|
|
||||||
Glob::new(s).map_err(error::TaggedFiltererError::GlobParse)?;
|
|
||||||
Ok(Pattern::Glob(s.to_string()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -257,6 +292,27 @@ impl Filter {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_glob_ignore(in_path: Option<PathBuf>, glob: &str) -> Self {
|
||||||
|
let (glob, negate) = glob.strip_prefix('!').map_or((glob, false), |g| (g, true));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
in_path,
|
||||||
|
on: Matcher::Path,
|
||||||
|
op: Op::NotGlob,
|
||||||
|
pat: Pattern::Glob(glob.to_string()),
|
||||||
|
negate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonicalised(mut self) -> Result<Self, error::TaggedFiltererError> {
|
||||||
|
if let Some(ctx) = self.in_path {
|
||||||
|
self.in_path = Some(canonicalize(&ctx)?);
|
||||||
|
trace!(canon=?ctx, "canonicalised in_path");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||||
|
@ -298,12 +354,6 @@ pub enum Op {
|
||||||
NotInSet, // :!
|
NotInSet, // :!
|
||||||
}
|
}
|
||||||
|
|
||||||
// globs:
|
|
||||||
// - use ignore's impl
|
|
||||||
// - on adding a filter, compile the gitignorebuilder and store the gitignore
|
|
||||||
// - use two gitignores: one for NotGlob (which is used for gitignores) and one for Glob (invert results from its matches)
|
|
||||||
// - store the globs as strings
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
|
|
Loading…
Reference in a new issue