{ pkgs, lib, config, ... }: let inherit (builtins) typeOf; inherit (pkgs) linkFarm writeScript runCommand; inherit (lib) concatStringsSep mapAttrsToList mkOption mkDefault types filterAttrsRecursive foldr; s6EntryTypes = { int = v: s6Entry (toString v); bool = v: s6Entry ""; string = writeScript "s6-file"; set = v: linkFarm "s6-dir" (mapAttrsToList (name: value: { inherit name; path = s6Entry value; }) v); list = v: s6Entry (concatStringsSep "\n" v); }; s6Entry = v: s6EntryTypes.${typeOf v} v; s6RcCompile = { uids ? null, gids ? null, fdhuser ? null }: source: runCommand "s6-rc-compile" {} '' ${config.s6.rc.package}/bin/s6-rc-compile \ ${if (uids != null) then "-u ${concatStringsSep "," uids}" else ""} \ ${if (gids != null) then "-g ${concatStringsSep "," gids}" else ""} \ ${if (fdhuser != null) then "-h ${fdhuser}" else ""} \ $out \ ${lib.traceVal (toString (s6Entry (filterAttrsRecursive (n: v: v != null) source)))} ''; in { options = { s6.rc.package = mkOption { default = pkgs.s6-rc; description = '' The package to look for the s6-rc, s6-rc-compile, and s6-rc-init commands in. ''; }; s6.rc.initTimeout = mkOption { default = null; description = '' Milliseconds to wait for all s6-supervise processes to start up before giving up. ''; }; s6.rc.timeout = mkOption { default = null; description = '' Milliseconds to wait for s6-rc to transition to the up state. ''; }; s6.rc.services = mkOption { description = '' Attribute set of available services. Names correspond to service directory names on disk. Values are attribute sets of service properties, which are then transformed into the directory structure expected by s6-rc-compile. ''; example = { foo = { type = "oneshot"; up = "echo hello world"; dependencies = [ "bar" "baz" ]; env = { a = "b"; }; }; }; type = with types; attrsOf (submodule { options = { type = mkOption { description = "type"; type = enum [ "bundle" "oneshot" "longrun" ]; }; contents = mkOption { description = "contents"; type = nullOr (listOf str); default = null; }; timeout-up = mkOption { description = "timeout-up"; type = nullOr ints.unsigned; default = null; }; timeout-down = mkOption { description = "timeout-down"; type = nullOr ints.unsigned; default = null; }; dependencies = mkOption { description = "dependencies"; type = nullOr (listOf str); default = null; }; up = mkOption { description = "up"; type = nullOr str; default = null; }; down = mkOption { description = "down"; type = nullOr str; default = null; }; run = mkOption { description = "run"; type = nullOr str; default = null; }; finish = mkOption { description = "finish"; type = nullOr str; default = null; }; notification-fd = mkOption { description = "notification-fd"; type = nullOr ints.unsigned; default = null; }; timeout-kill = mkOption { description = "timeout-kill"; type = nullOr ints.unsigned; default = null; }; timeout-finish = mkOption { description = "timeout-finish"; type = nullOr ints.unsigned; default = null; }; nosetsid = mkOption { description = "nosetsid"; type = nullOr bool; default = null; }; data = mkOption { description = "data"; type = nullOr (attrsOf str); default = null; }; env = mkOption { description = "env"; type = nullOr (attrsOf str); default = null; }; producer-for = mkOption { description = "producer-for"; type = nullOr str; default = null; }; consumer-for = mkOption { description = "consumer-for"; type = nullOr (listOf str); default = null; }; pipeline-name = mkOption { description = "pipeline-name"; type = nullOr str; default = null; }; }; }); }; s6.rc.live = mkOption { default = "/run/s6-rc"; description = '' Where to store the s6-rc live state. ''; }; s6.rc.prefix = mkOption { default = ""; description = '' Unique prefix to apply to all service names when they are added to the supervisor, for disambiguation. ''; }; s6.rc.uids = mkOption { default = null; description = '' IDs of users who should be allowed to start and stop services controlled by this instance of s6-rc. Default: only root. ''; }; s6.rc.gids = mkOption { default = null; description = '' IDs of groups who should be allowed to start and stop services controlled by this instance of s6-rc. Default: only root. ''; }; s6.rc.fdhuser = mkOption { default = null; description = '' User for the s6-fileholder-daemon process to run as. Defaults to root, the owner of the supervision tree. ''; }; s6.rc.initBundle = mkOption { default = "ok-all"; description = '' Name of the top bundle to be brought up at system startup. ''; }; s6.rc.initCommand = mkOption { description = '' The s6-rc-init command line to be executed by rc.init, prior to running s6-rc. ''; }; s6.rc.command = mkOption { description = '' The s6-rc command line to be executed by rc.init, after running s6-rc-init. ''; }; }; config = { s6.rc.services.${config.s6.rc.initBundle} = { type = "bundle"; contents = []; }; s6.rc.initCommand = mkDefault '' ${config.s6.rc.package}/bin/s6-rc-init \ -c ${s6RcCompile { inherit (config.s6.rc) uids gids fdhuser; } config.s6.rc.services} \ -l ${config.s6.rc.live} \ -p "${config.s6.rc.prefix}" \ ${if (config.s6.rc.initTimeout != null) then "-t ${toString config.s6.rc.initTimeout}" else ""} \ /run/service ''; s6.rc.command = mkDefault '' ${config.s6.rc.package}/bin/s6-rc \ -l ${config.s6.rc.live} \ change \ ${if (config.s6.rc.timeout != null) then "-t ${toString config.s6.rc.timeout}" else ""} \ ${config.s6.rc.initBundle} ''; }; }