use std::collections::BTreeMap;
use crate::ConfigError;
use crate::metadata::paths::validate_metadata_path;
use crate::path::canonicalize_path_with_aliases;
use super::super::{ConfigMetadata, EnvDecoder};
impl ConfigMetadata {
pub(crate) fn canonicalize_env_decoder_paths(&mut self) -> Result<(), ConfigError> {
let alias_source_fields = self
.fields
.iter()
.filter(|field| !field.is_env_decoder_only())
.cloned()
.collect::<Vec<_>>();
let aliases = ConfigMetadata {
fields: alias_source_fields,
checks: Vec::new(),
}
.alias_overrides()?;
let mut seen = BTreeMap::<String, (String, EnvDecoder)>::new();
for field in &mut self.fields {
if !field.is_env_decoder_only() {
continue;
}
let original_path = field.path.clone();
let canonical = canonicalize_path_with_aliases(&original_path, &aliases);
let Some(decoder) = field.env_decode else {
return Err(ConfigError::MetadataInvalid {
path: original_path,
message: "environment decoder metadata is missing a decoder".to_owned(),
});
};
if let Some((first_path, first_decoder)) = seen.get(&canonical)
&& (first_path != &original_path || *first_decoder != decoder)
{
return Err(ConfigError::MetadataConflict {
kind: "environment decoder",
name: canonical,
first_path: first_path.clone(),
second_path: original_path,
});
}
seen.insert(canonical.clone(), (original_path, decoder));
field.path = canonical;
}
self.normalize();
Ok(())
}
pub fn env_overrides(&self) -> Result<BTreeMap<String, String>, ConfigError> {
let aliases = self.alias_overrides()?;
let mut envs = BTreeMap::new();
let mut canonical_targets = BTreeMap::<String, String>::new();
for field in &self.fields {
let Some(env) = &field.env else {
continue;
};
if env.is_empty() {
return Err(ConfigError::MetadataInvalid {
path: field.path.clone(),
message: "explicit environment variable names cannot be empty".to_owned(),
});
}
validate_metadata_path(&field.path)?;
if field.path.is_empty() {
return Err(ConfigError::MetadataInvalid {
path: field.path.clone(),
message: "explicit environment variable names cannot target the root path"
.to_owned(),
});
}
if field.path.split('.').any(|segment| segment == "*") {
return Err(ConfigError::MetadataInvalid {
path: field.path.clone(),
message: "explicit environment variable names cannot target wildcard paths"
.to_owned(),
});
}
let canonical = canonicalize_path_with_aliases(&field.path, &aliases);
if let Some(first_env) = canonical_targets.insert(canonical.clone(), env.clone())
&& first_env != *env
{
return Err(ConfigError::MetadataConflict {
kind: "environment override target",
name: canonical,
first_path: first_env,
second_path: env.clone(),
});
}
if let Some(first_path) = envs.insert(env.clone(), field.path.clone())
&& first_path != field.path
{
return Err(ConfigError::MetadataConflict {
kind: "environment variable",
name: env.clone(),
first_path,
second_path: field.path.clone(),
});
}
}
Ok(envs)
}
}