use std::collections::HashMap;
use std::path::PathBuf;
use crate::config::{EnvVar, ProfileLayer, ResolvedProfile, validate_secret_specs};
use crate::errors::Result;
use super::layers::build_source_layers;
use super::merge::merge_with_policy;
use super::{CompositionInput, CompositionResult, ConflictResolution};
pub fn compose(local: &ResolvedProfile, sources: &[CompositionInput]) -> Result<CompositionResult> {
let mut all_layers: Vec<ProfileLayer> = local.layers.clone();
let mut conflicts: Vec<ConflictResolution> = Vec::new();
let mut source_env: HashMap<String, Vec<EnvVar>> = HashMap::new();
let mut sorted_sources: Vec<&CompositionInput> = sources.iter().collect();
sorted_sources.sort_by(|a, b| {
a.priority
.cmp(&b.priority)
.then(a.source_name.cmp(&b.source_name))
});
for input in &sorted_sources {
let mut env: Vec<EnvVar> = Vec::new();
for layer in &input.layers {
crate::merge_env(&mut env, &layer.spec.env);
}
source_env.insert(input.source_name.clone(), env);
let source_layers = build_source_layers(input, &mut conflicts)?;
all_layers.extend(source_layers);
}
all_layers.sort_by_key(|a| a.priority);
let mut merged = merge_with_policy(&all_layers, &mut conflicts)?;
let mut file_origins: HashMap<PathBuf, String> = HashMap::new();
for layer in &all_layers {
if layer.source != "local"
&& let Some(ref files) = layer.spec.files
{
for managed in &files.managed {
file_origins.insert(managed.target.clone(), layer.source.clone());
}
}
}
for merged_file in &mut merged.files.managed {
if merged_file.origin.is_none()
&& let Some(source) = file_origins.get(&merged_file.target)
{
merged_file.origin = Some(source.clone());
}
}
validate_secret_specs(&merged.secrets)?;
Ok(CompositionResult {
resolved: ResolvedProfile {
layers: all_layers,
merged,
},
conflicts,
source_env,
source_commits: HashMap::new(),
})
}