1use std::{
2 fs::{self, ReadDir},
3 path::PathBuf,
4};
5
6use nill::{Nil, NIL};
7
8use crate::common::{error::Result, utils::has_git_dir};
9
10#[derive(Debug, Default)]
11pub struct Options {
12 pub depth: u32,
13}
14
15#[derive(Debug, Default)]
16pub struct WalkDir {
17 pub path: PathBuf,
18 pub opts: Options,
19
20 pub rdirs: Vec<ReadDir>,
21 pub repos: Vec<PathBuf>,
22}
23
24impl WalkDir {
25 pub fn new<P: Into<PathBuf>>(path: P) -> Self {
26 WalkDir { path: path.into(), ..Default::default() }
27 }
28
29 #[inline]
30 fn find_next_dir(&mut self, mut rdir: ReadDir) -> Result<Nil> {
31 while let Some(entry) = rdir.next() {
32 let path = entry?.path();
33
34 if !path.is_dir() {
35 continue;
36 }
37
38 if has_git_dir(&path) {
39 self.repos.push(path);
40 } else {
41 self.rdirs.push(fs::read_dir(path)?);
42 }
43 }
44
45 Ok(NIL)
46 }
47
48 pub fn find_repo_dirs(&mut self) -> Result<&[PathBuf]> {
49 debug_assert_eq!(self.rdirs.len(), 0);
50 debug_assert_eq!(self.repos.len(), 0);
51
52 self.rdirs.push(fs::read_dir(&self.path)?);
53
54 while let Some(rdir) = self.rdirs.pop() {
55 self.find_next_dir(rdir)?;
56 }
57
58 Ok(&self.repos)
59 }
60}