diff options
author | Lars Wirzenius <liw@liw.fi> | 2018-09-15 20:44:51 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2018-09-15 20:44:51 +0300 |
commit | 70f23e9a741a7efcc2105e95d0278d6838d52b0a (patch) | |
tree | 60e50c3b796e92c511e13c86bd37aabff3a86a42 | |
download | fswalk-70f23e9a741a7efcc2105e95d0278d6838d52b0a.tar.gz |
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | src/main.rs | 133 |
4 files changed, 145 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..16188b9 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "fswalk" +version = "0.1.0" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6c26389 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "fswalk" +version = "0.1.0" +authors = ["Lars Wirzenius <liw@liw.fi>"] + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9dfa59c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,133 @@ +use std::env; +use std::path::PathBuf; +use std::io; +use std::cmp::Ordering; + +// Command line args are names of dirs, recursively list all files and +// dirs them +fn main() -> io::Result<()> { + for dirname in env::args().skip(1) { + let tree = DirTree::new(&dirname); + for entry in tree { + println!("{}", entry.path()); + } + } + Ok(()) +} + + +// A filesystem entry: directory, file, symlink, etc +#[derive(Debug)] +struct Entry { + path: PathBuf, +} + +impl Entry { + fn new(path: &PathBuf) -> Entry { + Entry { + path: path.clone(), + } + } + + 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)] +struct DirTree { + entries: Vec<Entry>, + dirs: Vec<Entry>, +} + + +impl DirTree { + fn empty() -> DirTree { + DirTree { + entries: Vec::new(), + dirs: Vec::new(), + } + } + + fn new(path: &str) -> DirTree { + let mut dt = DirTree::empty(); + dt.add_dir(&PathBuf::from(path)); + dt + } + + 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 + } + } +} |