diff options
Diffstat (limited to 'src')
| -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, | 
