Implement ignore rules.
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -26,15 +26,6 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bstr"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "camino"
|
name = "camino"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -87,12 +78,6 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.4"
|
version = "0.14.4"
|
||||||
@@ -114,19 +99,6 @@ dependencies = [
|
|||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "globset"
|
|
||||||
version = "0.4.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"bstr",
|
|
||||||
"fnv",
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libbsv"
|
name = "libbsv"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -134,7 +106,7 @@ dependencies = [
|
|||||||
"camino",
|
"camino",
|
||||||
"cas-core",
|
"cas-core",
|
||||||
"cas-simple",
|
"cas-simple",
|
||||||
"globset",
|
"regex",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -144,15 +116,6 @@ version = "0.2.98"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ license = "AGPL-3.0-or-later"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
camino = { version = "1.0.7" }
|
camino = "1.0.7"
|
||||||
globset = "0.4.9"
|
regex = "1.6.0"
|
||||||
cas-core = { path = "../cas-core" }
|
cas-core = { path = "../cas-core" }
|
||||||
cas-simple = { path = "../cas-simple" }
|
cas-simple = { path = "../cas-simple" }
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
|
|
||||||
|
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::{Utf8Path, Utf8PathBuf};
|
||||||
use globset::GlobSet;
|
use regex::RegexSet;
|
||||||
|
|
||||||
use cas_core::{err, Error, Result};
|
use cas_core::{err, Error, Result};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Ignore,
|
Ignore,
|
||||||
Accept,
|
Accept,
|
||||||
@@ -29,7 +29,7 @@ pub enum Action {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IgnoreRules {
|
pub struct IgnoreRules {
|
||||||
patterns: GlobSet,
|
patterns: RegexSet,
|
||||||
actions: Vec<Action>,
|
actions: Vec<Action>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,21 +37,101 @@ pub struct IgnoreRules {
|
|||||||
impl IgnoreRules {
|
impl IgnoreRules {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
patterns: GlobSet::default(),
|
patterns: RegexSet::new(&[] as &[&str]).unwrap(),
|
||||||
actions: vec![],
|
actions: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_vec(vec: Vec<(Action, Utf8PathBuf)>) -> Result<Self> {
|
pub fn from_source<P: AsRef<Utf8Path>>(source: &str, root: P) -> Result<Self> {
|
||||||
err!("Todo")
|
assert!(root.as_ref().is_absolute());
|
||||||
|
|
||||||
|
let separator = if std::path::MAIN_SEPARATOR == '/' {
|
||||||
|
"/"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert_eq!(std::path::MAIN_SEPARATOR, '\\');
|
||||||
|
"\\\\"
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut patterns = Vec::<String>::default();
|
||||||
|
let mut actions = Vec::<Action>::default();
|
||||||
|
|
||||||
|
for line in source.lines() {
|
||||||
|
let rule = line.trim();
|
||||||
|
let mut rule_it = rule.chars().peekable();
|
||||||
|
if rule_it.peek().is_none() || rule_it.peek() == Some(&'#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if rule_it.peek() == Some(&'!') {
|
||||||
|
rule_it.next();
|
||||||
|
actions.push(Action::Accept);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
actions.push(Action::Ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut pat = String::new();
|
||||||
|
let mut last_is_sep = false;
|
||||||
|
|
||||||
|
if rule_it.peek() == Some(&'/') {
|
||||||
|
pat.push_str("^");
|
||||||
|
pat.push_str(®ex::escape(root.as_ref().as_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(c) = rule_it.next() {
|
||||||
|
if c == '/' {
|
||||||
|
pat.push_str(separator);
|
||||||
|
last_is_sep = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if c == '*' {
|
||||||
|
if rule_it.peek() == Some(&'*') {
|
||||||
|
rule_it.next();
|
||||||
|
if !last_is_sep || (!rule_it.peek().is_none() && rule_it.peek() != Some(&'/')) {
|
||||||
|
return err!("** pattern can only be used as a whole path segment");
|
||||||
|
}
|
||||||
|
pat.push_str(".*");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pat.push_str("[^/]*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if c == '\\' {
|
||||||
|
let c2 = rule_it.next().ok_or(Error::unknown("invalid \\ at end of rule"))?;
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
pat.push_str(®ex::escape(c2.encode_utf8(&mut buf)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
pat.push_str(®ex::escape(c.encode_utf8(&mut buf)));
|
||||||
|
}
|
||||||
|
last_is_sep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if last_is_sep {
|
||||||
|
pat.pop();
|
||||||
|
}
|
||||||
|
pat.push_str("(/.*)?$");
|
||||||
|
|
||||||
|
dbg!(&pat);
|
||||||
|
patterns.push(pat);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
patterns: RegexSet::new(patterns)
|
||||||
|
.or_else(|err| err!("failed to compile ignore rules: {err}"))?,
|
||||||
|
actions: actions,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_ignore_file(ignore_file: &str, root: &Utf8Path) -> Result<Self> {
|
pub fn action_for<P: AsRef<Utf8Path>>(&self, path: P) -> Action {
|
||||||
err!("Todo")
|
assert!(path.as_ref().is_absolute());
|
||||||
}
|
let index = self.patterns.matches(path.as_ref().as_str())
|
||||||
|
.iter()
|
||||||
pub fn is_ignored<P: AsRef<Utf8PathBuf>>(&self, path: P) -> bool {
|
.next()
|
||||||
|
.unwrap_or(self.actions.len());
|
||||||
|
*self.actions.get(index).unwrap_or(&Action::Accept)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,5 +143,21 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_path_map() {
|
fn test_path_map() {
|
||||||
|
let root = Utf8PathBuf::from("/foo.dir/bar");
|
||||||
|
let patterns = "!hello/world\nhello\n/world/\n\\!\\*\n*.bak";
|
||||||
|
let ignore = IgnoreRules::from_source(patterns, root).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test")), Action::Accept);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/aoeu")), Action::Ignore);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello_world/aoeu")), Action::Accept);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/world/aoeu")), Action::Accept);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/hello/world/aoeu")), Action::Accept);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world/aoeu")), Action::Ignore);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/world")), Action::Ignore);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/fooXdir/bar/world")), Action::Accept);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/!*/aoeu")), Action::Ignore);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/file.bak")), Action::Ignore);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test/fileXbak")), Action::Accept);
|
||||||
|
assert_eq!(ignore.action_for(Utf8PathBuf::from("/foo.dir/bar/test.bak/file")), Action::Ignore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate camino;
|
extern crate camino;
|
||||||
extern crate globset;
|
extern crate regex;
|
||||||
|
|
||||||
extern crate cas_core;
|
extern crate cas_core;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ mod tree_item;
|
|||||||
// mod tree_walker;
|
// mod tree_walker;
|
||||||
// mod config;
|
// mod config;
|
||||||
mod path_map;
|
mod path_map;
|
||||||
// mod ignore;
|
mod ignore;
|
||||||
mod repository;
|
mod repository;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user