diff options
author | Daniel <kingdread@gmx.de> | 2020-06-08 00:27:33 +0200 |
---|---|---|
committer | Daniel <kingdread@gmx.de> | 2020-06-08 00:27:33 +0200 |
commit | 120d650b1d7dc9eeabcc287d6d27c564e818834f (patch) | |
tree | d776fc22d032e7821c870d04c067211f5b3f81c9 /src/main.rs | |
parent | 1477e7751c4afddd858596001a9d9c54be5754fb (diff) | |
download | raidgrep-120d650b1d7dc9eeabcc287d6d27c564e818834f.tar.gz raidgrep-120d650b1d7dc9eeabcc287d6d27c564e818834f.tar.bz2 raidgrep-120d650b1d7dc9eeabcc287d6d27c564e818834f.zip |
add --check to check a single file
The --check flag will check the given file and set the exit status
accordingly.
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 102 |
1 files changed, 69 insertions, 33 deletions
diff --git a/src/main.rs b/src/main.rs index 2b2aeb7..96a8539 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,6 +79,15 @@ pub struct Opt { #[structopt(short = "d", long = "dir", default_value = ".", parse(from_os_str))] path: PathBuf, + /// Check the given file only. + #[structopt( + short = "c", + long = "check", + value_name = "file", + conflicts_with = "path" + )] + check: Option<PathBuf>, + /// Only show the name of matching files. #[structopt(short = "l", long = "files-with-matches")] file_name_only: bool, @@ -116,6 +125,30 @@ pub struct Opt { expression: Vec<String>, } +impl Opt { + fn build_filter(&self) -> Result<Box<dyn LogFilter>> { + // As a shortcut, we allow only the regular expression to be given, to retain the behaviour + // before the filter changes. + if self.expression.len() == 1 { + let line = &self.expression[0]; + let maybe_filter = build_filter(line); + if maybe_filter.is_err() && !line.starts_with('-') { + let maybe_regex = Regex::new(line); + if let Ok(rgx) = maybe_regex { + let filter = filters::player::any( + filters::player::account(rgx.clone()) | filters::player::character(rgx), + ); + return Ok(filter); + } + } + return Ok(maybe_filter?); + } + + let expr_string = fexpr::requote(&self.expression); + Ok(build_filter(&expr_string)?) + } +} + /// A log that matches the search criteria. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct LogResult { @@ -302,26 +335,17 @@ fn run() -> Result<i32> { } fn single(opt: &Opt) -> Result<bool> { - // As a shortcut, we allow only the regular expression to be given, to retain the behaviour - // before the filter changes. - if opt.expression.len() == 1 { - let line = &opt.expression[0]; - let maybe_filter = build_filter(line); - if maybe_filter.is_err() && !line.starts_with('-') { - let maybe_regex = Regex::new(line); - if let Ok(rgx) = maybe_regex { - let filter = filters::player::any( - filters::player::account(rgx.clone()) | filters::player::character(rgx), - ); - return grep(opt, &*filter); - } - } - return grep(opt, &*maybe_filter?); + let filter = opt.build_filter()?; + if let Some(ref path) = opt.check { + let is_zip = path + .file_name() + .and_then(|f| f.to_str()) + .map(is_zip_file_name) + .unwrap_or(false); + search_file(path, is_zip, &*filter).map(|r| r.is_some()) + } else { + grep(&opt, &*filter) } - - let expr_string = fexpr::requote(&opt.expression); - let filter = build_filter(&expr_string)?; - grep(&opt, &*filter) } fn repl(opt: &Opt) -> Result<()> { @@ -417,7 +441,7 @@ fn grep(opt: &Opt, filter: &dyn LogFilter) -> Result<bool> { return; } if is_log_file(&entry) { - let search = search_log(&entry, filter); + let search = search_entry(&entry, filter); match search { Ok(None) => (), Ok(Some(result)) => { @@ -438,18 +462,30 @@ fn grep(opt: &Opt, filter: &dyn LogFilter) -> Result<bool> { Ok(found_something.load(Ordering::Relaxed)) } -/// Search the given single log. +fn is_zip_file_name(file_name: &str) -> bool { + file_name.ends_with(".zip") || file_name.ends_with(".zevtc") +} + +/// Search the given directory entry. /// -/// If the log matches, returns `Ok(Some(..))`. -/// If the log doesn't match, returns `Ok(None)`. -/// If there was a fatal error, returns `Err(..)`. -fn search_log(entry: &DirEntry, filter: &dyn LogFilter) -> Result<Option<LogResult>> { - let file_stream = BufReader::new(File::open(entry.path())?); +/// This forwards to [`search_file`][search_file] with the right parameters, and as such has the +/// same return possibilities. +fn search_entry(entry: &DirEntry, filter: &dyn LogFilter) -> Result<Option<LogResult>> { let is_zip = entry .file_name() .to_str() - .map(|n| n.ends_with(".zip") || n.ends_with(".zevtc")) + .map(is_zip_file_name) .unwrap_or(false); + search_file(entry.path(), is_zip, filter) +} + +/// Search the given single log.. +/// +/// If the log matches, returns `Ok(Some(..))`. +/// If the log doesn't match, returns `Ok(None)`. +/// If there was a fatal error, returns `Err(..)`. +fn search_file(path: &Path, is_zip: bool, filter: &dyn LogFilter) -> Result<Option<LogResult>> { + let file_stream = BufReader::new(File::open(path)?); let mut wrapper = if is_zip { ZipWrapper::zipped(file_stream) } else { @@ -459,7 +495,7 @@ fn search_log(entry: &DirEntry, filter: &dyn LogFilter) -> Result<Option<LogResu let partial = evtclib::raw::parser::parse_partial_file(&mut stream)?; let early_log = EarlyLogResult { - log_file: entry.path().to_owned(), + log_file: path.to_owned(), evtc: partial, }; let early_ok = filter.filter_early(&early_log); @@ -474,11 +510,11 @@ fn search_log(entry: &DirEntry, filter: &dyn LogFilter) -> Result<Option<LogResu let log = if let Some(e) = parsed { e } else { - debug!("log file cannot be parsed: {:?}", entry.path()); + debug!("log file cannot be parsed: {:?}", path); return Ok(None); }; - let info = extract_info(entry, &log); + let info = extract_info(path, &log); let take_log = filter.filter(&info); @@ -490,12 +526,12 @@ fn search_log(entry: &DirEntry, filter: &dyn LogFilter) -> Result<Option<LogResu } /// Extract human-readable information from the given log file. -fn extract_info(entry: &DirEntry, log: &Log) -> LogResult { +fn extract_info(path: &Path, log: &Log) -> LogResult { let boss = log.encounter(); if boss.is_none() { debug!( "log file has unknown boss: {:?} (id: {:#x})", - entry.path(), + path, log.encounter_id() ); } @@ -515,7 +551,7 @@ fn extract_info(entry: &DirEntry, log: &Log) -> LogResult { players.sort(); LogResult { - log_file: entry.path().to_path_buf(), + log_file: path.to_path_buf(), time: Utc.timestamp(i64::from(log.local_end_timestamp().unwrap_or(0)), 0), boss, players, |