port service manager to s6

still a lot of cleanup to do (e.g. support dbus service types), but it boots to a usable desktop
This commit is contained in:
Colin 2024-03-18 02:02:24 +00:00
parent 63af94383b
commit 2336767059
6 changed files with 126 additions and 37 deletions

View File

@ -79,6 +79,8 @@ in
"powertop"
"pstree"
"ripgrep"
"s6"
"s6-rc" # service manager
"screen"
"smartmontools" # smartctl
# "socat"
@ -763,6 +765,9 @@ in
rustc = {};
s6 = {};
s6-rc = {};
sane-open-desktop.sandbox.enable = false; #< trivial script, and all our deps are sandboxed
sane-open-desktop.suggestedPrograms = [
"gdbus"

View File

@ -16,7 +16,10 @@ let
export XDG_CURRENT_DESKTOP=sway
echo "launching sway (sway.desktop)..." | ${systemd-cat} --identifier=sway
exec ${configuredSway}/bin/sway 2>&1 | ${systemd-cat} --identifier=sway
# delete DISPLAY-related vars from env before launch, else sway will try to connect to a remote display.
# (consider: nested sway sessions, where sway actually has a reason to read these)
exec env -u DISPLAY -u WAYLAND_DISPLAY \
${configuredSway}/bin/sway 2>&1 | ${systemd-cat} --identifier=sway
'';
in
pkgs.symlinkJoin {
@ -194,6 +197,7 @@ in
# bind ALL of ~/.config/sway into the sandbox instead of just the individual configs.
# this way `swaymsg -- reload` can work even if the fd for ~/.config/sway/config changes.
".config/sway"
".config/s6"
];
sandbox.extraConfig = [
"--sane-sandbox-keep-namespace" "pid"
@ -218,26 +222,50 @@ in
xwayland = if config.sane.programs.xwayland.enabled then "enable" else "disable";
};
services.sway-session = {
description = "sway-session: active iff sway desktop environment is baseline operational";
documentation = [
"https://github.com/swaywm/sway/issues/7862"
"https://github.com/alebastr/sway-systemd"
];
env.XDG_CURRENT_DESKTOP = "sway";
# TODO: don't hardcode user id!
env.SWAYSOCK = "/run/user/1000/sway-ipc.sock";
# TODO: ensure this is reliable? might not work across sway restarts, etc.
env.DISPLAY = ":0";
env.WAYLAND_DISPLAY = "wayland-1";
# we'd like to start graphical-session after sway is ready, but it's marked `RefuseManualStart` because Lennart.
# instead, create `sway-session.service` which `bindsTo` `graphical-session.target`.
# we can manually start `sway-session`, and the `bindsTo` means that it will start `graphical-session`,
# and then track `graphical-session`s state (that is: it'll stop when graphical-session stops).
#
# additionally, set `ConditionEnvironment` to guard that the sway environment variables *really have* been imported into systemd.
unitConfig.ConditionEnvironment = "SWAYSOCK";
# requiredBy = [ "graphical-session.target" ];
before = [ "graphical-session.target" ];
bindsTo = [ "graphical-session.target" ];
# services.sway-session = {
# description = "sway-session: active iff sway desktop environment is baseline operational";
# documentation = [
# "https://github.com/swaywm/sway/issues/7862"
# "https://github.com/alebastr/sway-systemd"
# ];
# # we'd like to start graphical-session after sway is ready, but it's marked `RefuseManualStart` because Lennart.
# # instead, create `sway-session.service` which `bindsTo` `graphical-session.target`.
# # we can manually start `sway-session`, and the `bindsTo` means that it will start `graphical-session`,
# # and then track `graphical-session`s state (that is: it'll stop when graphical-session stops).
# #
# # additionally, set `ConditionEnvironment` to guard that the sway environment variables *really have* been imported into systemd.
# unitConfig.ConditionEnvironment = "SWAYSOCK";
# # requiredBy = [ "graphical-session.target" ];
# before = [ "graphical-session.target" ];
# bindsTo = [ "graphical-session.target" ];
# serviceConfig = {
# ExecStart = "${pkgs.coreutils}/bin/true";
# Type = "oneshot";
# RemainAfterExit = true;
# };
# };
# services.sway-session = {
# description = "sway-session: meta-service for everything wanted by sway (after launch)";
# wants = [ "graphical-session.target" ];
# };
services.sway = {
description = "sway: launch it";
wantedBy = [ "default.target" ];
serviceConfig = {
ExecStart = "${pkgs.coreutils}/bin/true";
ExecStart = "${cfg.package}/bin/sway";
# ExecStart = "${lib.getBin pkgs.glib}/bin/gio launch sway.desktop";
# ExecStart = "${pkgs.sane-open-desktop}/bin/sane-open-desktop sway.desktop";
Type = "oneshot";
RemainAfterExit = true;
};

View File

@ -258,6 +258,10 @@ exec --no-startup-id dbus-update-activation-environment --systemd PATH XDG_DATA_
# signal to systemd that sway is active,
# and therefore let it start any downstream services (e.g. apps that would like to auto-start)
# see `systemctl --user cat sway-session` for links to docs
exec --no-startup-id systemctl start --user sway-session.service
# exec --no-startup-id systemctl start --user sway-session.service
# TODO: remove this. likely, the variables above can/should be set *before* launching the service manager at all.
# and if need be we can replace this line with a "notify ready" signal to the service manager instead.
exec --no-startup-id s6-rc -l $HOME/.config/s6/live start graphical-session
@extra_lines@

View File

@ -119,15 +119,28 @@ in
};
};
# lib.mkAfter so that launching the DE happens *after* any other .profile setup.
# alternatively, we could recurse: exec a new login shell with some env-var signalling to not launch the DE,
# run with `-c "{cfg.afterLogin}"`
fs.".profile".symlink.text = lib.mkAfter ''
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN.
if [ "$(tty)" = "/dev/${tty}" ]; then
${tryLaunchDefaultDesktop}/bin/tryLaunchDefaultDesktop
fi
'';
fs.".profile".symlink.text = lib.mkMerge [
(lib.mkBefore ''
primarySessionCommands=()
initPrimarySession() {
for c in "''${primarySessionCommands[@]}"; do
eval "$c"
done
}
'')
# lib.mkAfter so that launching the DE happens *after* any other .profile setup.
(lib.mkAfter ''
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN.
if [ "$(tty)" = "/dev/${tty}" ]; then
if (( ''${#primarySessionCommands[@]} )); then
echo "launching primary session commands in ${builtins.toString cfg.config.delay}s: ''${primarySessionCommands[*]}"
# if the `sleep` call here is `Ctrl+C'd`, then it'll exit false and the desktop isn't launched.
sleep ${builtins.toString cfg.config.delay} && \
initPrimarySession
fi
fi
'')
];
# N.B.: this sandboxing applies to `unl0kr` itself -- the on-screen-keyboard;
# NOT to the wrapper which invokes `login`.

View File

@ -59,19 +59,19 @@ in
wantedBy = [ "graphical-session.target" ];
serviceConfig = {
ExecStart="${cfg.package}/libexec/xdg-desktop-portal";
# 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>
# i can actually almost omit it today; problem is that if you don't set it it'll look for `sway-portals.conf` in ~/.config/xdg-desktop-portal
# but then will check its *own* output dir for {gtk,wlr}.portal.
# arguable if that's a packaging bug, or limitation...
ExecStart=''env XDG_DESKTOP_PORTAL_DIR="$HOME/.config/xdg-desktop-portal" ${cfg.package}/libexec/xdg-desktop-portal'';
Type = "dbus";
BusName = "org.freedesktop.portal.Desktop";
Restart = "always";
RestartSec = "10s";
};
# 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>
# i can actually almost omit it today; problem is that if you don't set it it'll look for `sway-portals.conf` in ~/.config/xdg-desktop-portal
# but then will check its *own* output dir for {gtk,wlr}.portal.
# arguable if that's a packaging bug, or limitation...
environment.XDG_DESKTOP_PORTAL_DIR = "%E/xdg-desktop-portal";
# environment.XDG_DESKTOP_PORTAL_DIR = "%E/xdg-desktop-portal";
# environment.G_MESSAGES_DEBUG = "all"; #< also applies to all apps launched by the portal
};

View File

@ -103,7 +103,7 @@ let
inherit name;
run = service.serviceConfig.ExecStart;
depends = service.wants ++ builtins.attrNames (
lib.filterAttrs (_: cfg: lib.elem name cfg.wantedBy) services
lib.filterAttrs (_: cfg: lib.elem name cfg.wantedBy || lib.elem "${name}.service" cfg.wantedBy) services
);
})
services
@ -131,7 +131,46 @@ in
sources = genServices (s6SvcsFromConfigServices (implicitServices // config.services));
in {
fs.".config/s6/sources".symlink.target = sources;
fs.".config/s6/compiled".symlink.target = compileServices sources;
# N.B.: `compiled` needs to be writable (for locks -- maybe i can use symlinks to dodge this someday),
# so write this nearby and copy it over to `compiled` later
fs.".config/s6/compiled-static".symlink.target = compileServices sources;
fs.".profile".symlink.text = ''
function startS6() {
local S6_TARGET="''${1:-default}"
local COMPILED=$HOME/.config/s6/compiled
local LIVE=$HOME/.config/s6/live
local SCANDIR=$HOME/.config/s6/scandir
rm -rf $SCANDIR
mkdir $SCANDIR
s6-svscan $SCANDIR &
local SVSCAN=$!
# the scandir is just links back into the compiled dir,
# so the compiled dir therefore needs to be writable:
rm -rf $COMPILED
cp --dereference -R $COMPILED-static $COMPILED
chmod -R 0700 $COMPILED
s6-rc-init -c $COMPILED -l $LIVE -d $SCANDIR
# echo default: deps
# s6-rc-db -c $COMPILED contents default
# echo graphical-session: deps
# s6-rc-db -c $COMPILED contents graphical-session
if [ -n "$S6_TARGET" ]; then
s6-rc -l $LIVE start "$S6_TARGET"
fi
echo "s6 initialized: Ctrl+C to stop"
wait $SVSCAN
}
primarySessionCommands+=('startS6 &')
'';
}));
};
}