use std::collections::HashMap;
use anyhow::{Error, Result};
use ini_core as ini;
use regex::Regex;
use tracing::{event, Level};
pub fn parse_ini(payload: &String) -> Result<HashMap<String, HashMap<String, Vec<String>>>> {
let mut current_section = "".to_string();
let mut current_data = HashMap::new();
let mut parser = ini::Parser::new(payload.as_str());
while let Some(i) = parser.next() {
match i {
ini::Item::Error(e) => {
return Err(Error::msg(e.to_string()));
},
ini::Item::Section(s) => {
current_section = s.trim().to_string();
event![Level::DEBUG, "Found ini config section {}", s];
let re = Regex::new("^(?<kind>[^\\s]+)\\s*\"(?<name>[^\"]+)\"$").unwrap();
let (section_kind, section_name): (String, String);
match re.captures(¤t_section) {
Some(c) => {
section_kind = c.name("kind").unwrap().as_str().to_string();
section_name = c.name("name").unwrap().as_str().to_string();
current_section = format!("{} \"{}\"", section_kind, section_name);
},
None => {
if current_section == "global" {
current_data.insert(current_section.clone(), HashMap::new());
continue;
} else {
return Err(Error::msg(format!["Found unsupported ini header {}", s]));
}
}
}
if current_data.contains_key(¤t_section) {
event![
Level::WARN,
"The section key '{}' is present more than once in the configuration. {} {} {}",
current_section,
"Both sections will be merged.",
"This is not supported and the actual behavior may change in the future.",
"Update your configuration files to only declare jobs once.",
];
} else {
current_data.insert(current_section.clone(), HashMap::from([
("kind".to_string(), vec![section_kind]),
("name".to_string(), vec![section_name])
]));
}
},
ini::Item::SectionEnd => current_section = "".to_string(),
ini::Item::Property(k, v) => {
let k = k.trim();
let v = v.map(|v| v.trim());
event![Level::TRACE, "Found entry '{}' with value '{:?}'", k, v];
if current_section.is_empty() {
return Err(Error::msg(format!("Found property {} without a section", k)));
}
if v == None {
event![Level::WARN, "Found property '{}' without a value, it will be ignored.", k];
continue;
}
let section_info = current_data.get_mut(¤t_section).unwrap();
if !section_info.contains_key(k) {
section_info.insert(k.trim().to_string(), vec![]);
}
section_info.get_mut(k).unwrap().push(v.unwrap().to_string());
},
ini::Item::Comment(_) => {},
ini::Item::Blank => {},
}
}
Ok(current_data)
}