users/services: simplify the before/after/wantedBy criteria, to match s6 concepts

This commit is contained in:
Colin 2024-03-21 16:02:06 +00:00
parent c5c37e79ac
commit 16ca71188f
30 changed files with 83 additions and 110 deletions

View File

@ -87,7 +87,7 @@ in
services.abaddon = {
description = "unofficial Discord chat client";
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
command = "abaddon";
};
};

View File

@ -118,9 +118,7 @@ in
services.bonsaid = {
description = "bonsai: programmable input dispatcher";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = "bonsaid -t ${cfg.config.configFile}";
cleanupCommand = "rm -f $XDG_RUNTIME_DIR/bonsai";
};

View File

@ -44,7 +44,7 @@ in
services.gnome-calls = {
# TODO: prevent gnome-calls from daemonizing when started manually
description = "gnome-calls daemon to monitor incoming SIP calls";
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
# add --verbose for more debugging
command = "env G_MESSAGES_DEBUG=all gnome-calls --daemon";
};

View File

@ -27,10 +27,7 @@
services.conky = {
description = "conky dynamic desktop background";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ]; # propagate stop/restart signal from graphical-session to this unit
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = "conky";
};
};

View File

@ -34,8 +34,7 @@ in
services.dconf = {
description = "dconf configuration database/server";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = "${lib.getLib cfg.package}/libexec/dconf-service";
};

View File

@ -68,9 +68,7 @@ in
services.dino = {
description = "dino XMPP client";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ];
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
# audio buffering; see: <https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/FAQ#pipewire-buffering-explained>
# dino defaults to 10ms mic buffer, which causes underruns, which Dino handles *very* poorly

View File

@ -57,8 +57,7 @@ in
services.dissent = {
description = "dissent Discord client";
after = [ "graphical-session.target" ];
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
command = "dissent";
};
};

View File

@ -97,9 +97,7 @@
services.fcitx5 = {
description = "fcitx5: input method (IME) for emoji/internationalization";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = "fcitx5";
};

View File

@ -96,7 +96,7 @@ in
services.feedbackd = {
description = "feedbackd audio/vibration/led controller";
wantedBy = [ "default.target" ]; #< should technically be `sound.target`, but that doesn't seem to get auto-started?
partOf = [ "sound" ];
command = lib.concatStringsSep " " ([
"env"
"G_MESSAGES_DEBUG=all"

View File

@ -68,9 +68,7 @@ in
services.fractal = {
description = "fractal Matrix client";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ];
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
# env "G_MESSAGES_DEBUG=all"
command = "fractal";

View File

@ -87,9 +87,7 @@ in
services.geary = {
description = "geary email client";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ];
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
command = "geary";
};
};

View File

@ -26,9 +26,9 @@
fs.".local/share/keyrings/default" = {
file.text = "Default_keyring.keyring"; #< no trailing newline
# wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
"gnome-keyring.service" # TODO: sane.programs should declare this dependency for us
];
# wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
# "gnome-keyring.service" # TODO: sane.programs should declare this dependency for us
# ];
};
# N.B.: certain keyring names have special significance
# `login.keyring` is forcibly encrypted to the user's password, so that pam gnome-keyring can unlock it on login.
@ -41,15 +41,14 @@
lock-after=false
'';
# wantedBy = [ config.sane.fs."${config.sane.persist.stores.private.origin}".unit ];
wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
"gnome-keyring.service"
];
# wantedBeforeBy = [ #< don't create this as part of `multi-user.target`
# "gnome-keyring.service"
# ];
};
services.gnome-keyring = {
description = "gnome-keyring-daemon: secret provider";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = let
gkr-start = pkgs.writeShellScriptBin "gnome-keyring-daemon-start" ''
mkdir -m 0700 -p $XDG_RUNTIME_DIR/keyring

View File

@ -53,7 +53,7 @@
# on environment.packages, but then logs are blackholed.
services.mako = {
description = "mako desktop notification daemon";
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = "${config.sane.programs.mako.package}/bin/mako";
};
};

View File

