#include "kappa/rebuild/rebuild.hpp" #include "kappa/install/install.hpp" #include "kappa/service/types.hpp" #include #include namespace kappa::rebuild { ChangeSet compute_changes(const dsl::SystemConfig& cfg) { ChangeSet cs; auto installed = install::read_installed(); std::set installed_names; for (auto& e : installed) { installed_names.insert(e.name); } std::set config_names; for (auto& p : cfg.packages) { config_names.insert(p.name); } for (auto& p : cfg.packages) { if (!installed_names.contains(p.name)) { cs.added.push_back(p.name); continue; } bool found = false; for (auto& e : installed) { if (e.name != p.name) { continue; } found = true; bool changed = false; if (!p.version.empty() && p.version != e.version) { changed = true; } if (!changed && (!p.features.empty() || !p.config.empty())) { if (e.config_hash.empty()) { changed = true; } else { auto ch = install::compute_config_hash(p.features, p.config); changed = (ch != e.config_hash); } } if (changed) { cs.changed.push_back(p.name); } break; } if (!found) { cs.added.push_back(p.name); } } for (auto& e : installed) { if (!config_names.contains(e.name)) { cs.removed.push_back(e.name); } } for (auto& e : installed) { // Compare the installed version (which stores the identifier string // for virtual packages like init/kernel/bootloader) against the // config value. These virtual entries have their identity in the // version field, not the hash field. if (e.name == "kernel" && e.version != cfg.boot.kernel) { cs.kernel_changed = true; } if (e.name == "init" && e.version != cfg.boot.init) { cs.init_changed = true; } if (e.name == "bootloader" && e.version != cfg.boot.bootloader) { cs.bootloader_changed = true; } } for (auto& svc : cfg.services) { if (svc.enable) { cs.services_changed = true; break; } } return cs; } InitImpact compute_init_impact(const dsl::SystemConfig& cfg, const resolve::Registry& registry) { InitImpact impact; auto init_system = cfg.boot.init; // Only compute impact if an init system is actually configured if (init_system.empty()) { return impact; } auto is = kappa::service::parse_init_system(init_system); if (is == kappa::service::InitSystem::Unknown) { std::cerr << "warning: unknown init system '" << init_system << "' — cannot compute init impact\n"; return impact; } // For each package in the config that has a matching registry entry... for (auto& pref : cfg.packages) { auto rit = registry.find(pref.name); if (rit == registry.end()) { continue; } auto& pkg = rit->second; // No services — nothing to do if (pkg.services.empty()) { impact.skipped.push_back(pkg.name); continue; } // Check if build scripts reference ${enabledinit} bool uses_enabledinit = false; auto check_phase = [&](const dsl::Phase& phase) { for (auto& cmd : phase.commands) { if (cmd.find("${enabledinit}") != std::string::npos) { uses_enabledinit = true; return; } } }; check_phase(pkg.prepare); if (!uses_enabledinit) check_phase(pkg.build); if (!uses_enabledinit) check_phase(pkg.check); if (!uses_enabledinit) check_phase(pkg.install); if (uses_enabledinit) { impact.service_rebuild.push_back(pkg.name); } else { impact.service_only.push_back(pkg.name); } } return impact; } } // namespace kappa::rebuild