diff --git a/src/main.cpp b/src/main.cpp index 14bc196..c9dcf95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -111,6 +111,24 @@ static void handle_parse_error(const char* path, static resolve::Registry build_registry(const dsl::SystemConfig& cfg) { resolve::Registry registry; + // Pre-populate from cached packages so transitive deps can be resolved + auto pkg_dir = paths::packages_dir(); + std::error_code ec; + if (std::filesystem::exists(pkg_dir)) { + for (auto& entry : std::filesystem::directory_iterator(pkg_dir, ec)) { + if (ec) break; + if (entry.path().extension() != ".kap") continue; + std::ifstream in(entry.path()); + if (!in) continue; + std::ostringstream buf; + buf << in.rdbuf(); + try { + auto pkg = dsl::parse(buf.str()); + registry.try_emplace(pkg.name, std::move(pkg)); + } catch (...) { continue; } + } + } + for (const auto& pref : cfg.packages) { bool found = false; diff --git a/src/resolve/plan.cpp b/src/resolve/plan.cpp index cde17c2..4d3a254 100644 --- a/src/resolve/plan.cpp +++ b/src/resolve/plan.cpp @@ -42,7 +42,58 @@ BuildPlan resolve(const dsl::SystemConfig& cfg, const Registry& registry) { nodes.push_back(std::move(step)); } - // Detect conflicts between selected packages + // Transitive dependency discovery: pull in deps that are in the + // registry but not yet in the plan. Continue until no new deps + // are discovered — handles arbitrarily deep dependency chains. + bool changed = true; + while (changed) { + changed = false; + std::size_t current_size = nodes.size(); + + for (std::size_t i = 0; i < current_size; ++i) { + if (!nodes[i].package) continue; + + for (auto& dep : nodes[i].package->depends) { + if (name_to_idx.contains(dep.name)) continue; + + // Skip feature-conditional deps that aren't enabled + if (!dep.feature.empty()) { + auto fit = nodes[i].resolved.features.find(dep.feature); + if (fit == nodes[i].resolved.features.end() || !fit->second.enabled) { + continue; + } + } + + auto rit = registry.find(dep.name); + if (rit == registry.end()) continue; + + auto& pkg = rit->second; + auto resolved = config::resolve_package(pkg, cfg.system, {}); + + BuildStep step; + step.name = pkg.name; + step.package = &pkg; + step.resolved = std::move(resolved); + step.enabled_init = cfg.boot.init; + + for (auto& ddep : pkg.depends) { + if (!ddep.feature.empty()) { + auto fit = step.resolved.features.find(ddep.feature); + if (fit == step.resolved.features.end() || !fit->second.enabled) { + continue; + } + } + step.dependencies.push_back({ddep.name, ddep.version}); + } + + name_to_idx[step.name] = nodes.size(); + nodes.push_back(std::move(step)); + changed = true; + } + } + } + + // Detect conflicts between all selected packages (including transitive) std::unordered_set selected; for (auto& node : nodes) { selected.insert(node.name); }