use std::collections::BTreeMap;
use std::ops::Deref;
use std::path::Path;
use std::sync::Arc;
use cu::pre::*;
pub fn try_find_default_config_file() -> Option<&'static str> {
["Lisensor.toml", "lisensor.toml"]
.into_iter()
.find(|x| Path::new(x).exists())
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Config {
globs: BTreeMap<String, (Arc<String>, Arc<String>)>,
}
#[derive(Deserialize)]
struct TomlConfig(BTreeMap<String, BTreeMap<String, String>>);
impl Config {
pub fn new(holder: String, license: String, glob_list: Vec<String>) -> Self {
let holder = Arc::new(holder);
let license = Arc::new(license);
let mut globs = BTreeMap::new();
for glob in glob_list {
use std::collections::btree_map::Entry;
match globs.entry(glob) {
Entry::Vacant(entry) => {
entry.insert((Arc::clone(&holder), Arc::clone(&license)));
}
Entry::Occupied(entry) => {
let glob = entry.key();
cu::warn!("glob '{glob}' is specfied multiple times!");
}
}
}
Self { globs }
}
pub fn build(path: &str) -> cu::Result<Self> {
let raw = toml::parse::<TomlConfig>(&cu::fs::read_string(path)?)?;
let parent = Path::new(path)
.parent()
.context("failed to get parent path for config")?;
let mut globs = BTreeMap::new();
for (holder, table) in raw.0 {
let holder = Arc::new(holder);
for (glob, license) in table {
let glob = parent.join(glob).into_utf8()?;
use std::collections::btree_map::Entry;
match globs.entry(glob) {
Entry::Vacant(entry) => {
entry.insert((Arc::clone(&holder), Arc::new(license)));
}
Entry::Occupied(entry) => {
let glob = entry.key();
let (curr_holder, curr_license) = entry.get();
if *curr_holder == holder && curr_license.deref() == license.as_str() {
cu::warn!("glob '{glob}' specified multiple times in '{path}'!");
continue;
}
cu::error!("conflicting config specified for glob '{glob}':");
cu::error!(
"- in one config, it has holder '{holder}' and license '{license}'"
);
cu::error!(
"- in another, it has holder '{curr_holder}' and license '{curr_license}'"
);
cu::bail!("conflicting config detected!");
}
}
}
}
Ok(Self { globs })
}
pub fn absorb(&mut self, other: Self) -> cu::Result<()> {
for (glob, (holder, license)) in other.globs {
use std::collections::btree_map::Entry;
match self.globs.entry(glob) {
Entry::Vacant(entry) => {
entry.insert((holder, license));
}
Entry::Occupied(entry) => {
let glob = entry.key();
let (curr_holder, curr_license) = entry.get();
if *curr_holder == holder && curr_license.deref() == license.deref() {
cu::warn!("glob '{glob}' specified multiple times in multiple configs!");
continue;
}
cu::error!(
"conflicting config specified for glob '{glob}' in multiple configs:"
);
cu::error!("- in one config, it has holder '{holder}' and license '{license}'");
cu::error!(
"- in another, it has holder '{curr_holder}' and license '{curr_license}'"
);
cu::bail!("conflicting config detected!");
}
}
}
Ok(())
}
}
impl Config {
#[allow(clippy::should_implement_trait)]
pub fn into_iter(self) -> impl Iterator<Item = (String, Arc<String>, Arc<String>)> {
self.globs
.into_iter()
.map(|(path, (holder, license))| (path, holder, license))
}
}