use std::path::{Path, PathBuf};
use crate::normalize_lexical;
use super::section::{
path_relative_to, section_path_for_target, section_path_for_target_candidates,
template_path_for_section,
};
use crate::{
config::{ConfigResult, ConfigSchema},
config_load::{figment_for_file, load_layer},
config_schema::direct_child_split_section_paths,
};
pub(super) fn template_source_include_paths<S>(path: &Path) -> ConfigResult<Vec<PathBuf>>
where
S: ConfigSchema,
{
if !path.exists() {
return Ok(Vec::new());
}
match load_layer::<S>(path) {
Ok(layer) => Ok(S::include_paths(&layer)),
Err(_) => load_include_paths_only(path),
}
}
fn load_include_paths_only(path: &Path) -> ConfigResult<Vec<PathBuf>> {
match figment_for_file(path).extract_inner::<Vec<PathBuf>>("include") {
Ok(paths) => Ok(paths),
Err(error) if error.missing() => Ok(Vec::new()),
Err(error) => Err(error.into()),
}
}
pub(super) fn default_child_include_paths<S>(
root_source_path: &Path,
node_source_path: &Path,
split_paths: &[Vec<&'static str>],
) -> Vec<PathBuf>
where
S: ConfigSchema,
{
let root_base_dir = root_source_path.parent().unwrap_or_else(|| Path::new("."));
let section_path = section_path_for_target::<S>(root_base_dir, node_source_path, split_paths)
.unwrap_or_default();
let source_base_dir = node_source_path.parent().unwrap_or_else(|| Path::new("."));
direct_child_split_section_paths(§ion_path, split_paths)
.into_iter()
.map(|child_section_path| {
let child_path =
root_base_dir.join(template_path_for_section::<S>(&child_section_path));
path_relative_to(&child_path, source_base_dir)
})
.collect()
}
pub(super) fn retain_split_include_paths<S>(
root_source_path: &Path,
node_source_path: &Path,
include_paths: Vec<PathBuf>,
all_section_paths: &[Vec<&'static str>],
split_paths: &[Vec<&'static str>],
) -> Vec<PathBuf>
where
S: ConfigSchema,
{
let root_base_dir = root_source_path.parent().unwrap_or_else(|| Path::new("."));
let source_base_dir = node_source_path.parent().unwrap_or_else(|| Path::new("."));
include_paths
.into_iter()
.filter(|include_path| {
let target_path = if include_path.is_absolute() {
include_path.clone()
} else {
source_base_dir.join(include_path)
};
let target_path = normalize_lexical(target_path);
match section_path_for_target_candidates::<S>(
root_base_dir,
&target_path,
all_section_paths,
) {
Some(section_path) if split_paths.contains(§ion_path) => {
let expected_target = normalize_lexical(
root_base_dir.join(template_path_for_section::<S>(§ion_path)),
);
target_path == expected_target
}
Some(_) => false,
None => {
!looks_like_split_section_path::<S>(root_base_dir, &target_path, split_paths)
}
}
})
.collect()
}
fn looks_like_split_section_path<S>(
root_base_dir: &Path,
target_path: &Path,
split_paths: &[Vec<&'static str>],
) -> bool
where
S: ConfigSchema,
{
let target_file_name = target_path.file_name();
split_paths.iter().any(|section_path| {
let expected_path =
normalize_lexical(root_base_dir.join(template_path_for_section::<S>(section_path)));
target_file_name == expected_path.file_name() && target_path != expected_path
})
}
pub(super) fn append_missing_include_paths(
include_paths: &mut Vec<PathBuf>,
defaults: Vec<PathBuf>,
) {
for default_path in defaults {
if !include_paths.contains(&default_path) {
include_paths.push(default_path);
}
}
}