fix: Phase 3+4 review — deterministic hash, EINTR, env restore, installer wiring

- std::hash→FNV-1a (deterministic across runs, null-byte-separated)
- waitpid EINTR retry loop (prevents zombie processes under signals)
- setenv save/restore between builds (prevents cross-package env leaks)
- install::install() wired into kappa build CLI (store + DB + generations)
- Zero-padded generation filenames (gen-0001, lexicographic sort correct)
- Hardcoded paths fixed: /tmp/kappa-build→paths::temp_dir()/build
- Hardcoded destdir: /kappa/temp/destdir→paths::temp_dir()/destdir
- ensure_directories() called at main() startup
- build subcommand: -j N, --root wired end-to-end
This commit is contained in:
2026-07-30 05:14:51 -04:00
parent d7fc9d45fb
commit 6c993d2d17
12 changed files with 308 additions and 40 deletions
+58 -1
View File
@@ -1,8 +1,11 @@
#include "kappa/build/build.hpp"
#include "kappa/cli/diagnostic.hpp"
#include "kappa/config/eval.hpp"
#include "kappa/dsl/parser.hpp"
#include "kappa/dsl/system.hpp"
#include "kappa/fetch/fetch.hpp"
#include "kappa/install/install.hpp"
#include "kappa/paths.hpp"
#include "kappa/resolve/plan.hpp"
#include "kappa/tools/doctor.hpp"
#include "kappa/tools/format.hpp"
@@ -32,6 +35,7 @@ Subcommands:
doctor <file> Check a .kap file for issues and warnings
resolve <config> Resolve a build plan from a system config
fetch <package> Download and verify source for a package
build <package> Build a package from its source directory
Options:
-h, --help Show this help message
@@ -79,6 +83,8 @@ static void handle_parse_error(const char* path,
}
int main(int argc, char* argv[]) {
paths::ensure_directories();
if (argc < 2) {
std::cerr << "kappa: missing subcommand\n\n";
print_usage();
@@ -102,7 +108,8 @@ int main(int argc, char* argv[]) {
|| (subcommand == "format")
|| (subcommand == "doctor")
|| (subcommand == "resolve")
|| (subcommand == "fetch");
|| (subcommand == "fetch")
|| (subcommand == "build");
if (!valid_subcommand) {
std::cerr << "error: unknown subcommand '" << subcommand << "'\n\n";
@@ -122,6 +129,15 @@ int main(int argc, char* argv[]) {
std::cout << version << '\n';
return 0;
}
if (std::string_view(argv[i]) == "-j"
|| std::string_view(argv[i]) == "--jobs") {
++i;
continue;
}
if (std::string_view(argv[i]) == "--root" && i + 1 < argc) {
paths::set_root(argv[++i]);
continue;
}
if (!is_flag(argv[i])) {
file_arg = argv[i];
break;
@@ -197,6 +213,47 @@ int main(int argc, char* argv[]) {
}
}
if (subcommand == "build") {
try {
auto pkg = dsl::parse(source);
int jobs = 1;
for (int i = 2; i < argc; ++i) {
auto arg = std::string_view(argv[i]);
if ((arg == "-j" || arg == "--jobs") && i + 1 < argc) {
jobs = std::stoi(argv[++i]);
}
}
resolve::Registry reg;
reg[pkg.name] = pkg;
resolve::BuildStep step;
step.name = pkg.name;
step.package = &reg.at(pkg.name);
step.resolved = config::resolve_package(pkg, {}, {});
auto work_dir = paths::temp_dir() / "build";
auto result = build::build(step, work_dir, jobs);
if (result.ok) {
auto inst = install::install(step, work_dir);
if (inst.ok) {
std::cout << "build successful — installed to "
<< inst.store_path << "\n";
return 0;
}
std::cerr << "install failed: " << inst.error << "\n";
return 1;
}
std::cerr << "build failed in phase '" << result.phase
<< "': " << result.error << "\n";
return 1;
} catch (const std::exception& e) {
std::cerr << "build error: " << e.what() << "\n";
return 1;
}
}
if (subcommand == "format") {
try {
auto pkg = dsl::parse(source);