1use yaml_rust::{Yaml};
2use yaml;
3use regex::Regex;
4
5#[derive(Debug, PartialEq, Eq)]
7pub struct OS {
8 pub family: String,
9 pub major: Option<String>,
10 pub minor: Option<String>,
11 pub patch: Option<String>,
12 pub patch_minor: Option<String>,
13}
14
15#[derive(Debug)]
16pub struct OSParser {
17 pub regex: Regex,
18 pub family: Option<String>,
19 pub major: Option<String>,
20 pub minor: Option<String>,
21 pub patch: Option<String>,
22 pub patch_minor: Option<String>,
23}
24
25impl OSParser {
26 pub fn from_yaml(y: &Yaml) -> Option<OSParser> {
27 yaml::string_from_map(y, "regex")
28 .map(|r| r.replace(r"\-", r"-"))
29 .map(|r| r.replace(r"\ ", r" "))
30 .map(|r| r.replace(r"\/", r"/"))
31 .and_then(|r| Regex::new(&r[..]).ok())
32 .map(|r| OSParser {
33 regex: r,
34 family: yaml::string_from_map(y, "os_replacement"),
35 major: yaml::string_from_map(y, "os_v1_replacement"),
36 minor: yaml::string_from_map(y, "os_v2_replacement"),
37 patch: yaml::string_from_map(y, "os_v3_replacement"),
38 patch_minor: yaml::string_from_map(y, "os_v4_replacement"),
39 })
40 }
41
42 pub fn parse(&self, agent: String) -> Option<OS> {
43 self.regex.captures(&agent[..]).map(|c| {
44 let family = self.family.clone()
45 .and_then(|f| c.at(1).map(|a| f.replace("$1", a)))
46 .unwrap_or(c.at(1).unwrap_or("Other").to_string());
47 let major = self.major.clone()
48 .and_then(|f| c.at(2).map(|a| f.replace("$2", a)))
49 .or(c.at(2).map(String::from));
50 let minor = self.minor.clone()
51 .and_then(|f| c.at(3).map(|a| f.replace("$3", a)))
52 .or(c.at(3).map(String::from));
53 let patch = self.patch.clone()
54 .and_then(|f| c.at(4).map(|a| f.replace("$4", a)))
55 .or(c.at(4).map(String::from));
56 let patch_minor = self.patch_minor.clone()
57 .and_then(|f| c.at(5).map(|a| f.replace("$5", a)))
58 .or(c.at(5).map(String::from));
59
60 OS {
61 family: family,
62 major: major,
63 minor: minor,
64 patch: patch,
65 patch_minor: patch_minor,
66 }
67 })
68 }
69}