use super::model::{KVMap, KV};
use super::options::Options;
use std::collections::HashMap;
use std::env;
#[derive(Clone, Debug, Default)]
pub struct Scanner {
opts: Options,
map: KVMap,
}
impl Scanner {
pub fn new() -> Scanner {
Scanner {
opts: Options::default(),
..Default::default()
}
}
pub fn options(&self) -> &Options {
&self.opts
}
pub fn options_mut(&mut self) -> &mut Options {
&mut self.opts
}
pub fn set_top_level<'a>(&'a mut self, project: &str) -> &'a mut Scanner {
self.opts.set_top_level(project);
self
}
pub fn add_section<'a>(&'a mut self, section: &str) -> &'a mut Scanner {
self.opts.add_section(section);
self
}
pub fn scan(&mut self) -> &mut Scanner {
self.map = scan(self.opts.top_level(), self.opts.sections());
self
}
pub fn toml(&self) -> String {
self.map.toml()
}
}
fn env_format(name: &str) -> String {
name.to_string().to_uppercase().replace('-', "_")
}
pub fn scan(top_level: &str, sections: &[String]) -> KVMap {
let mut result_map = KVMap::new(top_level);
let mut seen = Vec::new();
let mut section_lookup = HashMap::new();
let mut prefixes = Vec::new();
let main_prefix = env_format(top_level);
for section in sections.iter().rev() {
let prefix = format!("{}_{}", main_prefix, env_format(section));
section_lookup.insert(prefix.clone(), section.as_str());
prefixes.push(prefix);
}
prefixes.push(main_prefix.clone());
section_lookup.insert(main_prefix, top_level);
let mut env_vars = Vec::new();
for (key, value) in env::vars() {
env_vars.push(KV::new(key, value));
}
env_vars.sort();
env_vars.reverse();
for prefix in prefixes.iter() {
let mut section_vars = Vec::new();
let section = section_lookup.get(prefix);
match section {
None => continue,
_ => {
for env_var in &env_vars {
if env_var.key().starts_with(prefix) && !seen.contains(env_var) {
let mut kv = env_var.clone();
kv.normalise_key(prefix);
section_vars.push(kv);
seen.push(env_var.clone());
continue;
};
}
}
}
section_vars.reverse();
if let Some(section_name) = section {
result_map.insert(section_name, section_vars);
}
}
result_map
}