Updated install script
This commit is contained in:
@@ -31,12 +31,15 @@ use std::{collections::BTreeMap, time::Duration};
|
||||
use ahash::AHashMap;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub struct Config {
|
||||
#[serde(skip)]
|
||||
pub keys: BTreeMap<String, String>,
|
||||
pub warnings: AHashMap<String, ConfigWarning>,
|
||||
pub errors: AHashMap<String, ConfigError>,
|
||||
#[cfg(debug_assertions)]
|
||||
#[serde(skip)]
|
||||
pub keys_read: parking_lot::Mutex<ahash::AHashSet<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
@@ -44,6 +47,7 @@ pub struct Config {
|
||||
pub enum ConfigWarning {
|
||||
Missing,
|
||||
AppliedDefault { default: String },
|
||||
Unread { value: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
@@ -199,7 +203,10 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_warnings(&self, use_stderr: bool) {
|
||||
pub fn log_warnings(&mut self, use_stderr: bool) {
|
||||
#[cfg(debug_assertions)]
|
||||
self.warn_unread_keys();
|
||||
|
||||
for (key, warn) in &self.warnings {
|
||||
let message = match warn {
|
||||
ConfigWarning::AppliedDefault { default } => {
|
||||
@@ -208,6 +215,9 @@ impl Config {
|
||||
ConfigWarning::Missing => {
|
||||
format!("WARNING: Missing setting {key:?}")
|
||||
}
|
||||
ConfigWarning::Unread { value } => {
|
||||
format!("WARNING: Unused setting {key:?} with value {value:?}")
|
||||
}
|
||||
};
|
||||
if !use_stderr {
|
||||
tracing::debug!("{}", message);
|
||||
@@ -218,6 +228,26 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Config {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
keys: self.keys.clone(),
|
||||
warnings: self.warnings.clone(),
|
||||
errors: self.errors.clone(),
|
||||
#[cfg(debug_assertions)]
|
||||
keys_read: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Config {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.keys == other.keys && self.warnings == other.warnings && self.errors == other.errors
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Config {}
|
||||
|
||||
impl From<(String, String)> for ConfigKey {
|
||||
fn from((key, value): (String, String)) -> Self {
|
||||
Self { key, value }
|
||||
|
||||
@@ -39,6 +39,10 @@ use super::{Config, ConfigError, ConfigWarning, Rate};
|
||||
impl Config {
|
||||
pub fn property<T: ParseValue>(&mut self, key: impl AsKey) -> Option<T> {
|
||||
let key = key.as_key();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(key.clone());
|
||||
|
||||
if let Some(value) = self.keys.get(&key) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
@@ -58,6 +62,10 @@ impl Config {
|
||||
default: &str,
|
||||
) -> Option<T> {
|
||||
let key = key.as_key();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(key.clone());
|
||||
|
||||
let value = match self.keys.get(&key) {
|
||||
Some(value) => value.as_str(),
|
||||
None => default,
|
||||
@@ -94,6 +102,10 @@ impl Config {
|
||||
|
||||
pub fn property_require<T: ParseValue>(&mut self, key: impl AsKey) -> Option<T> {
|
||||
let key = key.as_key();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(key.clone());
|
||||
|
||||
if let Some(value) = self.keys.get(&key) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
@@ -137,31 +149,22 @@ impl Config {
|
||||
pub fn set_values<'x, 'y: 'x>(&'y self, prefix: impl AsKey) -> impl Iterator<Item = &str> + 'x {
|
||||
let prefix = prefix.as_prefix();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(prefix.clone());
|
||||
|
||||
self.keys
|
||||
.keys()
|
||||
.filter_map(move |key| key.strip_prefix(&prefix))
|
||||
}
|
||||
|
||||
pub fn set_values_or_else(
|
||||
&self,
|
||||
prefix: impl AsKey,
|
||||
default: impl AsKey,
|
||||
) -> impl Iterator<Item = &str> {
|
||||
let mut prefix = prefix.as_prefix();
|
||||
|
||||
self.set_values(if self.keys.keys().any(|k| k.starts_with(&prefix)) {
|
||||
prefix.truncate(prefix.len() - 1);
|
||||
prefix
|
||||
} else {
|
||||
default.as_key()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn properties<T: ParseValue>(&mut self, prefix: impl AsKey) -> Vec<(String, T)> {
|
||||
let full_prefix = prefix.as_key();
|
||||
let prefix = prefix.as_prefix();
|
||||
let mut results = Vec::new();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(prefix.clone());
|
||||
|
||||
for (key, value) in &self.keys {
|
||||
if key.starts_with(&prefix) || key == &full_prefix {
|
||||
match T::parse_value(value) {
|
||||
@@ -180,7 +183,12 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn value(&self, key: impl AsKey) -> Option<&str> {
|
||||
self.keys.get(&key.as_key()).map(|s| s.as_str())
|
||||
let key = key.as_key();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(key.clone());
|
||||
|
||||
self.keys.get(&key).map(|s| s.as_str())
|
||||
}
|
||||
|
||||
pub fn contains_key(&self, key: impl AsKey) -> bool {
|
||||
@@ -189,6 +197,10 @@ impl Config {
|
||||
|
||||
pub fn value_require(&mut self, key: impl AsKey) -> Option<&str> {
|
||||
let key = key.as_key();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(key.clone());
|
||||
|
||||
if let Some(value) = self.keys.get(&key) {
|
||||
Some(value.as_str())
|
||||
} else {
|
||||
@@ -214,8 +226,16 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn value_or_else(&self, key: impl AsKey, or_else: impl AsKey) -> Option<&str> {
|
||||
let key = key.as_key();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
self.keys_read.lock().insert(key.clone());
|
||||
self.keys_read.lock().insert(or_else.clone().as_key());
|
||||
}
|
||||
|
||||
self.keys
|
||||
.get(&key.as_key())
|
||||
.get(&key)
|
||||
.or_else(|| self.keys.get(&or_else.as_key()))
|
||||
.map(|s| s.as_str())
|
||||
}
|
||||
@@ -224,6 +244,9 @@ impl Config {
|
||||
let full_prefix = prefix.as_key();
|
||||
let prefix = prefix.as_prefix();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(prefix.clone());
|
||||
|
||||
self.keys.iter().filter_map(move |(key, value)| {
|
||||
if key.starts_with(&prefix) || key == &full_prefix {
|
||||
(key.as_str(), value.as_str()).into()
|
||||
@@ -233,18 +256,35 @@ impl Config {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iterate_prefix(&self, prefix: impl AsKey) -> impl Iterator<Item = (&str, &str)> {
|
||||
let prefix = prefix.as_prefix();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
self.keys_read.lock().insert(prefix.clone());
|
||||
|
||||
self.keys
|
||||
.iter()
|
||||
.filter_map(move |(key, value)| Some((key.strip_prefix(&prefix)?, value.as_str())))
|
||||
}
|
||||
|
||||
pub fn values_or_else(
|
||||
&self,
|
||||
prefix: impl AsKey,
|
||||
default: impl AsKey,
|
||||
or_else: impl AsKey,
|
||||
) -> impl Iterator<Item = (&str, &str)> {
|
||||
let mut prefix = prefix.as_prefix();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
self.keys_read.lock().insert(prefix.clone());
|
||||
self.keys_read.lock().insert(or_else.clone().as_prefix());
|
||||
}
|
||||
|
||||
self.values(if self.keys.keys().any(|k| k.starts_with(&prefix)) {
|
||||
prefix.truncate(prefix.len() - 1);
|
||||
prefix
|
||||
} else {
|
||||
default.as_key()
|
||||
or_else.as_key()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -253,10 +293,6 @@ impl Config {
|
||||
self.keys.keys().any(|k| k.starts_with(&prefix))
|
||||
}
|
||||
|
||||
pub fn take_value(&mut self, key: &str) -> Option<String> {
|
||||
self.keys.remove(key)
|
||||
}
|
||||
|
||||
pub fn new_parse_error(&mut self, key: impl AsKey, details: impl Into<String>) {
|
||||
self.errors.insert(
|
||||
key.as_key(),
|
||||
@@ -278,6 +314,24 @@ impl Config {
|
||||
pub fn new_missing_property(&mut self, key: impl AsKey) {
|
||||
self.warnings.insert(key.as_key(), ConfigWarning::Missing);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn warn_unread_keys(&mut self) {
|
||||
let mut keys = self.keys.clone();
|
||||
|
||||
for key in self.keys_read.lock().iter() {
|
||||
if let Some(base_key) = key.strip_suffix('.') {
|
||||
keys.remove(base_key);
|
||||
keys.retain(|k, _| !k.starts_with(key));
|
||||
} else {
|
||||
keys.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (key, value) in keys {
|
||||
self.warnings.insert(key, ConfigWarning::Unread { value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseValue: Sized {
|
||||
|
||||
Reference in New Issue
Block a user