From c0487a3b8bb3d9df1e290579bbbd425f7707b5bd Mon Sep 17 00:00:00 2001 From: Akshay Date: Thu, 4 Nov 2021 18:46:03 +0530 Subject: use ignore crate to enforce simpler ignore rules - also respects .gitignore by default - adds new flag `-u` to unrestrict statix --- bin/src/dirs.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 bin/src/dirs.rs (limited to 'bin/src/dirs.rs') diff --git a/bin/src/dirs.rs b/bin/src/dirs.rs new file mode 100644 index 0000000..d3fe612 --- /dev/null +++ b/bin/src/dirs.rs @@ -0,0 +1,99 @@ +use std::{ + fs, + io::{self, Error, ErrorKind}, + path::{Path, PathBuf}, +}; + +use crate::dirs; + +use ignore::{ + gitignore::{Gitignore, GitignoreBuilder}, + Error as IgnoreError, Match, +}; + +#[derive(Debug)] +pub struct Walker { + dirs: Vec, + files: Vec, + ignore: Gitignore, +} + +impl Walker { + pub fn new>(target: P, ignore: Gitignore) -> io::Result { + let target = target.as_ref().to_path_buf(); + if !target.exists() { + Err(Error::new( + ErrorKind::NotFound, + format!("file not found: {}", target.display()), + )) + } else if target.is_dir() { + Ok(Self { + dirs: vec![target], + files: vec![], + ignore, + }) + } else { + Ok(Self { + dirs: vec![], + files: vec![target], + ignore, + }) + } + } +} + +impl Iterator for Walker { + type Item = PathBuf; + fn next(&mut self) -> Option { + if let Some(dir) = self.dirs.pop() { + if dir.is_dir() { + if let Match::None | Match::Whitelist(_) = self.ignore.matched(&dir, true) { + for entry in fs::read_dir(&dir).ok()? { + let entry = entry.ok()?; + let path = entry.path(); + if path.is_dir() { + self.dirs.push(path); + } else if path.is_file() { + self.files.push(path); + } + } + } + } + } + self.files.pop() + } +} + +pub fn build_ignore_set>( + ignore: &[String], + target: P, + unrestricted: bool, +) -> Result { + let gitignore_path = target.as_ref().join(".gitignore"); + + // Looks like GitignoreBuilder::new does not source globs + // within gitignore_path by default, we have to enforce that + // using GitignoreBuilder::add. Probably a bug in the ignore + // crate? + let mut gitignore = GitignoreBuilder::new(&gitignore_path); + + // if we are to "restrict" aka "respect" .gitignore, then + // add globs from gitignore path as well + if !unrestricted { + gitignore.add(&gitignore_path); + } + + for i in ignore { + gitignore.add_line(None, i.as_str())?; + } + + gitignore.build() +} + +pub fn walk_nix_files>( + ignore: Gitignore, + target: P, +) -> Result, io::Error> { + let walker = dirs::Walker::new(target, ignore)?; + Ok(walker.filter(|path: &PathBuf| matches!(path.extension(), Some(e) if e == "nix"))) +} -- cgit v1.2.3