modules: users: split services -> fs mapping into own `systemd.nix` file

This commit is contained in:
Colin 2024-03-16 23:48:30 +00:00
parent ac04dc639f
commit 4fd2db4e51
2 changed files with 81 additions and 62 deletions

View File

@ -1,4 +1,4 @@
{ config, lib, options, sane-lib, utils, ... }:
{ config, lib, options, sane-lib, ... }:
let
sane-user-cfg = config.sane.user;
@ -222,67 +222,6 @@ let
done
'';
}
{
fs = lib.mkMerge (lib.mapAttrsToList (serviceName: value:
let
# see: <repo:nixos/nixpkgs:nixos/lib/utils.nix>
# see: <repo:nix-community/home-manager:modules/systemd.nix>
cleanName = utils.systemdUtils.lib.mkPathSafeName serviceName;
generatedUnit = utils.systemdUtils.lib.serviceToUnit serviceName {
inherit (value)
requiredBy
script
wantedBy
;
serviceConfig = lib.filterAttrs (_: v: v != null) value.serviceConfig;
unitConfig = {
inherit (value.unitConfig)
ConditionEnvironment
;
After = value.after;
Before = value.before;
BindsTo = value.bindsTo;
Description = value.description;
Documentation = value.documentation;
Wants = value.wants;
};
environment = {
# clear PATH to allow inheriting it from environment.
# otherwise, nixos would force it to `systemd.globalEnvironment.PATH`, which is mostly tools like sed/find/etc.
# clearing PATH here allows user services to inherit whatever PATH the graphical session sets
# (see `dbus-update-activation-environment` call in ~/.config/sway/config),
# which is critical to making it so user services can see user *programs*/packages.
#
# note that systemd provides no way to *append* to the PATH, only to override it (or not).
# nor do they intend to ever support that:
# - <https://github.com/systemd/systemd/issues/1082>
PATH = null;
} // (value.environment or {});
};
#^ generatedUnit contains keys:
# - text
# - aliases (IGNORED)
# - wantedBy
# - requiredBy
# - enabled (IGNORED)
# - overrideStrategy (IGNORED)
# TODO: error if one of the above ignored fields are set
symlinkData = {
text = generatedUnit.text;
targetName = "${cleanName}.service"; # systemd derives unit name from symlink target
};
serviceEntry = {
".config/systemd/user/${serviceName}.service".symlink = symlinkData;
};
wants = builtins.map (wantedBy: {
".config/systemd/user/${wantedBy}.wants/${serviceName}.service".symlink = symlinkData;
}) generatedUnit.wantedBy;
requires = builtins.map (requiredBy: {
".config/systemd/user/${requiredBy}.requires/${serviceName}.service".symlink = symlinkData;
}) generatedUnit.requiredBy;
in lib.mkMerge ([ serviceEntry ] ++ wants ++ requires)
) config.services);
}
];
});
processUser = user: defn:
@ -305,6 +244,10 @@ let
};
in
{
imports = [
./systemd.nix
];
options = with lib; {
sane.users = mkOption {
type = types.attrsOf userModule;

76
modules/users/systemd.nix Normal file
View File

@ -0,0 +1,76 @@
{ lib, utils, ... }:
let
# see: <repo:nixos/nixpkgs:nixos/lib/utils.nix>
# see: <repo:nix-community/home-manager:modules/systemd.nix>
mkUnit = serviceName: value: utils.systemdUtils.lib.serviceToUnit serviceName {
inherit (value)
requiredBy
script
wantedBy
;
serviceConfig = lib.filterAttrs (_: v: v != null) value.serviceConfig;
unitConfig = {
inherit (value.unitConfig)
ConditionEnvironment
;
After = value.after;
Before = value.before;
BindsTo = value.bindsTo;
Description = value.description;
Documentation = value.documentation;
Wants = value.wants;
};
environment = {
# clear PATH to allow inheriting it from environment.
# otherwise, nixos would force it to `systemd.globalEnvironment.PATH`, which is mostly tools like sed/find/etc.
# clearing PATH here allows user services to inherit whatever PATH the graphical session sets
# (see `dbus-update-activation-environment` call in ~/.config/sway/config),
# which is critical to making it so user services can see user *programs*/packages.
#
# note that systemd provides no way to *append* to the PATH, only to override it (or not).
# nor do they intend to ever support that:
# - <https://github.com/systemd/systemd/issues/1082>
PATH = null;
} // (value.environment or {});
};
in
{
# create fs entries for every service, in the systemd user dir.
options.sane.users = with lib; mkOption {
type = types.attrsOf (types.submodule ({ config, ...}: {
fs = lib.concatMapAttrs
(serviceName: value: let
cleanName = utils.systemdUtils.lib.mkPathSafeName serviceName;
generatedUnit = mkUnit serviceName value;
#^ generatedUnit contains keys:
# - text
# - aliases (IGNORED)
# - wantedBy
# - requiredBy
# - enabled (IGNORED)
# - overrideStrategy (IGNORED)
# TODO: error if one of the above ignored fields are set
symlinkData = {
text = generatedUnit.text;
targetName = "${cleanName}.service"; # systemd derives unit name from symlink target
};
serviceEntry = {
".config/systemd/user/${serviceName}.service".symlink = symlinkData;
};
wants = builtins.map (wantedBy: {
".config/systemd/user/${wantedBy}.wants/${serviceName}.service".symlink = symlinkData;
}) generatedUnit.wantedBy;
requires = builtins.map (requiredBy: {
".config/systemd/user/${requiredBy}.requires/${serviceName}.service".symlink = symlinkData;
}) generatedUnit.requiredBy;
in lib.mergeAttrsList
([ serviceEntry ]
++ wants
++ requires
)
)
config.services
;
}));
};
}