1use anyhow::Result;
2use std::{
3 fs::File,
4 io::{Read, Write},
5};
6use toml_edit::{value, Document};
7
8use crate::git::git_interop::get_head_revision;
9
10pub fn write_config(conf: &str) -> Result<()> {
11 let mut f = File::create(".gitperfconfig")?;
12 f.write_all(conf.as_bytes())?;
13 Ok(())
14}
15
16pub fn read_config() -> Result<String> {
17 read_config_from_file(".gitperfconfig")
18}
19
20use std::path::Path;
21
22fn read_config_from_file<P: AsRef<Path>>(file: P) -> Result<String> {
23 let mut conf_str = String::new();
24 File::open(file)?.read_to_string(&mut conf_str)?;
25 Ok(conf_str)
26}
27
28pub fn determine_epoch_from_config(measurement: &str) -> Option<u32> {
29 let conf = read_config().ok()?;
32 determine_epoch(measurement, &conf)
33}
34
35fn determine_epoch(measurement: &str, conf_str: &str) -> Option<u32> {
36 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<()> {
66 let mut conf_str = read_config().unwrap_or_default();
67 bump_epoch_in_conf(measurement, &mut conf_str)?;
68 write_config(&conf_str)?;
69 Ok(())
70}
71
72pub fn backoff_max_elapsed_seconds_from_str(conf: &str) -> u64 {
74 let doc = conf.parse::<Document>().ok();
75 doc.and_then(|doc| {
76 doc.get("backoff")
77 .and_then(|b| b.get("max_elapsed_seconds"))
78 .and_then(|v| v.as_integer())
79 .map(|v| v as u64)
80 })
81 .unwrap_or(60)
82}
83
84pub fn backoff_max_elapsed_seconds() -> u64 {
86 backoff_max_elapsed_seconds_from_str(read_config().unwrap_or_default().as_str())
87}
88
89#[cfg(test)]
90mod test {
91 use super::*;
92
93 #[test]
94 fn test_read_epochs() {
95 let configfile = r#"[measurement."something"]
97#My comment
98epoch="34567898"
99
100[measurement."somethingelse"]
101epoch="a3dead"
102
103[measurement."*"]
104# General performance regression
105epoch="12344555"
106"#;
107
108 let epoch = determine_epoch("something", configfile);
109 assert_eq!(epoch, Some(0x34567898));
110
111 let epoch = determine_epoch("somethingelse", configfile);
112 assert_eq!(epoch, Some(0xa3dead));
113
114 let epoch = determine_epoch("unspecified", configfile);
115 assert_eq!(epoch, Some(0x12344555));
116 }
117
118 #[test]
119 fn test_bump_epochs() {
120 let configfile = r#"[measurement."something"]
121#My comment
122epoch = "34567898"
123"#;
124
125 let mut actual = String::from(configfile);
126 bump_epoch_in_conf("something", &mut actual).expect("Failed to bump epoch");
127
128 let expected = format!(
129 r#"[measurement."something"]
130#My comment
131epoch = "{}"
132"#,
133 &get_head_revision().expect("get_head_revision failed")[0..8],
134 );
135
136 assert_eq!(actual, expected);
137 }
138
139 #[test]
140 fn test_bump_new_epoch_and_read_it() {
141 let mut conf = String::new();
142 bump_epoch_in_conf("mymeasurement", &mut conf).expect("Failed to bump epoch");
143 let epoch = determine_epoch("mymeasurement", &conf);
144 assert!(epoch.is_some());
145 }
146
147 #[test]
148 fn test_parsing() {
149 let toml_str = r#"
150 measurement = { test2 = { epoch = "834ae670e2ecd5c87020fde23378b890832d6076" } }
151 "#;
152
153 let doc = toml_str.parse::<Document>().expect("sfdfdf");
154
155 let measurement = "test";
156
157 if let Some(e) = doc
158 .get("measurement")
159 .and_then(|m| m.get(measurement))
160 .and_then(|m| m.get("epoch"))
161 {
162 println!("YAY: {}", e);
163 panic!("stuff");
164 }
165 }
166
167 #[test]
168 fn test_backoff_max_elapsed_seconds() {
169 let configfile = "[backoff]\nmax_elapsed_seconds = 42\n";
171 assert_eq!(super::backoff_max_elapsed_seconds_from_str(configfile), 42);
172
173 let configfile = "";
175 assert_eq!(super::backoff_max_elapsed_seconds_from_str(configfile), 60);
176 }
177}