Skip to content

Commit 5864616

Browse files
committed
Add filtering functionality
1 parent 363e372 commit 5864616

File tree

5 files changed

+149
-32
lines changed

5 files changed

+149
-32
lines changed

base/src/event.rs

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,25 +150,83 @@ pub enum Type<'a> {
150150
}
151151

152152
impl<'a> Type<'a> {
153+
pub fn actor(&self) -> Option<&str> {
154+
use self::Type::*;
155+
match self {
156+
&Msg { ref from, .. } => Some(from),
157+
&Action { ref from, .. } => Some(from),
158+
&Join { ref nick, .. } => Some(nick),
159+
&Part { ref nick, .. } => Some(nick),
160+
&Quit { ref nick, .. } => Some(nick),
161+
&Nick { ref old_nick, .. } => Some(old_nick),
162+
&Notice { ref from, .. } => Some(from),
163+
&Kick { ref kicking_nick, .. } => kicking_nick.as_ref().map(|s| &*s as &str),
164+
&TopicChange { ref nick, .. } => nick.as_ref().map(|s| &*s as &str),
165+
&Mode { ref nick, .. } => nick.as_ref().map(|s| &*s as &str),
166+
_ => None,
167+
}
168+
}
169+
153170
pub fn involves(&self, needle: &str) -> bool {
154171
use self::Type::*;
155172
match self {
156-
&Msg { ref from, .. } => from == needle,
157-
&Action { ref from, .. } => from == needle,
173+
&Msg { ref from, ref content, .. } => from == needle || content.contains(needle),
174+
&Action { ref from, ref content, .. } => from == needle || content.contains(needle),
158175
&Join { ref nick, .. } => nick == needle,
159-
&Part { ref nick, .. } => nick == needle,
160-
&Quit { ref nick, .. } => nick == needle,
176+
&Part { ref nick, ref reason, .. } => {
177+
nick == needle || reason.as_ref().map_or(false, |r| r.contains(needle))
178+
}
179+
&Quit { ref nick, ref reason, .. } => {
180+
nick == needle || reason.as_ref().map_or(false, |r| r.contains(needle))
181+
}
161182
&Nick { ref old_nick, ref new_nick, .. } => old_nick == needle || new_nick == needle,
162-
&Notice { ref from, .. } => from == needle,
163-
&Kick { ref kicked_nick, ref kicking_nick, .. } => {
183+
&Notice { ref from, ref content, .. } => from == needle || content.contains(needle),
184+
&Kick { ref kicked_nick, ref kicking_nick, ref kick_message, .. } => {
164185
*kicked_nick == Cow::Borrowed(needle) ||
165-
kicking_nick.as_ref().map_or(false, |k| k.as_ref() == Cow::Borrowed(needle))
186+
kicking_nick.as_ref().map_or(false, |k| k.as_ref() == Cow::Borrowed(needle)) ||
187+
kick_message.as_ref().map_or(false, |k| k.as_ref() == Cow::Borrowed(needle))
188+
}
189+
&TopicChange { ref nick, ref new_topic, .. } => {
190+
nick.as_ref().map_or(false, |k| k.as_ref() == needle) || new_topic.contains(needle)
166191
}
167-
&TopicChange { ref nick, .. } => nick.as_ref().map_or(false, |k| k.as_ref() == needle),
168192
&Mode { ref nick, .. } => {
169193
nick.as_ref().map_or(false, |k| k.as_ref() == Cow::Borrowed(needle))
170194
}
171195
_ => false,
172196
}
173197
}
198+
199+
pub fn type_desc(&self) -> &'static str {
200+
use self::Type::*;
201+
match self {
202+
&Msg { .. } => "message",
203+
&Action { .. } => "action",
204+
&Join { .. } => "join",
205+
&Part { .. } => "part",
206+
&Quit { .. } => "quit",
207+
&Nick { .. } => "nick",
208+
&Notice { .. } => "notice",
209+
&Topic { .. } => "topic",
210+
&TopicChange { .. } => "topic_change",
211+
&Kick { .. } => "kick",
212+
&Mode { .. } => "mode",
213+
&Connect { .. } => "connect",
214+
&Disconnect { .. } => "disconnect",
215+
}
216+
}
217+
218+
pub fn text(&self) -> Option<&str> {
219+
use self::Type::*;
220+
match self {
221+
&Msg { ref content, .. } => Some(content),
222+
&Action { ref content, .. } => Some(content),
223+
&Part { ref reason, .. } => reason.as_ref().map(|s| s as &str),
224+
&Quit { ref reason, .. } => reason.as_ref().map(|s| s as &str),
225+
&Notice { ref content, .. } => Some(content),
226+
&Kick { ref kick_message, .. } => kick_message.as_ref().map(|s| s as &str),
227+
&Topic { ref topic, .. } => Some(topic),
228+
&TopicChange { ref new_topic, .. } => Some(new_topic),
229+
_ => None,
230+
}
231+
}
174232
}

cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ default = ["ilc-format-weechat", "ilc-format-energymech"]
1515
log = "0.3.5"
1616
clap = "2.1.2"
1717
chrono = "0.2.19"
18+
regex = "0.1.55"
1819
serde = "~0.7"
1920
serde_json = "~0.7"
2021
env_logger = "0.3.2"

cli/src/lib.rs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@ extern crate env_logger;
1111
extern crate serde;
1212
extern crate serde_json;
1313
extern crate glob;
14+
extern crate regex;
1415

1516
use ilc_base::{Context, Decode, Encode};
17+
use ilc_ops::convert::{Filter, Operator, Subject};
1618
use ilc_format_weechat::Weechat;
1719
use ilc_format_energymech::Energymech;
1820

19-
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
21+
use clap::{App, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand};
2022

2123
use chrono::{FixedOffset, NaiveDate};
2224

2325
use glob::glob;
2426

27+
use regex::Regex;
28+
2529
use std::str::FromStr;
2630
use std::fs::File;
2731
use std::path::{Path, PathBuf};
@@ -30,6 +34,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Write};
3034
use std::process;
3135
use std::error::Error;
3236

37+
3338
mod chain;
3439
mod stats;
3540

@@ -121,7 +126,32 @@ pub fn main(cli: Cli) {
121126
.setting(AppSettings::AllowLeadingHyphen))
122127
.subcommand(SubCommand::with_name("convert")
123128
.about("Convert from a source to a target format")
124-
.setting(AppSettings::AllowLeadingHyphen))
129+
.setting(AppSettings::AllowLeadingHyphen)
130+
.arg(Arg::with_name("subject")
131+
.takes_value(true)
132+
.requires("operator")
133+
.long("if")
134+
.possible_values(&["nick", "time", "type", "text"]))
135+
.arg(Arg::with_name("op_not").long("not"))
136+
.arg(Arg::with_name("op_exactly")
137+
.takes_value(true)
138+
.long("exactly"))
139+
.arg(Arg::with_name("op_contains")
140+
.takes_value(true)
141+
.long("contains"))
142+
.arg(Arg::with_name("op_greater")
143+
.takes_value(true)
144+
.long("greater"))
145+
.arg(Arg::with_name("op_less").takes_value(true).long("less"))
146+
.arg(Arg::with_name("op_matches")
147+
.takes_value(true)
148+
.long("matches"))
149+
.group(ArgGroup::with_name("operator").args(&["op_exactly",
150+
"op_contains",
151+
"op_equal",
152+
"op_greater",
153+
"op_less",
154+
"op_matches"])))
125155
.subcommand(SubCommand::with_name("stats")
126156
.about("Analyse the activity of users by certain metrics")
127157
.setting(AppSettings::AllowLeadingHyphen))
@@ -157,11 +187,57 @@ pub fn main(cli: Cli) {
157187
}
158188
("convert", Some(args)) => {
159189
let e = Environment(&args);
190+
let subject = match args.value_of("subject") {
191+
Some("nick") => Some(Subject::Nick),
192+
Some("time") => Some(Subject::Time),
193+
Some("type") => Some(Subject::Type),
194+
Some("text") => Some(Subject::Text),
195+
_ => None,
196+
};
197+
198+
let op = {
199+
if args.is_present("operator") {
200+
if let Some(sub) = args.value_of("op_exactly") {
201+
Some(Operator::Exactly(sub.into()))
202+
} else if let Some(sub) = args.value_of("op_contains") {
203+
Some(Operator::Contains(sub.into()))
204+
} else if let Some(sub) = args.value_of("op_matches") {
205+
match Regex::new(sub) {
206+
Ok(regex) => Some(Operator::Matches(regex)),
207+
Err(e) => error(Box::new(e)),
208+
}
209+
} else {
210+
// must be numeric operator if not op_exactly, op_contains, or op_matches
211+
// unwrap is safe because of .is_present("operator") earlier
212+
let num = match args.value_of("operator").unwrap().parse::<i64>() {
213+
Ok(n) => n,
214+
Err(e) => error(Box::new(e)),
215+
};
216+
217+
if args.is_present("op_equal") {
218+
Some(Operator::Equal(num))
219+
} else if args.is_present("op_greater") {
220+
Some(Operator::Greater(num))
221+
} else if args.is_present("op_less") {
222+
Some(Operator::Less(num))
223+
} else {
224+
None
225+
}
226+
}
227+
} else {
228+
None
229+
}
230+
};
231+
232+
let filter = subject.and_then(|s| op.map(|o| Filter(s, o)));
233+
160234
ilc_ops::convert::convert(&e.context(),
161235
&mut e.input(),
162236
&mut *e.decoder(),
163237
&mut *e.output(),
164-
&*e.encoder())
238+
&*e.encoder(),
239+
filter,
240+
args.is_present("op_not"))
165241
}
166242
("stats", Some(args)) => {
167243
let e = Environment(&args);

ops/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ authors = ["Till Höppner <till@hoeppner.ws>"]
1010
[dependencies]
1111
log = "0.3.5"
1212
chrono = "0.2.19"
13+
regex = "0.1.54"
1314
ilc-base = "~0.2"
1415
blist = "0.0.4"
1516
bit-set = "0.3.0"

ops/src/lib.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ extern crate bit_set;
55
extern crate serde;
66
extern crate chrono;
77
extern crate ilc_base;
8+
extern crate regex;
89

910
mod ageset;
1011
pub mod stats;
12+
pub mod convert;
1113

1214
/// No-op log parsing
1315
pub mod parse {
@@ -27,27 +29,6 @@ pub mod parse {
2729
}
2830
}
2931

30-
/// Log format conversion
31-
pub mod convert {
32-
use ilc_base::{self, Context, Decode, Encode};
33-
use std::io::{BufRead, Write};
34-
35-
/// Convert from one format to another, not necessarily different, format. In combination with a
36-
/// timezone offset, this can be used to correct the timestamps.
37-
/// Will return `Err` and abort conversion if the decoder yields `Err` or re-encoding fails.
38-
pub fn convert(ctx: &Context,
39-
input: &mut BufRead,
40-
decoder: &mut Decode,
41-
output: &mut Write,
42-
encoder: &Encode)
43-
-> ilc_base::Result<()> {
44-
for e in decoder.decode(&ctx, input) {
45-
try!(encoder.encode(&ctx, output, &try!(e)));
46-
}
47-
Ok(())
48-
}
49-
}
50-
5132
/// Last-seen of nicks
5233
pub mod seen {
5334
use ilc_base::{self, Context, Decode, Encode, Event};

0 commit comments

Comments
 (0)