1use 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
33struct 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}