From 198def6a83b2f6f80f151b5dfb76be4710a135b6 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Fri, 16 Jun 2023 17:20:22 +0200 Subject: [PATCH] start to work on nextsyncignore --- Cargo.lock | 7 ++ Cargo.toml | 1 + src/utils/nextsyncignore.rs | 132 ++++++++++++++++++++++++++++++++++++ src/utils/path.rs | 12 ++++ 4 files changed, 152 insertions(+) create mode 100644 src/utils/nextsyncignore.rs diff --git a/Cargo.lock b/Cargo.lock index 48c5d72..ea03922 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,6 +250,12 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "h2" version = "0.3.19" @@ -523,6 +529,7 @@ dependencies = [ "clap", "colored", "dotenv", + "glob", "lazy_static", "regex", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index 197a05f..6b214ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ colored = "2.0.0" xml-rs = "0.8.0" regex = "1.8.3" lazy_static = "1.4.0" +glob = "0.3.1" diff --git a/src/utils/nextsyncignore.rs b/src/utils/nextsyncignore.rs new file mode 100644 index 0000000..3ca707c --- /dev/null +++ b/src/utils/nextsyncignore.rs @@ -0,0 +1,132 @@ +use crate::utils::{read, path}; +use glob::{Pattern, MatchOptions}; +use regex::Regex; +use std::fs::File; +use std::io::{Cursor, Lines, BufReader, empty, BufRead}; + +fn read_lines() -> Result, ()> { + if let Some(path) = path::nextsyncignore() { + let file = match File::open(path) { + Ok(buffer) => buffer, + Err(_) => return Err(()), + }; + let reader = BufReader::new(file); + let mut lines = vec![]; + for line in reader.lines() { + if let Ok(l) = line { + lines.push(l.clone()); + } else { + return Err(()); + } + } + return Ok(lines); + } + Ok(vec![]) +} + +fn ignore_files(files: &mut Vec) -> bool { + let ignored = false; + let origin_len = files.len(); + if let Some(path) = path::nextsyncignore() { + if let Ok(lines) = read_lines() { + files.retain(|file| ignore_file(file, lines.clone())); + } + } + files.len() != origin_len +} + +pub fn ignore_file(path: &String, lines: Vec) -> bool { + let options = MatchOptions { + case_sensitive: true, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + + let mut ignored = false; + dbg!(path.clone()); + for line in lines { + if line.starts_with("!") { + if !ignored { + continue; + } + let strip_line = line.strip_prefix("!").unwrap(); + dbg!("start with"); + dbg!(strip_line.clone()); + dbg!(path.clone()); + let pattern = Pattern::new(strip_line).expect("Invalid glob pattern"); + if pattern.matches_with(path, options) { + ignored = false; + } + } else if !ignored { + dbg!(line.clone()); + let pattern = Pattern::new(&line).expect("Invalid glob pattern"); + if pattern.matches_with(path, options) { + ignored = true; + } + } + } + ignored +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ignore_files() { + let lines_data = b"*.log\nexclude\n/logs/*\n/build/target/\n**/*.swp\nsecret/\n"; + let cursor = Cursor::new(lines_data); + let reader = BufReader::new(cursor); + let mut lines = vec![]; + for line in reader.lines() { + if let Ok(l) = line { + lines.push(l.clone()); + } + } + + assert_eq!(ignore_file(&String::from("error.log"), lines.clone()), true); + assert_eq!(ignore_file(&String::from("./error.log"), lines.clone()), true); + assert_eq!(ignore_file(&String::from("dir/error.log"), lines.clone()), true); + + assert_eq!(ignore_file(&String::from("exclude"), lines.clone()), true); + assert_eq!(ignore_file(&String::from("dir/exclude"), lines.clone()), false); + + assert_eq!(ignore_file(&String::from("/logs/dir/file2"), lines.clone()), true); + assert_eq!(ignore_file(&String::from("dir/logs/dir/file2"), lines.clone()), false); + + assert_eq!(ignore_file(&String::from("build/target/file1"), lines.clone()), true); + //assert_eq!(ignore_file(&String::from("/build/target/dir/file1"), lines.clone()), true); + //assert_eq!(ignore_file(&String::from("/build"), lines.clone()), false.clone()); + //assert_eq!(ignore_file(&String::from("/build/target"), lines.clone()), true); + //assert_eq!(ignore_file(&String::from("dir/build/target"), lines.clone()), false); + + assert_eq!(ignore_file(&String::from("dir/file.swp"), lines.clone()), true); + assert_eq!(ignore_file(&String::from(".swp"), lines.clone()), true); + + //assert_eq!(ignore_file(&String::from("secret"), lines.clone()), true); + //assert_eq!(ignore_file(&String::from("./dir/secret"), lines.clone()), true); + //assert_eq!(ignore_file(&String::from("./dir/secret/file"), lines.clone()), true); + } + + #[test] + fn test_ignore_files_negation() { + let lines_data = b"*\n!*.log\n!*log.*\n"; + let cursor = Cursor::new(lines_data); + let reader = BufReader::new(cursor); + let mut lines = vec![]; + for line in reader.lines() { + if let Ok(l) = line { + lines.push(l.clone()); + } + } + + assert_eq!(ignore_file(&String::from("file"), lines.clone()), true); + assert_eq!(ignore_file(&String::from("dir/file"), lines.clone()), true); + assert_eq!(ignore_file(&String::from("file.log"), lines.clone()), false); + assert_eq!(ignore_file(&String::from("log.file"), lines.clone()), false); + assert_eq!(ignore_file(&String::from("dir/file.log"), lines.clone()), false); + assert_eq!(ignore_file(&String::from("dir/log.file"), lines.clone()), false); + } +} + + diff --git a/src/utils/path.rs b/src/utils/path.rs index d799164..2acc793 100644 --- a/src/utils/path.rs +++ b/src/utils/path.rs @@ -58,3 +58,15 @@ pub fn objects() -> Option { } None } + +pub fn nextsyncignore() -> Option { + if let Some(mut path) = nextsync_root() { + path.push(".nextsyncignore"); + if path.exists() { + return Some(path); + } else { + return None; + } + } + None +}