summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2018-10-01 17:24:50 +0300
committerLars Wirzenius <liw@liw.fi>2018-10-01 17:24:50 +0300
commit72af75c035e6ae459914654c654243b435ace255 (patch)
treee7c6193fd63981a4e68022440c24c2fe0a66fdbb
parent21ec762dd8680a924cec7fec7197fffb3fa92fa7 (diff)
downloadsummainrs-72af75c035e6ae459914654c654243b435ace255.tar.gz
Change: split out fswaslking to its own module
-rw-r--r--src/fswalk.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/fswalk.rs b/src/fswalk.rs
new file mode 100644
index 0000000..ac95540
--- /dev/null
+++ b/src/fswalk.rs
@@ -0,0 +1,117 @@
+use std::io;
+use std::path::PathBuf;
+use std::cmp::Ordering;
+
+// A filesystem entry: directory, file, symlink, etc
+#[derive(Debug)]
+pub struct Entry {
+ path: PathBuf,
+}
+
+impl Entry {
+ fn new(path: &PathBuf) -> Entry {
+ Entry {
+ path: path.clone(),
+ }
+ }
+
+ pub fn path(&self) -> String {
+ self.path.to_string_lossy().to_string()
+ }
+}
+
+impl Eq for Entry {}
+
+impl PartialEq for Entry {
+ fn eq(&self, other: &Entry) -> bool {
+ self.path == other.path
+ }
+}
+
+impl Ord for Entry {
+ fn cmp(&self, other: &Entry) -> Ordering {
+ self.path.cmp(&other.path)
+ }
+}
+
+impl PartialOrd for Entry {
+ fn partial_cmp(&self, other: &Entry) -> Option<Ordering> {
+ Some(self.path.cmp(&other.path))
+ }
+}
+
+// Keep two stacks of Entry values, sorted in ascending order. The
+// first stack has non-directories. When we iterate, we return a
+// directory, then of its non-dirs, then recurse each of its subdirs.
+#[derive(Debug)]
+pub struct DirTree {
+ entries: Vec<Entry>,
+ dirs: Vec<Entry>,
+}
+
+impl DirTree {
+ pub fn new(path: &str) -> DirTree {
+ let mut dt = DirTree::empty();
+ dt.add_dir(&PathBuf::from(path));
+ dt
+ }
+
+ fn empty() -> DirTree {
+ DirTree {
+ entries: Vec::new(),
+ dirs: Vec::new(),
+ }
+ }
+
+ fn add_dir(&mut self, path: &PathBuf) {
+ let entry = Entry::new(path);
+ self.dirs.push(entry);
+ }
+
+ fn add_entries(&mut self, path: &PathBuf) -> io::Result<()> {
+ let mut entries = Vec::new();
+ let mut dirs = Vec::new();
+ for dir_entry in path.read_dir()? {
+ let dir_entry = dir_entry?;
+ let metadata = dir_entry.metadata()?;
+ let entry = Entry::new(&dir_entry.path());
+ if metadata.is_dir() {
+ dirs.push(entry);
+ } else {
+ entries.push(entry);
+ }
+ }
+
+ entries.sort();
+ entries.reverse();
+ for e in entries {
+ self.entries.push(e);
+ }
+
+ dirs.sort();
+ dirs.reverse();
+ for e in dirs {
+ self.dirs.push(e);
+ }
+
+ Ok(())
+ }
+}
+
+impl Iterator for DirTree {
+ type Item = Entry;
+
+ fn next(&mut self) -> Option<Entry> {
+ if let Some(e) = self.entries.pop() {
+ Some(e)
+ } else if let Some(e) = self.dirs.pop() {
+ if let Ok(_) = self.add_entries(&e.path) {
+ // We ignore any errors from adding entries. Boo. Not
+ // sure how I'd propagate errors, from a next method.
+ }
+ Some(e)
+ } else {
+ None
+ }
+ }
+}