@ -27,7 +27,7 @@ in
services.ntfy-sub = {
description = "listen for push-notifications";
wantedBy = lib.mkIf cfg.config.autostart [ "default.target" ];
partOf = lib.mkIf cfg.config.autostart [ "default" ];
command = let
sub = pkgs.writeShellScriptBin "ntfy-sub" ''
topic=$(cat ~/.config/ntfy-sh/topic)

View File

@ -30,8 +30,7 @@ in
services.pipewire = {
description = "pipewire: multimedia service";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "sound" ];
# env PIPEWIRE_LOG_SYSTEMD=false"
# env PIPEWIRE_DEBUG"*:3,mod.raop*:5,pw.rtsp-client*:5"
command = "pipewire";
@ -43,8 +42,8 @@ in
};
services.pipewire-pulse = {
description = "pipewire-pulse: Pipewire compatibility layer for PulseAudio clients";
after = [ "pipewire.service" ];
wantedBy = [ "pipewire.service" ];
depends = [ "pipewire" ];
partOf = [ "sound" ];
command = "pipewire-pulse";
pollReadyCommand = pkgs.writeShellScript "pipewire-pulse-wait-started" ''
[ -e "$XDG_RUNTIME_DIR/pulse/native" ] && \

View File

@ -8,7 +8,7 @@
services.playerctld = {
description = "playerctl daemon to keep track of which MPRIS players were recently active";
documentation = [ "https://github.com/altdesktop/playerctl/issues/161" ];
wantedBy = [ "default.target" ]; #< TODO: maybe better to zero `wantedBy` here and have the specific consumers (e.g. swaync) explicitly depend on this.
partOf = [ "default" ]; #< TODO: maybe better to zero `wantedBy` here and have the specific consumers (e.g. swaync) explicitly depend on this.
command = "playerctld";
# serviceConfig.BusName = "org.mpris.MediaPlayer2.Player";
};

View File

@ -46,9 +46,8 @@ in
services.signal-desktop = {
description = "signal-desktop Signal Messenger client";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ];
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
# depends = [ "graphical-session" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
# for some reason the --ozone-platform-hint=auto flag fails when signal-desktop is launched from a service
command = "env NIXOS_OZONE_WL=1 signal-desktop";

View File

@ -31,7 +31,7 @@ in
services.sway-autoscaler = {
description = "adjust global desktop scale to match the activate application";
wantedBy = lib.mkIf cfg.config.autostart [ "graphical-session.target" ];
partOf = lib.mkIf cfg.config.autostart [ "graphical-session" ];
command = lib.escapeShellArgs [
"env"
"SWAY_DEFAULT_SCALE=${builtins.toString cfg.config.defaultScale}"

View File

@ -253,7 +253,7 @@ in
services.sway = {
description = "sway: tiling wayland desktop environment";
wantedBy = [ "default.target" ];
partOf = [ "default" ];
command = "sway";
};
};

View File

@ -54,8 +54,7 @@ in
services.swayidle = {
description = "swayidle: perform actions when sway session is idle";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
command = lib.escapeShellArgs (
[

View File

@ -471,12 +471,8 @@ in
# swaync ships its own service, but i want to add `environment` variables and flags for easier debugging.
# seems that's not possible without defining an entire nix-native service (i.e. this).
description = "swaynotificationcenter (swaync) desktop notification daemon";
after = [
"graphical-session.target"
"pipewire-pulse.service" #< TODO: else it will NEVER see the pulse socket in its sandbox
];
# partOf = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
depends = [ "sound" ]; #< TODO: else it will NEVER see the pulse socket in its sandbox
partOf = [ "graphical-session" ];
command = "env G_MESSAGES_DEBUG=all swaync";
# serviceConfig.BusName = "org.freedesktop.Notifications";

View File

@ -52,8 +52,8 @@
services."sysvol" = {
description = "sysvol: volume monitor/notifier";
after = [ "graphical-session.target" "pipewire-pulse.service" ];
wantedBy = [ "graphical-session.target" ];
depends = [ "sound" ]; #< specifically wireplumber-pulse
partOf = [ "graphical-session" ];
# options:
# -p {0,1,2,3} to attach to top/right/bottom/left screen edge

View File

@ -115,9 +115,7 @@ in
services.waybar = {
description = "swaybar graphical header bar/tray for sway";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
# env G_MESSAGES_DEBUG=all
command = "waybar";

View File

@ -31,9 +31,8 @@
services.wireplumber = {
description = "wireplumber: pipewire Multimedia Service Session Manager";
after = [ "pipewire.service" ];
bindsTo = [ "pipewire.service" ];
wantedBy = [ "pipewire.service" ];
depends = [ "pipewire" ];
partOf = [ "sound" ];
command = "wireplumber";
};
};

View File

@ -15,8 +15,8 @@
services.wvkbd = {
description = "wvkbd: wayland virtual keyboard";
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
# depends = [ "graphical-session" ];
partOf = [ "graphical-session" ];
command = lib.escapeShellArgs [
"env"
# --hidden: send SIGUSR2 to unhide

View File

@ -41,9 +41,8 @@ in
services.xdg-desktop-portal-gtk = {
description = "xdg-desktop-portal-gtk backend (provides graphical dialogs for xdg-desktop-portal)";
after = [ "graphical-session.target" ];
before = [ "xdg-desktop-portal.service" ];
wantedBy = [ "xdg-desktop-portal.service" ];
# depends = [ "graphical-session" ];
dependencyOf = [ "xdg-desktop-portal" ];
command = "${cfg.package}/libexec/xdg-desktop-portal-gtk";
serviceConfig.BusName = "org.freedesktop.impl.portal.desktop.gtk";

View File

@ -26,9 +26,8 @@ in
services.xdg-desktop-portal-wlr = {
description = "xdg-desktop-portal-wlr backend (provides screenshot functionality for xdg-desktop-portal)";
after = [ "graphical-session.target" ];
before = [ "xdg-desktop-portal.service" ];
wantedBy = [ "xdg-desktop-portal.service" ];
# depends = [ "graphical-session" ];
dependencyOf = [ "xdg-desktop-portal" ];
command = "${cfg.package}/libexec/xdg-desktop-portal-wlr";
serviceConfig.BusName = "org.freedesktop.impl.portal.desktop.wlr";

View File

@ -54,9 +54,7 @@ in
services.xdg-desktop-portal = {
description = "xdg-desktop-portal freedesktop.org portal (URI opener, file chooser, etc)";
after = [ "graphical-session.target" ];
# partOf = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
partOf = [ "graphical-session" ];
# tracking issue for having xdg-desktop-portal locate portals via more standard directories, obviating this var:
# - <https://github.com/flatpak/xdg-desktop-portal/issues/603>
@ -76,9 +74,8 @@ in
# xdg-desktop-portal would *usually* dbus-activate this.
# this service might not strictly be necssary. xdg-desktop-portal does warn if it's not present, though.
description = "xdg-permission-store: lets xdg-desktop-portal know which handlers are 'safe'";
after = [ "graphical-session.target" ];
before = [ "xdg-desktop-portal.service" ];
wantedBy = [ "xdg-desktop-portal.service" ];
# after = [ "graphical-session" ];
dependencyOf = [ "xdg-desktop-portal" ];
command = lib.concatStringsSep " " [
"env"

View File

@ -16,25 +16,21 @@ let
references and links for where to find documentation about this service.
'';
};
after = mkOption {
depends = mkOption {
type = types.listOf types.str;
default = [];
};
bindsTo = mkOption {
dependencyOf = mkOption {
type = types.listOf types.str;
default = [];
};
before = mkOption {
type = types.listOf types.str;
default = [];
};
wantedBy = mkOption {
type = types.listOf types.str;
default = [];
};
wants = mkOption {
partOf = mkOption {
type = types.listOf types.str;
default = [];
description = ''
"bundles" to which this service belongs.
e.g. `partOf = [ "default" ];` describes services which should be started "by default".
'';
};
command = mkOption {

View File

@ -2,7 +2,6 @@
let
logBase = "$HOME/.local/state/s6/logs";
maybe = cond: value: if cond then value else null;
normalizeName = name: lib.removeSuffix ".service" (lib.removeSuffix ".target" name);
# create a derivation whose output is the on-disk representation of some attrset.
# @path: /foo/bar/...
@ -56,22 +55,19 @@ let
# infers the service type from the arguments and creates an attrset usable by `fsToDerivation`.
# also configures the service for logging, if applicable.
serviceToFs = { name, run, finish, depends }: let
name' = normalizeName name;
serviceToFs = { name, run, finish, depends, contents }: let
type = if run != null then "longrun" else "bundle";
logger = serviceToFs' {
name = "logger:${name'}";
consumerFor = name';
run = ''exec s6-log -- T p'${name'}:' "${logBase}/${name'}"'';
name = "logger:${name}";
consumerFor = name;
run = ''exec s6-log -- T p'${name}:' "${logBase}/${name}"'';
type = "longrun";
};
in (serviceToFs' {
inherit type run finish;
name = name';
# TODO: a bundle can have dependencies too!
depends = lib.optionals (type == "longrun") depends;
contents = maybe (type == "bundle") depends;
producerFor = maybe (type == "longrun") "logger:${name'}";
inherit name type run finish;
depends = depends;
contents = maybe (type == "bundle") contents;
producerFor = maybe (type == "longrun") "logger:${name}";
}) // (lib.optionalAttrs (type == "longrun") logger);
serviceToFs'= {
@ -97,11 +93,11 @@ let
${run} 2>&1
'';
"contents".text = maybe (contents != null) (
lib.concatStringsSep "\n" (builtins.map normalizeName contents)
lib.concatStringsSep "\n" contents
);
# TODO: a bundle can also have dependencies
"dependencies.d".dir = lib.genAttrs
(builtins.map normalizeName depends)
depends
(dep: { text = ""; })
;
"consumer-for".text = maybe (consumerFor != null) consumerFor;
@ -155,8 +151,11 @@ let
inherit name;
run = service.command;
finish = service.cleanupCommand;
depends = service.wants ++ builtins.attrNames (
lib.filterAttrs (_: cfg: lib.elem name cfg.wantedBy || lib.elem "${name}.service" cfg.wantedBy) services
depends = service.depends ++ builtins.attrNames (
lib.filterAttrs (_: cfg: lib.elem name cfg.dependencyOf) services
);
contents = builtins.attrNames (
lib.filterAttrs (_: cfg: lib.elem name cfg.partOf) services
);
})
services
@ -164,19 +163,28 @@ let
# 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).
# map them onto s6 "bundles". their contents are determined via finding every other service which declares itself to be `partOf` this one.
implicitServices = {
"default.target" = {
"default" = {
command = null;
cleanupCommand = null;
wants = [];
wantedBy = [];
depends = [];
dependencyOf = [];
partOf = [];
};
"graphical-session.target" = {
"graphical-session" = {
command = null;
cleanupCommand = null;
wants = [];
wantedBy = [];
depends = [];
dependencyOf = [];
partOf = [];
};
"sound" = {
command = null;
cleanupCommand = null;
depends = [];
dependencyOf = [];
partOf = [ "default" ];
};
};
in