/* * foo — a web server with optional SSL and GUI support. * * 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" const source = "https://example.com/foo-${version}.tar.gz" sha256 = "e127a709cba24c76de8936cb7083dd768f28cd37eb010492e2f19b71eb1294e4" license = "MIT" provides = ["libfoo.so.1", "foo"] conflicts = [] // packages this cannot coexist with (e.g. ["eudev"] if this were systemd) patches = [ { url = "https://example.com/fix-build.patch" sha256 = "abc123def456" level = 1 }, "local-fix.patch" // local shorthand, no hash ] outputs = ["bin", "lib", "dev"] depends = [ { name = "zlib", version = ">=1.2,<2.0" }, { name = "openssl", feature = "ssl" }, { name = "gtk", feature = "gui", version = ">=3" }, "gettext:lib" // name:output shorthand ] features { ssl = { enabled = true, flag = "--with-ssl-dir=${cfg.ssl_dir}" } gui = { enabled = false, flag = "--enable-gui" } drivers = { enabled = true, force = true } debug = false } config { // Written once, left alone on rebuild if the user edits it. file "etc/foo.conf" mode = "default" { hostname = ${cfg.hostname !} // required — user must set listen_port = ${cfg.port ? 8080} // optional, default 8080 ssl_enabled = ${cfg.ssl ? true} // optional, default true } // Always overwritten on rebuild. file "etc/log.conf" mode = "replace" { log_level = ${cfg.log_level ? info} log_path = ${cfg.log_path ? /var/log/foo} } // Three-way diff on rebuild. file "etc/limits.conf" mode = "merge" { max_connections = ${cfg.max_conn ? 1024} } } env { CFLAGS = "-O2 -march=native" LDFLAGS = "-Wl,--as-needed" 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 { 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 { patch "fix-build.patch" } build { ./configure --prefix=${prefix} ${feature.ssl} ${feature.gui} make -j${jobs} } check { make check } install { make DESTDIR=${destdir} install } uninstall { make -C build uninstall } }