about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2023-08-24 21:45:25 -0500
committergennyble <gen@nyble.dev>2023-08-24 21:45:25 -0500
commit544aae00aa8d589a2b2817373611d21aa70eec0e (patch)
tree7cd78a83c8370284efc1554ceb2fd062bf6fcda0 /src
parent96ba35059a31dcf12f78587ee76bdea7262fe16b (diff)
downloadwhenwasit-544aae00aa8d589a2b2817373611d21aa70eec0e.tar.gz
whenwasit-544aae00aa8d589a2b2817373611d21aa70eec0e.zip
whenwasignore?
Diffstat (limited to 'src')
-rw-r--r--src/main.rs114
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(), &times)
+				row(&ctx.root, path, &times)
 			}
 			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(_) => {}
 		}
 	}