Skip to content

Commit 75610e5

Browse files
committedMar 13, 2021
Refactor code into lib/ and write a test for parser
1 parent c1356be commit 75610e5

File tree

5 files changed

+188
-73
lines changed

5 files changed

+188
-73
lines changed
 

‎Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ authors = ["Pancy <pancy@xerberus.net>"]
55
edition = "2018"
66

77
[dependencies]
8+
anyhow = "1.0"
89
pest = "2.0"
910
pest_derive = "2.0"
1011

‎src/lib/mod.rs

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
pub mod parser;
2+
3+
#[cfg(test)]
4+
mod test {
5+
6+
use super::*;
7+
use parser::{parse, SystemdValue};
8+
use std::env::current_dir;
9+
10+
#[test]
11+
fn test_parse_systemd_str() {
12+
let mut dir = current_dir().unwrap();
13+
dir.push("src");
14+
dir.push("cardano-node.service");
15+
let filepath = dir.to_str().unwrap();
16+
if let Ok(p) = parse(filepath) {
17+
let unit = p.get(&String::from("Unit")).unwrap();
18+
let mut test_pairs = vec![
19+
(
20+
unit.get(&String::from("Description")).unwrap(),
21+
String::from("Cardano Node"),
22+
),
23+
(
24+
unit.get(&String::from("After")).unwrap(),
25+
String::from("network-online.target"),
26+
),
27+
(
28+
unit.get(&String::from("Wants")).unwrap(),
29+
String::from("network-online.target"),
30+
),
31+
];
32+
for tp in test_pairs.into_iter() {
33+
match tp {
34+
(SystemdValue::Str(s), expect) => {
35+
assert_eq!(*s, *expect);
36+
},
37+
_ => assert!(false),
38+
}
39+
}
40+
41+
let srv = p.get(&String::from("Service")).expect("Holy shit");
42+
test_pairs = vec![
43+
(
44+
srv.get(&String::from("Type")).unwrap(),
45+
String::from("simple"),
46+
),
47+
(
48+
srv.get(&String::from("ExecStart")).unwrap(),
49+
String::from("/usr/local/sbin/relay-init.sh"),
50+
),
51+
(
52+
srv.get(&String::from("Restart")).unwrap(),
53+
String::from("on-failure"),
54+
),
55+
(
56+
srv.get(&String::from("RestartSec")).unwrap(),
57+
String::from("3"),
58+
),
59+
(
60+
srv.get(&String::from("KillMode")).unwrap(),
61+
String::from("process"),
62+
),
63+
];
64+
for tp in test_pairs.into_iter() {
65+
match tp {
66+
(SystemdValue::Str(s), expect) => {
67+
assert_eq!(*s, *expect);
68+
},
69+
_ => assert!(false),
70+
}
71+
}
72+
73+
let install = p.get(&String::from("Install")).unwrap();
74+
test_pairs = vec![
75+
(
76+
install.get(&String::from("WantedBy")).unwrap(),
77+
String::from("multi-user.target"),
78+
)
79+
];
80+
for tp in test_pairs.into_iter() {
81+
match tp {
82+
(SystemdValue::Str(s), expect) => {
83+
assert_eq!(*s, *expect);
84+
},
85+
_ => assert!(false),
86+
}
87+
}
88+
} else {
89+
assert!(false);
90+
}
91+
}
92+
}

‎src/lib/parser.rs

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use std::collections::HashMap;
2+
use std::fs;
3+
use pest::Parser;
4+
use anyhow::{Context, Result};
5+
6+
#[derive(Parser)]
7+
#[grammar = "systemd.pest"]
8+
pub struct SystemdParser;
9+
10+
#[derive(Debug, Clone)]
11+
pub enum SystemdValue {
12+
List(Vec<String>),
13+
Str(String),
14+
}
15+
16+
fn pre_process_map(map: &mut HashMap<String, HashMap<String, SystemdValue>>) {
17+
for (_, value) in map.into_iter() {
18+
for (_, v) in value.into_iter() {
19+
if let SystemdValue::List(vs) = v {
20+
if vs.len() == 0 {
21+
let v_ = SystemdValue::Str(String::new());
22+
*v = v_.clone();
23+
} else if vs.len() == 1 {
24+
let v_ = SystemdValue::Str((vs[0]).clone());
25+
*v = v_.clone();
26+
}
27+
}
28+
}
29+
}
30+
}
31+
32+
pub fn parse(name: &str) -> Result<HashMap<String, HashMap<String, SystemdValue>>> {
33+
34+
let unparsed_file = fs::read_to_string(name)
35+
.with_context(|| format!("cannot read file {}", name))?;
36+
37+
let file = SystemdParser::parse(Rule::file, &unparsed_file)
38+
.with_context(|| format!("unsuccessful parse"))?
39+
.next()
40+
.unwrap();
41+
42+
let mut properties: HashMap<String, HashMap<String, SystemdValue>> =
43+
HashMap::new();
44+
45+
let mut current_section_name = String::new();
46+
let mut current_key_name = String::new();
47+
48+
for line in file.into_inner() {
49+
match line.as_rule() {
50+
Rule::section => {
51+
let mut inner_rules = line.into_inner();
52+
// current_section_name = inner_rules.next().unwrap().as_str();
53+
current_section_name = inner_rules.next().unwrap().as_str().to_string();
54+
},
55+
Rule::property => {
56+
let mut inner_rules = line.into_inner();
57+
let section = properties.entry(current_section_name.clone()).or_default();
58+
59+
let name = inner_rules.next().unwrap().as_str().to_string();
60+
let value = inner_rules.next().unwrap().as_str().to_string();
61+
62+
if name == current_key_name {
63+
let entry = section.entry(current_key_name.clone()).or_insert(SystemdValue::List(vec![]));
64+
if let SystemdValue::List(ent) = entry {
65+
ent.push(value);
66+
}
67+
} else {
68+
let entry = section.entry(name.clone()).or_insert(SystemdValue::List(vec![]));
69+
if let SystemdValue::List(ent) = entry {
70+
ent.push(value);
71+
}
72+
current_key_name = name;
73+
}
74+
},
75+
Rule::EOI => (),
76+
_ => unreachable!(),
77+
}
78+
}
79+
80+
pre_process_map(&mut properties);
81+
82+
Ok(properties)
83+
}

