#include "kappa/resolve/plan.hpp" #include "kappa/config/merge.hpp" #include #include namespace kappa::resolve { BuildPlan resolve(const dsl::SystemConfig& cfg, const Registry& registry) { BuildPlan plan; std::unordered_map name_to_idx; std::vector nodes; for (auto& pref : cfg.packages) { auto rit = registry.find(pref.name); if (rit == registry.end()) { plan.missing.push_back(pref.name); continue; } auto& pkg = rit->second; auto resolved = config::resolve_package(pkg, cfg.system, pref); BuildStep step; step.name = pkg.name; step.package = pkg; step.features = resolved.features; step.config = resolved.config; for (auto& dep : pkg.depends) { if (!dep.feature.empty()) { auto fit = step.features.find(dep.feature); if (fit == step.features.end() || !fit->second.enabled) { continue; // feature-gated and disabled } } step.dependencies.push_back({dep.name, dep.version}); } name_to_idx[step.name] = nodes.size(); nodes.push_back(std::move(step)); } std::vector in_degree(nodes.size(), 0); std::vector> adj(nodes.size()); for (std::size_t i = 0; i < nodes.size(); ++i) { for (auto& dep : nodes[i].dependencies) { auto it = name_to_idx.find(dep.name); if (it != name_to_idx.end()) { adj[it->second].push_back(i); in_degree[i]++; } } } std::queue q; for (std::size_t i = 0; i < nodes.size(); ++i) { if (in_degree[i] == 0) { q.push(i); } } std::vector visited(nodes.size(), false); while (!q.empty()) { auto u = q.front(); q.pop(); visited[u] = true; plan.steps.push_back(nodes[u]); for (auto v : adj[u]) { if (--in_degree[v] == 0) { q.push(v); } } } for (std::size_t i = 0; i < nodes.size(); ++i) { if (!visited[i]) { plan.cycles.push_back(nodes[i].name); } } return plan; } } // namespace kappa::resolve