feat: system-agnostic package manager — 5 inits, 2 bootloaders, parallel scheduler
Complete rewrite of kappa from a sequential build tool into a
system-agnostic package manager with runtime init switching.
Core additions:
- 5 init system backends: systemd, openrc, s6, runit, dinit
(service file generation, enable/disable, init_paths)
- 2 bootloader backends: grub, limine (config generation, fallback entries)
- Parallel scheduler with worker pool, depth-based priority (Beta/Alpha/Zeta),
atomic claiming, dependency tracking, deduplication, and failure propagation
- Init-switch impact analysis: only rebuild packages using ${enabledinit}
- Init-agnostic service definitions: flat NamedService blocks replace
per-init nesting
- Package conflicts: mutual incompatibility detection in resolver
- System groups: init-agnostic group creation in DSL
- Init-agnostic hostname/timezone: direct /etc/hostname and /etc/localtime writes
- Source tarball caching at /kappa/cache/ with atomic write-then-rename
- Package recipe caching with remote fetching and version comparison
- remotes = [...] block in system config for package repositories
- Auto-fetch: rebuild resolves missing packages from remotes
- uninstall phase in package definitions
- ${enabledinit} eval variable for init-conditional builds
- Shared util module (to_lower, shell_escape)
- 54 integration tests across two shell test suites
- Comprehensive README and CONTRIBUTING guide
Bug fixes from review:
- CRITICAL: Replace std::system() with fork+execvp (command injection)
- CRITICAL: Fix scheduler deadlock on successful completion
- CRITICAL: Fix rebuild init/kernel/bootloader change detection
- HIGH: Fix path traversal via unsanitized package names in cache
- HIGH: Fix TOCTOU race in cache write with atomic rename
- HIGH: Fix formatter dropping remotes/imports blocks
- HIGH: Fix formatter stripping empty-string assert values
- HIGH: Fix formatter non-idempotent output (sorted key iteration)
- HIGH: Populate ${enabledinit} from boot.init in BuildStep
- MEDIUM: Fix data race on non-atomic scheduler stop flag
- MEDIUM: Fix compute_depths() traversal direction
- MEDIUM: Add runit to doctor supported-init warning
- MEDIUM: Extract to_lower/shell_escape to shared kappa::util
- MEDIUM: Consolidate generator declarations in headers
This commit is contained in:
+64
-13
@@ -1,6 +1,51 @@
|
||||
/*
|
||||
* foo — a web server with optional SSL and GUI support.
|
||||
* Demonstrates the full kappa DSL surface.
|
||||
*
|
||||
* SERVICE MODEL
|
||||
* =============
|
||||
* Kappa service definitions are init-system-agnostic. The `service` block
|
||||
* describes what the service IS (exec, type, ports, user) — NOT how each init
|
||||
* system runs it. The system config's `boot.init` field (see config.kap)
|
||||
* determines which init system's service files get generated at install time:
|
||||
*
|
||||
* boot.init = "systemd" → generates .service unit files
|
||||
* boot.init = "openrc" → generates /etc/init.d scripts
|
||||
* boot.init = "s6" → generates s6 service directories
|
||||
* boot.init = "dinit" → generates dinit service descriptors
|
||||
* boot.init = "runit" → generates runit service directories
|
||||
*
|
||||
* Per-init blocks (service { systemd { ... } s6 { ... } }) do NOT exist.
|
||||
* If a package genuinely needs init-specific behaviour (e.g. different
|
||||
* ./configure flags for systemd vs. openrc), use ${enabledinit} in the
|
||||
* build phase — see examples/postgres.kap for that pattern.
|
||||
*
|
||||
* SERVICE TYPE VALUES
|
||||
* ===================
|
||||
* These are semantic, not init-specific. Each backend translates them
|
||||
* into its own vocabulary:
|
||||
*
|
||||
* "simple" — foreground process; init manages lifecycle directly.
|
||||
* systemd: Type=simple openrc: command_background=false
|
||||
* s6: type=longrun dinit: type=process
|
||||
*
|
||||
* "forking" — process daemonises itself; init tracks the forked PID.
|
||||
* systemd: Type=forking openrc: command_background=true
|
||||
* s6: type=longrun dinit: type=bgprocess
|
||||
*
|
||||
* "notify" — foreground process that signals readiness (sd_notify).
|
||||
* systemd: Type=notify openrc: command_background=true
|
||||
* s6: type=longrun dinit: type=process
|
||||
*
|
||||
* "oneshot" — runs once and exits (startup tasks, database migrations).
|
||||
* systemd: Type=oneshot openrc: command_background=false
|
||||
* s6: type=oneshot dinit: type=scripted
|
||||
*
|
||||
* "longrun" — long-running supervised process (s6/runit idiom).
|
||||
* systemd: Type=simple openrc: command_background=true
|
||||
* s6: type=longrun dinit: type=process
|
||||
*
|
||||
* The backend generators handle all translation. Package authors only
|
||||
* need to pick the semantic type that describes their daemon's behaviour.
|
||||
*/
|
||||
package "foo" {
|
||||
const version = "1.2.3"
|
||||
@@ -8,7 +53,8 @@ package "foo" {
|
||||
sha256 = "e127a709cba24c76de8936cb7083dd768f28cd37eb010492e2f19b71eb1294e4"
|
||||
license = "MIT"
|
||||
|
||||
provides = ["libfoo.so.1", "foo"]
|
||||
provides = ["libfoo.so.1", "foo"]
|
||||
conflicts = [] // packages this cannot coexist with (e.g. ["eudev"] if this were systemd)
|
||||
|
||||
patches = [
|
||||
{
|
||||
@@ -60,18 +106,19 @@ package "foo" {
|
||||
CFLAGS ?= "-g"
|
||||
}
|
||||
|
||||
// --- service ----------------------------------------------------------
|
||||
// Init-agnostic service definition. The `type` field is semantic
|
||||
// ("forking") — the selected init system's backend translates it into
|
||||
// the appropriate native format. If the package ships multiple
|
||||
// services, use named blocks (see examples/postgres.kap).
|
||||
service {
|
||||
runit {
|
||||
exec = "/usr/bin/foo --daemon"
|
||||
type = "forking"
|
||||
user = "foo"
|
||||
}
|
||||
s6 {
|
||||
exec = "/usr/bin/foo"
|
||||
type = "longrun"
|
||||
ports = [80, 443]
|
||||
user = "foo"
|
||||
}
|
||||
exec = "/usr/bin/foo"
|
||||
type = "forking" // daemonises itself
|
||||
user = "foo"
|
||||
ports = [80, 443]
|
||||
description = "Foo web server"
|
||||
after = "network" // ordering hint — systemd After=, OpenRC need, etc.
|
||||
restart = "on-failure" // "always" | "on-failure" | "never"
|
||||
}
|
||||
|
||||
prepare {
|
||||
@@ -90,4 +137,8 @@ package "foo" {
|
||||
install {
|
||||
make DESTDIR=${destdir} install
|
||||
}
|
||||
|
||||
uninstall {
|
||||
make -C build uninstall
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user