Skip to content

Commit 3b45c6f

Browse files
committed
refactor(filter): Pull out parser mod
1 parent 57d938c commit 3b45c6f

File tree

2 files changed

+264
-252
lines changed

2 files changed

+264
-252
lines changed

crates/env_filter/src/lib.rs

Lines changed: 3 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use std::fmt;
5656
use std::mem;
5757

5858
mod op;
59+
mod parser;
5960

6061
/// A builder for a log filter.
6162
///
@@ -145,7 +146,7 @@ impl Builder {
145146
///
146147
/// [Enabling Logging]: ../index.html#enabling-logging
147148
pub fn parse(&mut self, filters: &str) -> &mut Self {
148-
let (directives, filter) = parse_spec(filters);
149+
let (directives, filter) = parser::parse_spec(filters);
149150

150151
self.filter = filter;
151152

@@ -281,77 +282,6 @@ impl fmt::Debug for Filter {
281282
}
282283
}
283284

284-
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=error/foo")
285-
/// and return a vector with log directives.
286-
fn parse_spec(spec: &str) -> (Vec<Directive>, Option<op::FilterOp>) {
287-
let mut dirs = Vec::new();
288-
289-
let mut parts = spec.split('/');
290-
let mods = parts.next();
291-
let filter = parts.next();
292-
if parts.next().is_some() {
293-
eprintln!(
294-
"warning: invalid logging spec '{}', \
295-
ignoring it (too many '/'s)",
296-
spec
297-
);
298-
return (dirs, None);
299-
}
300-
if let Some(m) = mods {
301-
for s in m.split(',').map(|ss| ss.trim()) {
302-
if s.is_empty() {
303-
continue;
304-
}
305-
let mut parts = s.split('=');
306-
let (log_level, name) =
307-
match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
308-
(Some(part0), None, None) => {
309-
// if the single argument is a log-level string or number,
310-
// treat that as a global fallback
311-
match part0.parse() {
312-
Ok(num) => (num, None),
313-
Err(_) => (LevelFilter::max(), Some(part0)),
314-
}
315-
}
316-
(Some(part0), Some(""), None) => (LevelFilter::max(), Some(part0)),
317-
(Some(part0), Some(part1), None) => match part1.parse() {
318-
Ok(num) => (num, Some(part0)),
319-
_ => {
320-
eprintln!(
321-
"warning: invalid logging spec '{}', \
322-
ignoring it",
323-
part1
324-
);
325-
continue;
326-
}
327-
},
328-
_ => {
329-
eprintln!(
330-
"warning: invalid logging spec '{}', \
331-
ignoring it",
332-
s
333-
);
334-
continue;
335-
}
336-
};
337-
dirs.push(Directive {
338-
name: name.map(|s| s.to_string()),
339-
level: log_level,
340-
});
341-
}
342-
}
343-
344-
let filter = filter.and_then(|filter| match op::FilterOp::new(filter) {
345-
Ok(re) => Some(re),
346-
Err(e) => {
347-
eprintln!("warning: invalid regex filter - {}", e);
348-
None
349-
}
350-
});
351-
352-
(dirs, filter)
353-
}
354-
355285
// Check whether a level and target are enabled by the set of directives.
356286
fn enabled(directives: &[Directive], level: Level, target: &str) -> bool {
357287
// Search for the longest match, the vector is assumed to be pre-sorted.
@@ -368,7 +298,7 @@ fn enabled(directives: &[Directive], level: Level, target: &str) -> bool {
368298
mod tests {
369299
use log::{Level, LevelFilter};
370300

371-
use super::{enabled, parse_spec, Builder, Directive, Filter};
301+
use super::{enabled, Builder, Directive, Filter};
372302

373303
fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
374304
let mut logger = Builder::new().build();
@@ -680,183 +610,4 @@ mod tests {
680610
assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
681611
assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
682612
}
683-
684-
#[test]
685-
fn parse_spec_valid() {
686-
let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug");
687-
assert_eq!(dirs.len(), 3);
688-
assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
689-
assert_eq!(dirs[0].level, LevelFilter::Error);
690-
691-
assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
692-
assert_eq!(dirs[1].level, LevelFilter::max());
693-
694-
assert_eq!(dirs[2].name, Some("crate2".to_string()));
695-
assert_eq!(dirs[2].level, LevelFilter::Debug);
696-
assert!(filter.is_none());
697-
}
698-
699-
#[test]
700-
fn parse_spec_invalid_crate() {
701-
// test parse_spec with multiple = in specification
702-
let (dirs, filter) = parse_spec("crate1::mod1=warn=info,crate2=debug");
703-
assert_eq!(dirs.len(), 1);
704-
assert_eq!(dirs[0].name, Some("crate2".to_string()));
705-
assert_eq!(dirs[0].level, LevelFilter::Debug);
706-
assert!(filter.is_none());
707-
}
708-
709-
#[test]
710-
fn parse_spec_invalid_level() {
711-
// test parse_spec with 'noNumber' as log level
712-
let (dirs, filter) = parse_spec("crate1::mod1=noNumber,crate2=debug");
713-
assert_eq!(dirs.len(), 1);
714-
assert_eq!(dirs[0].name, Some("crate2".to_string()));
715-
assert_eq!(dirs[0].level, LevelFilter::Debug);
716-
assert!(filter.is_none());
717-
}
718-
719-
#[test]
720-
fn parse_spec_string_level() {
721-
// test parse_spec with 'warn' as log level
722-
let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=warn");
723-
assert_eq!(dirs.len(), 1);
724-
assert_eq!(dirs[0].name, Some("crate2".to_string()));
725-
assert_eq!(dirs[0].level, LevelFilter::Warn);
726-
assert!(filter.is_none());
727-
}
728-
729-
#[test]
730-
fn parse_spec_empty_level() {
731-
// test parse_spec with '' as log level
732-
let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=");
733-
assert_eq!(dirs.len(), 1);
734-
assert_eq!(dirs[0].name, Some("crate2".to_string()));
735-
assert_eq!(dirs[0].level, LevelFilter::max());
736-
assert!(filter.is_none());
737-
}
738-
739-
#[test]
740-
fn parse_spec_empty_level_isolated() {
741-
// test parse_spec with "" as log level (and the entire spec str)
742-
let (dirs, filter) = parse_spec(""); // should be ignored
743-
assert_eq!(dirs.len(), 0);
744-
assert!(filter.is_none());
745-
}
746-
747-
#[test]
748-
fn parse_spec_blank_level_isolated() {
749-
// test parse_spec with a white-space-only string specified as the log
750-
// level (and the entire spec str)
751-
let (dirs, filter) = parse_spec(" "); // should be ignored
752-
assert_eq!(dirs.len(), 0);
753-
assert!(filter.is_none());
754-
}
755-
756-
#[test]
757-
fn parse_spec_blank_level_isolated_comma_only() {
758-
// The spec should contain zero or more comma-separated string slices,
759-
// so a comma-only string should be interpreted as two empty strings
760-
// (which should both be treated as invalid, so ignored).
761-
let (dirs, filter) = parse_spec(","); // should be ignored
762-
assert_eq!(dirs.len(), 0);
763-
assert!(filter.is_none());
764-
}
765-
766-
#[test]
767-
fn parse_spec_blank_level_isolated_comma_blank() {
768-
// The spec should contain zero or more comma-separated string slices,
769-
// so this bogus spec should be interpreted as containing one empty
770-
// string and one blank string. Both should both be treated as
771-
// invalid, so ignored.
772-
let (dirs, filter) = parse_spec(", "); // should be ignored
773-
assert_eq!(dirs.len(), 0);
774-
assert!(filter.is_none());
775-
}
776-
777-
#[test]
778-
fn parse_spec_blank_level_isolated_blank_comma() {
779-
// The spec should contain zero or more comma-separated string slices,
780-
// so this bogus spec should be interpreted as containing one blank
781-
// string and one empty string. Both should both be treated as
782-
// invalid, so ignored.
783-
let (dirs, filter) = parse_spec(" ,"); // should be ignored
784-
assert_eq!(dirs.len(), 0);
785-
assert!(filter.is_none());
786-
}
787-
788-
#[test]
789-
fn parse_spec_global() {
790-
// test parse_spec with no crate
791-
let (dirs, filter) = parse_spec("warn,crate2=debug");
792-
assert_eq!(dirs.len(), 2);
793-
assert_eq!(dirs[0].name, None);
794-
assert_eq!(dirs[0].level, LevelFilter::Warn);
795-
assert_eq!(dirs[1].name, Some("crate2".to_string()));
796-
assert_eq!(dirs[1].level, LevelFilter::Debug);
797-
assert!(filter.is_none());
798-
}
799-
800-
#[test]
801-
fn parse_spec_global_bare_warn_lc() {
802-
// test parse_spec with no crate, in isolation, all lowercase
803-
let (dirs, filter) = parse_spec("warn");
804-
assert_eq!(dirs.len(), 1);
805-
assert_eq!(dirs[0].name, None);
806-
assert_eq!(dirs[0].level, LevelFilter::Warn);
807-
assert!(filter.is_none());
808-
}
809-
810-
#[test]
811-
fn parse_spec_global_bare_warn_uc() {
812-
// test parse_spec with no crate, in isolation, all uppercase
813-
let (dirs, filter) = parse_spec("WARN");
814-
assert_eq!(dirs.len(), 1);
815-
assert_eq!(dirs[0].name, None);
816-
assert_eq!(dirs[0].level, LevelFilter::Warn);
817-
assert!(filter.is_none());
818-
}
819-
820-
#[test]
821-
fn parse_spec_global_bare_warn_mixed() {
822-
// test parse_spec with no crate, in isolation, mixed case
823-
let (dirs, filter) = parse_spec("wArN");
824-
assert_eq!(dirs.len(), 1);
825-
assert_eq!(dirs[0].name, None);
826-
assert_eq!(dirs[0].level, LevelFilter::Warn);
827-
assert!(filter.is_none());
828-
}
829-
830-
#[test]
831-
fn parse_spec_valid_filter() {
832-
let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc");
833-
assert_eq!(dirs.len(), 3);
834-
assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
835-
assert_eq!(dirs[0].level, LevelFilter::Error);
836-
837-
assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
838-
assert_eq!(dirs[1].level, LevelFilter::max());
839-
840-
assert_eq!(dirs[2].name, Some("crate2".to_string()));
841-
assert_eq!(dirs[2].level, LevelFilter::Debug);
842-
assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
843-
}
844-
845-
#[test]
846-
fn parse_spec_invalid_crate_filter() {
847-
let (dirs, filter) = parse_spec("crate1::mod1=error=warn,crate2=debug/a.c");
848-
assert_eq!(dirs.len(), 1);
849-
assert_eq!(dirs[0].name, Some("crate2".to_string()));
850-
assert_eq!(dirs[0].level, LevelFilter::Debug);
851-
assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
852-
}
853-
854-
#[test]
855-
fn parse_spec_empty_with_filter() {
856-
let (dirs, filter) = parse_spec("crate1/a*c");
857-
assert_eq!(dirs.len(), 1);
858-
assert_eq!(dirs[0].name, Some("crate1".to_string()));
859-
assert_eq!(dirs[0].level, LevelFilter::max());
860-
assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
861-
}
862613
}

0 commit comments

Comments
 (0)