1use anyhow::Result;
2use std::{
3 fs::File,
4 io::{Read, Write},
5};
6use toml_edit::{value, Document};
7
8use crate::git_interop::get_head_revision;
9
10pub fn write_config(conf: &str) {
12 let mut f = File::create(".gitperfconfig").expect("open file for writing failed");
13 f.write_all(conf.as_bytes()).expect("failed to write");
14}
15
16pub fn read_config() -> Option<String> {
17 read_config_from_file(".gitperfconfig")
18}
19
20fn read_config_from_file(file: &str) -> Option<String> {
23 let mut conf_str = String::new();
24 File::open(file).ok()?.read_to_string(&mut conf_str).ok()?;
25 Some(conf_str)
26}
27
28pub fn determine_epoch_from_config(measurement: &str) -> Option<u32> {
29 let conf = read_config()?;
31 determine_epoch(measurement, &conf)
32}
33
34fn determine_epoch(measurement: &str, conf_str: &str) -> Option<u32> {
35 let config = conf_str
37 .parse::<Document>()
38 .expect("Failed to parse config");
39
40 let get_epoch = |section: &str| {
41 let s = config
42 .get("measurement")?
43 .get(section)?
44 .get("epoch")?
45 .as_str()?;
46 u32::from_str_radix(s, 16).ok()
47 };
48
49 get_epoch(measurement).or_else(|| get_epoch("*"))
50}
51
52pub fn bump_epoch_in_conf(measurement: &str, conf_str: &mut String) -> Result<()> {
53 let mut conf = conf_str
54 .parse::<Document>()
55 .expect("failed to parse config");
56
57 let head_revision = get_head_revision()?;
58 conf["measurement"][measurement]["epoch"] = value(&head_revision[0..8]);
60 *conf_str = conf.to_string();
61
62 Ok(())
63}
64
65pub fn bump_epoch(measurement: &str) -> Result<()> {
67 let mut conf_str = read_config().unwrap_or_default();
68 bump_epoch_in_conf(measurement, &mut conf_str)?;
69 write_config(&conf_str);
70 Ok(())
71}
72
73#[cfg(test)]
74mod test {
75 use super::*;
76
77 #[test]
78 fn test_read_epochs() {
79 let configfile = r#"[measurement."something"]
81#My comment
82epoch="34567898"
83
84[measurement."somethingelse"]
85epoch="a3dead"
86
87[measurement."*"]
88# General performance regression
89epoch="12344555"
90"#;
91
92 let epoch = determine_epoch("something", configfile);
93 assert_eq!(epoch, Some(0x34567898));
94
95 let epoch = determine_epoch("somethingelse", configfile);
96 assert_eq!(epoch, Some(0xa3dead));
97
98 let epoch = determine_epoch("unspecified", configfile);
99 assert_eq!(epoch, Some(0x12344555));
100 }
101
102 #[test]
103 fn test_bump_epochs() {
104 let configfile = r#"[measurement."something"]
105#My comment
106epoch = "34567898"
107"#;
108
109 let mut actual = String::from(configfile);
110 bump_epoch_in_conf("something", &mut actual).expect("Failed to bump epoch");
111
112 let expected = format!(
113 r#"[measurement."something"]
114#My comment
115epoch = "{}"
116"#,
117 &get_head_revision().expect("get_head_revision failed")[0..8],
118 );
119
120 assert_eq!(actual, expected);
121 }
122
123 #[test]
124 fn test_bump_new_epoch_and_read_it() {
125 let mut conf = String::new();
126 bump_epoch_in_conf("mymeasurement", &mut conf).expect("Failed to bump epoch");
127 let epoch = determine_epoch("mymeasurement", &conf);
128 assert!(epoch.is_some());
129 }
130
131 #[test]
132 fn test_parsing() {
133 let toml_str = r#"
134 measurement = { test2 = { epoch = "834ae670e2ecd5c87020fde23378b890832d6076" } }
135 "#;
136
137 let doc = toml_str.parse::<Document>().expect("sfdfdf");
138
139 let measurement = "test";
140
141 if let Some(e) = doc
142 .get("measurement")
143 .and_then(|m| m.get(measurement))
144 .and_then(|m| m.get("epoch"))
145 {
146 println!("YAY: {}", e);
147 panic!("stuff");
148 }
149 }
150}