‎src/main.rs

+5-73
Original file line numberDiff line numberDiff line change
@@ -2,90 +2,22 @@ extern crate pest;
22
#[macro_use]
33
extern crate pest_derive;
44

5-
use std::collections::HashMap;
6-
use std::{fs, env::current_dir};
7-
use pest::Parser;
8-
9-
#[derive(Parser)]
10-
#[grammar = "systemd.pest"]
11-
pub struct SystemdParser;
12-
13-
#[derive(Debug, Clone)]
14-
pub enum SystemdValue<'a> {
15-
List(Vec<&'a str>),
16-
Str(&'a str),
17-
}
5+
mod lib;
6+
use lib::parser;
7+
use std::env::current_dir;
188

199
fn main() {
2010
let mut dir = current_dir().unwrap();
2111
dir.push("src");
2212
dir.push("cardano-node.service");
2313

2414
let name = dir.to_str().unwrap();
25-
26-
let unparsed_file = fs::read_to_string(name)
27-
.expect("cannot read file");
28-
29-
let file = SystemdParser::parse(Rule::file, &unparsed_file)
30-
.expect("unsuccessful parse")
31-
.next().unwrap();
32-
let mut properties: HashMap<&str, HashMap<&str, SystemdValue<'_>>> =
33-
HashMap::new();
34-
35-
let mut current_section_name = "";
36-
let mut current_key_name = "";
3715

38-
for line in file.into_inner() {
39-
match line.as_rule() {
40-
Rule::section => {
41-
let mut inner_rules = line.into_inner();
42-
current_section_name = inner_rules.next().unwrap().as_str();
43-
},
44-
Rule::property => {
45-
let mut inner_rules = line.into_inner();
46-
let section = properties.entry(current_section_name).or_default();
47-
let name: &str = inner_rules.next().unwrap().as_str();
48-
let value: &str = inner_rules.next().unwrap().as_str();
49-
50-
if name == current_key_name {
51-
let entry = section.entry(&current_key_name).or_insert(SystemdValue::List(vec![]));
52-
if let SystemdValue::List(ent) = entry {
53-
ent.push(value);
54-
}
55-
} else {
56-
let entry = section.entry(&name).or_insert(SystemdValue::List(vec![]));
57-
if let SystemdValue::List(ent) = entry {
58-
ent.push(value);
59-
}
60-
current_key_name = name;
61-
}
62-
},
63-
Rule::EOI => (),
64-
_ => unreachable!(),
65-
}
16+
if let Ok(p) = parser::parse(name) {
17+
println!("{:#?}", p);
6618
}
67-
68-
pre_process_map(&mut properties);
69-
70-
println!("{:#?}", properties);
7119
}
7220

73-
fn pre_process_map(map: &mut HashMap<&str, HashMap<&str, SystemdValue<'_>>>) {
74-
for (_, value) in map.into_iter() {
75-
for (_, v) in value.into_iter() {
76-
if let SystemdValue::List(vs) = v {
77-
if vs.len() == 0 {
78-
let v_ = SystemdValue::Str("");
79-
*v = v_.clone();
80-
} else if vs.len() == 1 {
81-
let v_ = SystemdValue::Str(vs[0]);
82-
*v = v_.clone();
83-
}
84-
}
85-
}
86-
}
87-
// map.clear();
88-
}
8921

9022

9123

0 commit comments

Comments
 (0)
Please sign in to comment.