From 4a3e7137334601828f56a3ee614f01d84bada4ce Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 12 Jun 2020 15:55:19 +0200 Subject: implement -after/-before in terms of -time It makes sense to unify this implementation to avoid code duplication and bugs that might be hidden. -after and -before can stay for now, as shortcuts for -time < and -time >, the same way we have other shortcuts as well. --- src/fexpr/grammar.lalrpop | 8 ++++-- src/filters/log.rs | 65 +++++------------------------------------------ src/filters/values.rs | 22 ++++++++++++++-- 3 files changed, 32 insertions(+), 63 deletions(-) diff --git a/src/fexpr/grammar.lalrpop b/src/fexpr/grammar.lalrpop index 700481c..092407e 100644 --- a/src/fexpr/grammar.lalrpop +++ b/src/fexpr/grammar.lalrpop @@ -52,8 +52,12 @@ LogPredicate: Box = { "-outcome" > => filters::log::outcome(<>), "-weekday" > => filters::log::weekday(<>), - "-before" => filters::log::before(<>), - "-after" => filters::log::after(<>), + "-before" => filters::values::comparison( + filters::values::time(), filters::values::CompOp::Less, filters::values::constant(<>) + ), + "-after" => filters::values::comparison( + filters::values::time(), filters::values::CompOp::Greater, filters::values::constant(<>) + ), "-log-before" => filters::log::log_before(<>), "-log-after" => filters::log::log_after(<>), diff --git a/src/filters/log.rs b/src/filters/log.rs index 9ca7d3c..bde02e5 100644 --- a/src/filters/log.rs +++ b/src/filters/log.rs @@ -7,17 +7,12 @@ use super::{ Filter, Inclusion, }; -use std::{collections::HashSet, ffi::OsStr}; +use std::collections::HashSet; use evtclib::Boss; -use chrono::{DateTime, Datelike, Local, TimeZone, Utc, Weekday}; +use chrono::{DateTime, Datelike, Utc, Weekday}; use num_traits::FromPrimitive as _; -use once_cell::sync::Lazy; -use regex::Regex; - -/// The regular expression used to extract datetimes from filenames. -static DATE_REGEX: Lazy = Lazy::new(|| Regex::new(r"\d{8}-\d{6}").unwrap()); /// Filter trait used for filters that operate on complete logs. pub trait LogFilter = Filter; @@ -91,23 +86,9 @@ pub fn weekday(weekdays: HashSet) -> Box { } #[derive(Debug, Clone)] -struct TimeFilter(Option>, Option>, bool); +struct TimeFilter(Option>, Option>); impl Filter for TimeFilter { - fn filter_early(&self, early_log: &EarlyLogResult) -> Inclusion { - // Ignore the filename heuristic if the user wishes so. - if !self.2 { - return Inclusion::Unknown; - } - early_log - .log_file - .file_name() - .and_then(datetime_from_filename) - .map(|d| time_is_between(d, self.0, self.1)) - .map(Into::into) - .unwrap_or(Inclusion::Unknown) - } - fn filter(&self, log: &LogResult) -> bool { time_is_between(log.time, self.0, self.1) } @@ -133,46 +114,12 @@ fn time_is_between( after_ok && before_ok } -/// Try to extract the log time from the filename. -/// -/// This expects the filename to have the datetime in the pattern `YYYYmmdd-HHMMSS` somewhere in -/// it. -pub(crate) fn datetime_from_filename(name: &OsStr) -> Option> { - let date_match = DATE_REGEX.find(name.to_str()?)?; - let local_time = Local - .datetime_from_str(date_match.as_str(), "%Y%m%d-%H%M%S") - .ok()?; - Some(local_time.with_timezone(&Utc)) -} - -/// A `LogFilter` that only accepts logs in the given time frame. -/// -/// If a bound is not given, -Infinity is assumed for the lower bound, and Infinity for the upper -/// bound. -pub fn time(lower: Option>, upper: Option>) -> Box { - Box::new(TimeFilter(lower, upper, true)) -} - -/// A `LogFilter` that only accepts logs after the given date. -/// -/// Also see [`time`][time] and [`before`][before]. -pub fn after(when: DateTime) -> Box { - time(Some(when), None) -} - -/// A `LogFilter` that only accepts logs before the given date. -/// -/// Also see [`time`][time] and [`after`][after]. -pub fn before(when: DateTime) -> Box { - time(None, Some(when)) -} - /// A `LogFilter` that only accepts logs in the given time frame. /// -/// Compared to [`time`][time], this filter ignores the file name. This can result in more accurate -/// results if you renamed logs, but if also leads to a worse runtime. +/// Compared to [`-time`][super::values::time], this filter ignores the file name. This can result +/// in more accurate results if you renamed logs, but if also leads to a worse runtime. pub fn log_time(lower: Option>, upper: Option>) -> Box { - Box::new(TimeFilter(lower, upper, false)) + Box::new(TimeFilter(lower, upper)) } /// Like [`after`][after], but ignores the file name for date calculations. diff --git a/src/filters/values.rs b/src/filters/values.rs index df5b805..a523dad 100644 --- a/src/filters/values.rs +++ b/src/filters/values.rs @@ -14,15 +14,21 @@ use std::{ cmp::Ordering, convert::TryFrom, + ffi::OsStr, fmt::{self, Debug}, }; -use chrono::{DateTime, Duration, Utc}; +use chrono::{DateTime, Duration, Local, TimeZone, Utc}; use evtclib::Agent; +use once_cell::sync::Lazy; +use regex::Regex; use super::{log::LogFilter, player::PlayerFilter, Filter, Inclusion}; use crate::{EarlyLogResult, LogResult}; +/// The regular expression used to extract datetimes from filenames. +static DATE_REGEX: Lazy = Lazy::new(|| Regex::new(r"\d{8}-\d{6}").unwrap()); + /// A producer for a given value. /// /// A producer is something that produces a value of a certain type from a log, which can then be @@ -167,7 +173,7 @@ impl Producer for TimeProducer { early_log .log_file .file_name() - .and_then(super::log::datetime_from_filename) + .and_then(datetime_from_filename) } fn produce(&self, log: &LogResult) -> Self::Output { @@ -175,6 +181,18 @@ impl Producer for TimeProducer { } } +/// Try to extract the log time from the filename. +/// +/// This expects the filename to have the datetime in the pattern `YYYYmmdd-HHMMSS` somewhere in +/// it. +fn datetime_from_filename(name: &OsStr) -> Option> { + let date_match = DATE_REGEX.find(name.to_str()?)?; + let local_time = Local + .datetime_from_str(date_match.as_str(), "%Y%m%d-%H%M%S") + .ok()?; + Some(local_time.with_timezone(&Utc)) +} + /// A producer that produces the time at which a log was created. pub fn time() -> Box>> { Box::new(TimeProducer) -- cgit v1.2.3