diff --git a/src/main.rs b/src/main.rs index 5da67cb..f9d15a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,17 @@ -use std::process::ExitCode; +use std::{path::PathBuf, process::ExitCode}; use clap::Parser; -use crate::matches::Matches; +use crate::{matches::Matches, parser::process_files}; mod matches; mod parser; #[derive(Parser)] struct Cli { pattern: String, - file_path: String, + + #[arg(value_name = "FILES", num_args = 1..)] + file_paths: Vec, } fn main() -> ExitCode { @@ -29,8 +31,9 @@ fn main() -> ExitCode { fn run() -> anyhow::Result { let cli = Cli::parse(); - let lines_iter = parser::read_lines(&cli.file_path)?; - let matches = parser::match_pattern(lines_iter, &cli.pattern, &cli.file_path)?; + // println!("{:?} {}", cli.file_paths, cli.pattern); + + let matches = process_files(&cli.file_paths, &cli.pattern)?; Ok(matches) } diff --git a/src/matches.rs b/src/matches.rs index 0cc950a..f161e89 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -15,6 +15,10 @@ impl Matches { pub fn is_empty(&self) -> bool { self.items.is_empty() } + + pub fn append(&mut self, matches: &mut Self) -> () { + self.items.append(&mut matches.items); + } } impl Display for Match { diff --git a/src/parser.rs b/src/parser.rs index a795e39..6bbd9b3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use std::{ fs::File, io::{BufRead, BufReader}, - path::Path, + path::{Path, PathBuf}, }; use anyhow::Context; @@ -9,22 +9,44 @@ use regex::Regex; use crate::matches::{Match, Matches}; -pub fn read_lines( - file_path: &str, -) -> anyhow::Result>, anyhow::Error> { - if file_path.is_empty() { - return Err(anyhow::anyhow!("File path cannot be empty")); +pub fn process_files( + file_paths: &Vec, + pattern: &str, +) -> anyhow::Result { + let mut matches = Matches { items: vec![], pattern: String::from(pattern) }; + + for file_path in file_paths { + let lines_iter = read_lines(file_path)?; + let mut _matches = match_pattern(lines_iter, pattern, file_path)?; + matches.append(&mut _matches); } + // let lines_iter = read_lines(file_path)?; + // let matches = match_pattern(lines_iter, pattern, file_path)?; + + Ok(matches) +} + +pub fn read_lines( + file_path: &Path, +) -> anyhow::Result>, anyhow::Error> { + match file_path.try_exists() { + Ok(true) => {} + Ok(false) => return Err(anyhow::anyhow!("File path needs to exist")), + Err(e) => eprintln!("Error checking path: {e}"), + } + + let path_string = file_path.to_string_lossy().to_string(); + let file = - File::open(file_path).with_context(|| format!("failed to open file: {file_path}"))?; + File::open(file_path).with_context(|| format!("failed to open file: {path_string}"))?; let reader = BufReader::new(file); Ok(reader.lines()) } -fn get_file_name_from_path(file_path: &str) -> String { - match Path::new(file_path).file_name() { +fn get_file_name_from_path(file_path: &Path) -> String { + match file_path.file_name() { Some(name) => name.to_string_lossy().to_string(), None => String::from("unknown"), } @@ -33,7 +55,7 @@ fn get_file_name_from_path(file_path: &str) -> String { pub fn match_pattern( iter: impl Iterator>, pattern: &str, - file_path: &str, + file_path: &Path, ) -> anyhow::Result { let reg = Regex::new(pattern).with_context(|| format!("invalid regex: {:?}", pattern))?; let mut matches = Vec::new(); @@ -61,11 +83,11 @@ mod tests { #[test] fn test_get_file_name_from_path() { - let path = "/path/to/file.txt"; + let path = Path::new("/path/to/file.txt"); let file_name = get_file_name_from_path(path); assert_eq!(file_name, "file.txt"); - let path = "file.txt"; + let path = Path::new("file.txt"); let file_name = get_file_name_from_path(path); assert_eq!(file_name, "file.txt"); } @@ -75,7 +97,8 @@ mod tests { let input: Vec> = vec![Ok("hola".into()), Ok("no".into()), Ok("hola again".into())]; - let result = match_pattern(input.into_iter(), r"^hola", "/tmp/test.txt").unwrap(); + let result = + match_pattern(input.into_iter(), r"^hola", Path::new("/tmp/test.txt")).unwrap(); assert_eq!(result.items.len(), 2);