possum/
walk.rs

1//! Directory spelunking
2
3use std::fs::{DirEntry as StdDirEntry, FileType};
4
5use super::*;
6
7#[derive(Debug, PartialEq, Eq, Hash)]
8pub struct Entry {
9    pub path: PathBuf,
10    pub entry_type: EntryType,
11}
12
13use EntryType::*;
14
15impl Entry {
16    pub fn file_id(&self) -> Option<FileId> {
17        match self.entry_type {
18            SnapshotValue | ValuesFile => self.path.file_name().expect("file name").try_into().ok(),
19            _ => None,
20        }
21    }
22}
23
24#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
25pub enum EntryType {
26    ManifestFile,
27    SnapshotDir,
28    SnapshotValue,
29    ValuesFile,
30    Unknown,
31}
32
33/// A slightly decoded std::fs::DirEntry
34struct DirEntry {
35    file_name: String,
36    file_type: FileType,
37}
38
39impl TryFrom<&StdDirEntry> for DirEntry {
40    type Error = anyhow::Error;
41
42    fn try_from(value: &StdDirEntry) -> Result<Self, Self::Error> {
43        let file_name = value
44            .file_name()
45            .to_str()
46            .context("file name not str")?
47            .to_owned();
48        Ok(Self {
49            file_name,
50            file_type: value.file_type()?,
51        })
52    }
53}
54
55pub fn walk_dir<P>(dir: P) -> Result<Vec<Entry>>
56where
57    P: AsRef<Path>,
58{
59    let mut ok = vec![];
60    for std_entry in read_dir(dir)? {
61        let std_entry = std_entry?;
62        let entry = DirEntry::try_from(&std_entry)?;
63        let file_name = entry.file_name;
64        let file_type = entry.file_type;
65        use EntryType::*;
66        let entry_type = if file_name.starts_with(MANIFEST_DB_FILE_NAME) && file_type.is_file() {
67            ManifestFile
68        } else if file_name.starts_with(VALUES_FILE_NAME_PREFIX) && file_type.is_file() {
69            ValuesFile
70        } else if file_name.starts_with(SNAPSHOT_DIR_NAME_PREFIX) && file_type.is_dir() {
71            ok.extend(walk_snapshot_dir(std_entry.path())?);
72            SnapshotDir
73        } else {
74            Unknown
75        };
76        ok.push(Entry {
77            entry_type,
78            path: std_entry.path(),
79        });
80    }
81    Ok(ok)
82}
83
84pub(crate) fn walk_snapshot_dir<P>(path: P) -> Result<Vec<Entry>>
85where
86    P: AsRef<Path>,
87{
88    let mut ok = vec![];
89    for std_entry in read_dir(path)? {
90        let std_entry = std_entry?;
91        let entry = DirEntry::try_from(&std_entry)?;
92        let file_name = entry.file_name;
93        let file_type = entry.file_type;
94        use EntryType::*;
95        let entry_type = if file_name.starts_with(VALUES_FILE_NAME_PREFIX) && file_type.is_file() {
96            SnapshotValue
97        } else {
98            Unknown
99        };
100        ok.push(Entry {
101            path: std_entry.path(),
102            entry_type,
103        });
104    }
105    Ok(ok)
106}