aboutsummaryrefslogtreecommitdiff
path: root/bin/src/dirs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bin/src/dirs.rs')
-rw-r--r--bin/src/dirs.rs99
1 files changed, 99 insertions, 0 deletions
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 @@
1use std::{
2 fs,
3 io::{self, Error, ErrorKind},
4 path::{Path, PathBuf},
5};
6
7use crate::dirs;
8
9use ignore::{
10 gitignore::{Gitignore, GitignoreBuilder},
11 Error as IgnoreError, Match,
12};
13
14#[derive(Debug)]
15pub struct Walker {
16 dirs: Vec<PathBuf>,
17 files: Vec<PathBuf>,
18 ignore: Gitignore,
19}
20
21impl Walker {
22 pub fn new<P: AsRef<Path>>(target: P, ignore: Gitignore) -> io::Result<Self> {
23 let target = target.as_ref().to_path_buf();
24 if !target.exists() {
25 Err(Error::new(
26 ErrorKind::NotFound,
27 format!("file not found: {}", target.display()),
28 ))
29 } else if target.is_dir() {
30 Ok(Self {
31 dirs: vec![target],
32 files: vec![],
33 ignore,
34 })
35 } else {
36 Ok(Self {
37 dirs: vec![],
38 files: vec![target],
39 ignore,
40 })
41 }
42 }
43}
44
45impl Iterator for Walker {
46 type Item = PathBuf;
47 fn next(&mut self) -> Option<Self::Item> {
48 if let Some(dir) = self.dirs.pop() {
49 if dir.is_dir() {
50 if let Match::None | Match::Whitelist(_) = self.ignore.matched(&dir, true) {
51 for entry in fs::read_dir(&dir).ok()? {
52 let entry = entry.ok()?;
53 let path = entry.path();
54 if path.is_dir() {
55 self.dirs.push(path);
56 } else if path.is_file() {
57 self.files.push(path);
58 }
59 }
60 }
61 }
62 }
63 self.files.pop()
64 }
65}
66
67pub fn build_ignore_set<P: AsRef<Path>>(
68 ignore: &[String],
69 target: P,
70 unrestricted: bool,
71) -> Result<Gitignore, IgnoreError> {
72 let gitignore_path = target.as_ref().join(".gitignore");
73
74 // Looks like GitignoreBuilder::new does not source globs
75 // within gitignore_path by default, we have to enforce that
76 // using GitignoreBuilder::add. Probably a bug in the ignore
77 // crate?
78 let mut gitignore = GitignoreBuilder::new(&gitignore_path);
79
80 // if we are to "restrict" aka "respect" .gitignore, then
81 // add globs from gitignore path as well
82 if !unrestricted {
83 gitignore.add(&gitignore_path);
84 }
85
86 for i in ignore {
87 gitignore.add_line(None, i.as_str())?;
88 }
89
90 gitignore.build()
91}
92
93pub fn walk_nix_files<P: AsRef<Path>>(
94 ignore: Gitignore,
95 target: P,
96) -> Result<impl Iterator<Item = PathBuf>, io::Error> {
97 let walker = dirs::Walker::new(target, ignore)?;
98 Ok(walker.filter(|path: &PathBuf| matches!(path.extension(), Some(e) if e == "nix")))
99}