diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 114 |
1 files changed, 104 insertions, 10 deletions
diff --git a/src/main.rs b/src/main.rs index 0dc9899..0d560e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,28 +1,110 @@ use std::{ - fs::Metadata, + fs::{File, Metadata}, + io::{BufRead, BufReader}, time::{Duration, SystemTime}, }; use camino::{Utf8Path, Utf8PathBuf}; +use getopts::Options; + +struct Context { + root: Utf8PathBuf, + ignores: Vec<String>, +} + +impl Context { + pub fn new(root: Utf8PathBuf) -> Self { + Self { + root, + ignores: vec![], + } + } + + pub fn ignore_file(&mut self, ignore_path: Utf8PathBuf) { + let file = File::open(ignore_path).unwrap(); + let mut bufread = BufReader::new(file); + + let mut line = String::new(); + loop { + if bufread.read_line(&mut line).unwrap() == 0 { + break; + } + + if line.starts_with("\\#") || line.starts_with("/") { + self.ignores.push(String::from((&line[1..]).trim())); + } else if line.starts_with("#") || line.is_empty() || line.trim().is_empty() { + () + } else { + self.ignores.push(line.trim().to_owned()); + } + + line.clear(); + } + } + + pub fn is_file_ignored<P: AsRef<Utf8Path>>(&self, path: P) -> bool { + match path.as_ref().strip_prefix(&self.root) { + Ok(rel) => { + for ignore in &self.ignores { + if rel.starts_with(ignore) { + return true; + } + } + + false + } + Err(_) => false, + } + } +} fn main() { - // currently only accepts one argument, the path to the directory it will - // recurse through and make the csv for. - // spits the csv on stdout + let mut opts = Options::new(); + #[rustfmt::skip] + opts.optopt("", "ignore", "file of paths to ignore, one per line", "PATH"); + opts.optflag("h", "help", "print this help thing"); + + let matches = match opts.parse(std::env::args()) { + Ok(m) => m, + Err(e) => { + eprintln!("{e}"); + return; + } + }; + + if matches.opt_present("h") { + println!("{}", opts.usage("Usage: whenwasit [options] PATH")); + return; + } - let path: Utf8PathBuf = std::env::args().nth(1).unwrap().parse().unwrap(); - process(&path, &path) + let root = match matches.free.get(1) { + None => { + println!("expected path"); + println!("{}", opts.usage("Usage: whenwasit [options] PATH")); + return; + } + Some(p) => Utf8PathBuf::from(p), + }; + + let mut context = Context::new(root); + + if let Some(ignore) = matches.opt_str("ignore") { + let ignore = Utf8PathBuf::from(ignore); + context.ignore_file(ignore); + } + + process(&context, &context.root) } /// Loop through the provided directory printing CSV rows. The `root_path` is /// used to make printed paths relative to it. /// /// Does two passes: First pass prints files. Second pass recurs, printing directories. -fn process(root_path: &Utf8Path, path: &Utf8Path) { +fn process(ctx: &Context, path: &Utf8Path) { //TODO: do not panic, please let this_meta = std::fs::metadata(&path).unwrap(); let this_times = Times::metadata(&this_meta); - row(root_path, &path, &this_times); + row(&ctx.root, &path, &this_times); for entry in path.read_dir_utf8().unwrap() { let entry = entry.unwrap(); @@ -30,9 +112,14 @@ fn process(root_path: &Utf8Path, path: &Utf8Path) { match entry.file_type() { Err(_) => panic!(), Ok(ft) if ft.is_file() => { + let path = entry.path(); + if ctx.is_file_ignored(path) { + continue; + } + let meta = entry.metadata().unwrap(); let times = Times::metadata(&meta); - row(root_path, entry.path(), ×) + row(&ctx.root, path, ×) } Ok(_) => {} } @@ -43,7 +130,14 @@ fn process(root_path: &Utf8Path, path: &Utf8Path) { match entry.file_type() { Err(_) => panic!(), - Ok(ft) if ft.is_dir() => process(root_path, entry.path()), + Ok(ft) if ft.is_dir() => { + let path = entry.path(); + if ctx.is_file_ignored(path) { + continue; + } + + process(ctx, entry.path()) + } Ok(_) => {} } } |