|
|
|
@ -5,12 +5,13 @@ use valico::json_schema::Scope;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
distro::distro_config::DistroConfig,
|
|
|
|
|
error::{AppError, AppResult},
|
|
|
|
|
error::{AppResult, OSConfigError, SchemaError},
|
|
|
|
|
utils::CFG_PATH,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use super::OSConfig;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct OSConfigLoader<'a> {
|
|
|
|
|
distro_cfg: &'a DistroConfig,
|
|
|
|
|
cfg_path: PathBuf,
|
|
|
|
@ -24,6 +25,7 @@ impl<'a> OSConfigLoader<'a> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tracing::instrument(level = "trace", skip_all)]
|
|
|
|
|
pub async fn load(&self) -> AppResult<OSConfig> {
|
|
|
|
|
let schema = self.load_extension_schema().await?;
|
|
|
|
|
let os_config = OSConfig::load(&self.cfg_path).await?;
|
|
|
|
@ -32,13 +34,14 @@ impl<'a> OSConfigLoader<'a> {
|
|
|
|
|
Ok(os_config)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn load_extension_schema(&self) -> AppResult<serde_json::Value> {
|
|
|
|
|
#[tracing::instrument(level = "trace", skip_all)]
|
|
|
|
|
async fn load_extension_schema(&self) -> Result<serde_json::Value, SchemaError> {
|
|
|
|
|
let schema_path = self
|
|
|
|
|
.distro_cfg
|
|
|
|
|
.config
|
|
|
|
|
.schema
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(PathBuf::from)
|
|
|
|
|
.map(|p| CFG_PATH.join(p))
|
|
|
|
|
.unwrap_or_else(|| CFG_PATH.join("config.schema.json"));
|
|
|
|
|
let contents = fs::read_to_string(schema_path).await?;
|
|
|
|
|
let schema = serde_json::from_str(&contents)?;
|
|
|
|
@ -46,33 +49,29 @@ impl<'a> OSConfigLoader<'a> {
|
|
|
|
|
Ok(schema)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tracing::instrument(level = "trace", skip_all)]
|
|
|
|
|
fn validate_config(schema: serde_json::Value, config: &OSConfig) -> AppResult<()> {
|
|
|
|
|
let mut scope = Scope::new();
|
|
|
|
|
let schema = scope.compile_and_return(schema, true)?;
|
|
|
|
|
let mut errors = Vec::new();
|
|
|
|
|
let schema = scope
|
|
|
|
|
.compile_and_return(schema, true)
|
|
|
|
|
.map_err(SchemaError::ParseSchema)?;
|
|
|
|
|
let ext_value = serde_json::Value::Object(config.extended.clone().into_iter().collect());
|
|
|
|
|
|
|
|
|
|
for (key, value) in config.extended.iter() {
|
|
|
|
|
let result = schema.validate_in(value, key);
|
|
|
|
|
let result = schema.validate(&ext_value);
|
|
|
|
|
|
|
|
|
|
for error in result.errors {
|
|
|
|
|
tracing::error!(
|
|
|
|
|
"ConfigError: {} ({}) at {}",
|
|
|
|
|
error.get_title(),
|
|
|
|
|
error.get_code(),
|
|
|
|
|
error.get_path(),
|
|
|
|
|
);
|
|
|
|
|
errors.push(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if errors.is_empty() {
|
|
|
|
|
if result.is_valid() {
|
|
|
|
|
tracing::debug!("Config is valid");
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
let msg = errors
|
|
|
|
|
let msg = result
|
|
|
|
|
.errors
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|e| format!("{} ({}) at {}", e.get_title(), e.get_code(), e.get_path()))
|
|
|
|
|
.map(|e| format!("{} > {}", e.get_path(), e.get_title()))
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
.join("\n");
|
|
|
|
|
Err(AppError::InvalidConfig(msg))
|
|
|
|
|
tracing::error!("Config is invalid");
|
|
|
|
|
|
|
|
|
|
Err(OSConfigError::Validation(msg).into())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|