modules/users: prototype s6 integration: ~/.config/s6/{sources,compiled}
This commit is contained in:
parent
787e6af646
commit
a5c36d39f4
|
@ -241,6 +241,7 @@ let
|
|||
in
|
||||
{
|
||||
imports = [
|
||||
./s6-rc.nix
|
||||
./systemd.nix
|
||||
];
|
||||
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
{ lib, pkgs, ... }:
|
||||
let
|
||||
normalizeName = name: lib.removeSuffix ".service" (lib.removeSuffix ".target" name);
|
||||
|
||||
# infers the service type from the arguments and dispatches appropriately
|
||||
genService = { name, run, depends }: if run != null then
|
||||
genService' (normalizeName name) "longrun" depends [
|
||||
(pkgs.writeTextFile {
|
||||
name = "s6-${name}-run";
|
||||
destination = "/${normalizeName name}/run";
|
||||
text = run;
|
||||
})
|
||||
]
|
||||
else
|
||||
# TODO: a bundle can totally have dependencies. i can't just map them *all* to contents.
|
||||
# genService' (normalizeName name) "bundle" [] (
|
||||
# (builtins.map
|
||||
# (d: pkgs.writeTextFile {
|
||||
# name = "s6-${name}-contains-${d}";
|
||||
# destination = "/${normalizeName name}/contents.d/${normalizeName d}";
|
||||
# text = "";
|
||||
# })
|
||||
# depends
|
||||
# ) ++ [
|
||||
# # in case the bundle has no contents, ensure `contents.d` still gets made
|
||||
# (pkgs.runCommandLocal "s6-${name}-contains.d" {} ''
|
||||
# mkdir -p $out/"${normalizeName name}"/contents.d
|
||||
# '')
|
||||
# ]
|
||||
# )
|
||||
genService' (normalizeName name) "bundle" [] [
|
||||
(pkgs.writeTextFile {
|
||||
name = "s6-${name}-contents";
|
||||
destination = "/${normalizeName name}/contents";
|
||||
text = lib.concatStringsSep "\n" (builtins.map normalizeName depends);
|
||||
})
|
||||
]
|
||||
;
|
||||
genService' = name: type: depends: others: pkgs.symlinkJoin {
|
||||
name = "s6-${name}";
|
||||
paths = others ++ [
|
||||
(pkgs.writeTextFile {
|
||||
name = "s6-${name}-type";
|
||||
destination = "/${name}/type";
|
||||
text = type;
|
||||
})
|
||||
] ++ builtins.map
|
||||
(d: pkgs.writeTextFile {
|
||||
name = "s6-${name}-depends-${d}";
|
||||
destination = "/${name}/dependencies.d/${normalizeName d}";
|
||||
text = "";
|
||||
})
|
||||
depends;
|
||||
};
|
||||
|
||||
# create a directory, containing N subdirectories:
|
||||
# - svc-a/
|
||||
# - type
|
||||
# - run
|
||||
# - svc-b/
|
||||
# - type
|
||||
# - run
|
||||
# - ...
|
||||
genServices = svcs: pkgs.symlinkJoin {
|
||||
name = "s6-user-services";
|
||||
paths = builtins.map genService svcs;
|
||||
};
|
||||
|
||||
# output is a directory containing:
|
||||
# - db
|
||||
# - lock
|
||||
# - n
|
||||
# - resolve.cdb
|
||||
# - servicedirs/
|
||||
# - svc-a/
|
||||
# - svc-b/
|
||||
# - ...
|
||||
#
|
||||
# this can then be used by s6-rc-init, like:
|
||||
# s6-svscan scandir &
|
||||
# s6-rc-init -c $compiled -l $PWD/live -d $PWD/scandir
|
||||
# s6-rc -l $PWD/live start svc-a
|
||||
compileServices = sources: with pkgs; stdenv.mkDerivation {
|
||||
name = "s6-user-services";
|
||||
src = sources;
|
||||
nativeBuildInputs = [ s6-rc ];
|
||||
buildPhase = ''
|
||||
s6-rc-compile $out $src
|
||||
'';
|
||||
};
|
||||
|
||||
# transform the `user.services` attrset into a s6 services list.
|
||||
s6SvcsFromConfigServices = services: lib.mapAttrsToList
|
||||
(name: service: {
|
||||
inherit name;
|
||||
run = service.serviceConfig.ExecStart;
|
||||
depends = service.wants ++ builtins.attrNames (
|
||||
lib.filterAttrs (_: cfg: lib.elem name cfg.wantedBy) services
|
||||
);
|
||||
})
|
||||
services
|
||||
;
|
||||
|
||||
# in the systemd service management, these targets are implicitly defined and used
|
||||
# to accomplish something like run-levels, or service groups.
|
||||
# map them onto s6 "bundles". their contents are determined via reverse dependency mapping (`wantedBy` of every other service).
|
||||
implicitServices = {
|
||||
"default.target" = {
|
||||
serviceConfig.ExecStart = null;
|
||||
wants = [];
|
||||
wantedBy = [];
|
||||
};
|
||||
"graphical-session.target" = {
|
||||
serviceConfig.ExecStart = null;
|
||||
wants = [];
|
||||
wantedBy = [];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.sane.users = with lib; mkOption {
|
||||
type = types.attrsOf (types.submodule ({ config, ...}: let
|
||||
sources = genServices (s6SvcsFromConfigServices (implicitServices // config.services));
|
||||
in {
|
||||
fs.".config/s6/sources".symlink.target = sources;
|
||||
fs.".config/s6/compiled".symlink.target = compileServices sources;
|
||||
}));
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue