1use std::collections::BTreeMap;
5use std::ops::Deref;
6use std::path::Path;
7use std::sync::Arc;
8
9use cu::pre::*;
10
11pub fn try_find_default_config_file() -> Option<&'static str> {
14 ["Lisensor.toml", "lisensor.toml"]
15 .into_iter()
16 .find(|x| Path::new(x).exists())
17}
18
19#[derive(Debug, Default, Clone, PartialEq, Eq)]
21pub struct Config {
22 globs: BTreeMap<String, (Arc<String>, Arc<String>)>,
24}
25
26#[derive(Deserialize)]
30struct TomlConfig(BTreeMap<String, BTreeMap<String, String>>);
31
32impl Config {
33 pub fn new(holder: String, license: String, glob_list: Vec<String>) -> Self {
36 let holder = Arc::new(holder);
37 let license = Arc::new(license);
38 let mut globs = BTreeMap::new();
39 for glob in glob_list {
40 use std::collections::btree_map::Entry;
41 match globs.entry(glob) {
42 Entry::Vacant(entry) => {
43 entry.insert((Arc::clone(&holder), Arc::clone(&license)));
44 }
45 Entry::Occupied(entry) => {
46 let glob = entry.key();
47 cu::warn!("glob '{glob}' is specfied multiple times!");
48 }
49 }
50 }
51 Self { globs }
52 }
53
54 pub fn build(path: &str) -> cu::Result<Self> {
59 let raw = toml::parse::<TomlConfig>(&cu::fs::read_string(path)?)?;
60 let parent = Path::new(path)
61 .parent()
62 .context("failed to get parent path for config")?;
63 let mut globs = BTreeMap::new();
64 for (holder, table) in raw.0 {
65 let holder = Arc::new(holder);
66 for (glob, license) in table {
67 let glob = parent.join(glob).into_utf8()?;
70 use std::collections::btree_map::Entry;
71 match globs.entry(glob) {
72 Entry::Vacant(entry) => {
73 entry.insert((Arc::clone(&holder), Arc::new(license)));
74 }
75 Entry::Occupied(entry) => {
76 let glob = entry.key();
77 let (curr_holder, curr_license) = entry.get();
78 if *curr_holder == holder && curr_license.deref() == license.as_str() {
79 cu::warn!("glob '{glob}' specified multiple times in '{path}'!");
80 continue;
81 }
82 cu::error!("conflicting config specified for glob '{glob}':");
83 cu::error!(
84 "- in one config, it has holder '{holder}' and license '{license}'"
85 );
86 cu::error!(
87 "- in another, it has holder '{curr_holder}' and license '{curr_license}'"
88 );
89 cu::bail!("conflicting config detected!");
90 }
91 }
92 }
93 }
94 Ok(Self { globs })
95 }
96
97 pub fn absorb(&mut self, other: Self) -> cu::Result<()> {
99 for (glob, (holder, license)) in other.globs {
100 use std::collections::btree_map::Entry;
101 match self.globs.entry(glob) {
102 Entry::Vacant(entry) => {
103 entry.insert((holder, license));
104 }
105 Entry::Occupied(entry) => {
106 let glob = entry.key();
107 let (curr_holder, curr_license) = entry.get();
108 if *curr_holder == holder && curr_license.deref() == license.deref() {
109 cu::warn!("glob '{glob}' specified multiple times in multiple configs!");
110 continue;
111 }
112 cu::error!(
113 "conflicting config specified for glob '{glob}' in multiple configs:"
114 );
115 cu::error!("- in one config, it has holder '{holder}' and license '{license}'");
116 cu::error!(
117 "- in another, it has holder '{curr_holder}' and license '{curr_license}'"
118 );
119 cu::bail!("conflicting config detected!");
120 }
121 }
122 }
123 Ok(())
124 }
125}
126
127impl Config {
128 #[allow(clippy::should_implement_trait)]
130 pub fn into_iter(self) -> impl Iterator<Item = (String, Arc<String>, Arc<String>)> {
131 self.globs
134 .into_iter()
135 .map(|(path, (holder, license))| (path, holder, license))
136 }
137}