From 21ec762dd8680a924cec7fec7197fffb3fa92fa7 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 1 Oct 2018 17:08:04 +0300 Subject: Add: initial commit --- .gitignore | 2 + Cargo.lock | 4 ++ Cargo.toml | 6 +++ src/main.rs | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs 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..9deae2d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "summainrs" +version = "0.1.0" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..924309c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "summainrs" +version = "0.1.0" +authors = ["Lars Wirzenius "] + +[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 { + 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, + dirs: Vec, +} + + +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 { + 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 + } + } +} -- cgit v1.2.1