proplate_core/fs/
walk.rs

1use std::{
2  fs,
3  io::{Error, ErrorKind},
4  path::{Path, PathBuf},
5};
6
7/// # Example
8///
9/// Let's walk this path: "C:\Users\proplate\samples\exclude_files\ban-node-modules"
10///
11/// For the file ".proplate_aux_utils\.gitkeep", WalkdirPathBuf would look like
12///
13///  r#"C:\Users\proplate\samples\exclude_files\ban-node-modules\.proplate_aux_utils\.gitkeep"#
14///  r#".proplate_aux_utils\.gitkeep"#
15pub type WalkdirPathBuf = (/*abs*/ PathBuf, /*relative*/ PathBuf);
16
17struct WalkDir {
18  skip: Vec<PathBuf>,
19}
20
21impl WalkDir {
22  pub fn new(skip: Option<Vec<PathBuf>>) -> WalkDir {
23    WalkDir {
24      skip: skip.unwrap_or_else(|| Vec::new()),
25    }
26  }
27
28  pub fn walk(&self, path: &Path, dir: Option<PathBuf>) -> std::io::Result<Vec<WalkdirPathBuf>> {
29    if path.is_file() {
30      // TODO: Avoid alloc vec for no use
31      return Ok(vec![self.walk_file(path, &dir.unwrap_or("".into()))]);
32    }
33    let mut dirs: Vec<WalkdirPathBuf> = Vec::new();
34    self.walk_dir(&path, &dir.unwrap_or("".into()), &mut dirs)?;
35
36    Ok(dirs)
37  }
38
39  fn walk_file(&self, path: &Path, dir: &Path) -> WalkdirPathBuf {
40    (path.to_owned(), dir.to_owned())
41  }
42
43  fn walk_dir(
44    &self,
45    path: &Path,
46    dir: &Path,
47    dirs: &mut Vec<WalkdirPathBuf>,
48  ) -> std::io::Result<()> {
49    for entry in fs::read_dir(path)? {
50      let entry = entry?;
51      let path = entry.path();
52
53      if self.skip.contains(&path) {
54        continue;
55      }
56
57      let file_name = path.file_name().ok_or_else(|| {
58        Error::new(
59          ErrorKind::InvalidInput,
60          "File does not have a valid filename",
61        )
62      })?;
63      let dir = dir.join(file_name);
64      dirs.extend(self.walk(&path, Some(dir))?);
65    }
66    Ok(())
67  }
68}
69
70pub fn walk_dir_skip(path: &Path, skip: Vec<PathBuf>) -> std::io::Result<Vec<WalkdirPathBuf>> {
71  let wd = WalkDir::new(Some(skip));
72  let paths = wd.walk(path, None /*dir*/)?;
73  Ok(paths)
74}
75
76pub fn walk_dir(path: &Path) -> std::io::Result<Vec<WalkdirPathBuf>> {
77  let wd = WalkDir::new(None /*skip*/);
78  let paths = wd.walk(path, None /*dir*/)?;
79  Ok(paths)
80}