aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs102
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,