mirror of
https://github.com/LnL7/nix-darwin.git
synced 2025-03-31 04:04:45 +00:00
launchd: move userLaunchd
to system activation
I’m not *completely* certain that this handles user agents correctly. There is a deprecated command, `launchctl asuser`, that executes a command in the Mach bootstrap context of another user`. <https://scriptingosx.com/2020/08/running-a-command-as-another-user/> claims that this is required when loading and unloading user agents, but I haven’t tested this. Our current launchd agent logic is pretty weird and broken already anyway, so unless this actively regresses things I’d lean towards keeping it like this until we can move over entirely to `launchctl bootstrap`/`launchctl kickstart`, which aren’t deprecated and can address individual users directly. Someone should definitely test it more extensively than I have, though.
This commit is contained in:
parent
73a6ceda1b
commit
56d8208c45
39 changed files with 106 additions and 23 deletions
|
@ -1,6 +1,8 @@
|
|||
{ config, lib, inputs, pkgs, ... }:
|
||||
|
||||
{
|
||||
system.primaryUser = "lnl";
|
||||
|
||||
system.defaults.NSGlobalDomain.AppleKeyboardUIMode = 3;
|
||||
system.defaults.NSGlobalDomain.ApplePressAndHoldEnabled = false;
|
||||
system.defaults.NSGlobalDomain.InitialKeyRepeat = 10;
|
||||
|
|
|
@ -170,7 +170,16 @@ in
|
|||
|
||||
launchd.user.agents = mkOption {
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule serviceOptions);
|
||||
type = types.attrsOf (types.submodule [
|
||||
serviceOptions
|
||||
({ name, ... }: {
|
||||
options.managedBy = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
internal = true;
|
||||
default = lib.showOption [ "launchd" "user" "agents" name ];
|
||||
};
|
||||
})
|
||||
]);
|
||||
description = ''
|
||||
Definition of per-user launchd agents.
|
||||
|
||||
|
@ -187,6 +196,18 @@ in
|
|||
|
||||
config = {
|
||||
|
||||
system.requiresPrimaryUser =
|
||||
lib.map (
|
||||
name:
|
||||
lib.showOption [
|
||||
"launchd"
|
||||
"user"
|
||||
"envVariables"
|
||||
name
|
||||
]
|
||||
) (attrNames cfg.user.envVariables)
|
||||
++ lib.map ({ managedBy, ... }: managedBy) (attrValues cfg.user.agents);
|
||||
|
||||
environment.launchAgents = mapAttrs' toEnvironmentText cfg.agents;
|
||||
environment.launchDaemons = mapAttrs' toEnvironmentText cfg.daemons;
|
||||
|
||||
|
|
|
@ -253,6 +253,7 @@ in
|
|||
KeepAlive = true;
|
||||
RunAtLoad = true;
|
||||
};
|
||||
managedBy = "services.aerospace.enable";
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
|
@ -126,6 +126,7 @@ in
|
|||
serviceConfig.RunAtLoad = true;
|
||||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.ProcessType = "Interactive";
|
||||
managedBy = "services.chunkwm.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -49,6 +49,7 @@ in {
|
|||
RunAtLoad = true;
|
||||
KeepAlive = true;
|
||||
};
|
||||
managedBy = "services.emacs.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -64,6 +64,7 @@ in
|
|||
StandardErrorPath = cfg.logFile;
|
||||
EnvironmentVariables = {} // (optionalAttrs (cfg.ipfsPath != null) { IPFS_PATH = cfg.ipfsPath; });
|
||||
};
|
||||
managedBy = "services.ipfs.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ in {
|
|||
++ (optionalArg "order" cfg.order);
|
||||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.RunAtLoad = true;
|
||||
managedBy = "services.jankyborders.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ in
|
|||
"${parentAppDir}/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager" "activate"
|
||||
];
|
||||
serviceConfig.RunAtLoad = true;
|
||||
managedBy = "services.karabiner-elements.enable";
|
||||
};
|
||||
|
||||
# We need this to run every reboot as /run gets nuked so we can't put this
|
||||
|
@ -105,6 +106,7 @@ in
|
|||
];
|
||||
serviceConfig.Label = "org.pqrs.karabiner.karabiner_session_monitor";
|
||||
serviceConfig.KeepAlive = true;
|
||||
managedBy = "services.karabiner-elements.enable";
|
||||
};
|
||||
|
||||
environment.userLaunchAgents."org.pqrs.karabiner.agent.karabiner_grabber.plist".source = "${cfg.package}/Library/LaunchAgents/org.pqrs.karabiner.agent.karabiner_grabber.plist";
|
||||
|
|
|
@ -57,6 +57,8 @@ in
|
|||
SockType = "dgram";
|
||||
SockFamily = "IPv4";
|
||||
};
|
||||
|
||||
managedBy = "services.khd.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -47,6 +47,7 @@ in
|
|||
SockType = "dgram";
|
||||
SockFamily = "IPv4";
|
||||
};
|
||||
managedBy = "services.kwm.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -38,6 +38,7 @@ in
|
|||
];
|
||||
|
||||
environment.systemPackages = [ pkgs.lorri ];
|
||||
|
||||
launchd.user.agents.lorri = {
|
||||
command = with pkgs; "${lorri}/bin/lorri daemon";
|
||||
path = with pkgs; [ config.nix.package git gnutar gzip ];
|
||||
|
@ -49,6 +50,7 @@ in
|
|||
StandardErrorPath = cfg.logFile;
|
||||
EnvironmentVariables = { NIX_PATH = "nixpkgs=" + toString pkgs.path; };
|
||||
};
|
||||
managedBy = "services.lorri.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ in {
|
|||
serviceConfig.StartInterval = cfg.startInterval;
|
||||
serviceConfig.StandardErrorPath = "/var/log/offlineimap.log";
|
||||
serviceConfig.StandardOutPath = "/var/log/offlineimap.log";
|
||||
managedBy = "services.offlineimap.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ in
|
|||
serviceConfig.Program = "${cfg.package}/bin/mopidy";
|
||||
serviceConfig.RunAtLoad = true;
|
||||
serviceConfig.KeepAlive = true;
|
||||
managedBy = "services.mopidy.enable";
|
||||
};
|
||||
})
|
||||
(mkIf cfg.mediakeys.enable {
|
||||
|
@ -48,6 +49,7 @@ in
|
|||
serviceConfig.Program = "${cfg.package}/bin/mpdkeys";
|
||||
serviceConfig.RunAtLoad = true;
|
||||
serviceConfig.KeepAlive = true;
|
||||
managedBy = "services.mopidy.mediakeys.enable";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
|
|
@ -363,6 +363,7 @@ in
|
|||
serviceConfig.EnvironmentVariables = {
|
||||
PGDATA = cfg.dataDir;
|
||||
};
|
||||
managedBy = "services.postgresql.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -61,6 +61,7 @@ in
|
|||
${cfg.package}/bin/privoxy /etc/privoxy-config
|
||||
'';
|
||||
serviceConfig.KeepAlive = true;
|
||||
managedBy = "services.privoxy.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ in
|
|||
launchd.user.agents.redis = {
|
||||
command = "${cfg.package}/bin/redis-server /etc/redis.conf";
|
||||
serviceConfig.KeepAlive = true;
|
||||
managedBy = "services.redis.enable";
|
||||
};
|
||||
|
||||
environment.etc."redis.conf".text = ''
|
||||
|
|
|
@ -54,6 +54,7 @@ in
|
|||
++ optionals (cfg.config != "") [ "--config" "${configFile}" ];
|
||||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.RunAtLoad = true;
|
||||
managedBy = "services.sketchybar.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ in
|
|||
++ optionals (cfg.skhdConfig != "") [ "-c" "/etc/skhdrc" ];
|
||||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.ProcessType = "Interactive";
|
||||
|
||||
managedBy = "services.skhd.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -69,6 +69,8 @@ in
|
|||
serviceConfig.EnvironmentVariables = {
|
||||
PATH = "${cfg.package}/bin:${config.environment.systemPath}";
|
||||
};
|
||||
|
||||
managedBy = "services.spacebar.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ in
|
|||
RunAtLoad = true;
|
||||
ThrottleInterval = 30;
|
||||
};
|
||||
managedBy = "services.spotifyd.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ in
|
|||
command = "${cfg.package}/bin/synapse --config ${configFile}";
|
||||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.RunAtLoad = true;
|
||||
managedBy = "services.synapse-bt.enable";
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -130,6 +130,7 @@ in
|
|||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.RunAtLoad = cfg.client.autoStart;
|
||||
serviceConfig.ProcessType = "Interactive";
|
||||
managedBy = "services.synergy.client.enable";
|
||||
};
|
||||
})
|
||||
|
||||
|
@ -145,6 +146,7 @@ in
|
|||
serviceConfig.KeepAlive = true;
|
||||
serviceConfig.RunAtLoad = cfg.server.autoStart;
|
||||
serviceConfig.ProcessType = "Interactive";
|
||||
managedBy = "services.synergy.server.enable";
|
||||
};
|
||||
})
|
||||
];
|
||||
|
|
|
@ -42,6 +42,7 @@ in {
|
|||
KeepAlive = true;
|
||||
RunAtLoad = true;
|
||||
};
|
||||
managedBy = "services.trezord.enable";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ in
|
|||
serviceConfig.EnvironmentVariables = {
|
||||
PATH = "${cfg.package}/bin:${config.environment.systemPath}";
|
||||
};
|
||||
|
||||
managedBy = "services.yabai.enable";
|
||||
};
|
||||
})
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ in
|
|||
${cfg.activationScripts.etc.text}
|
||||
${cfg.activationScripts.defaults.text}
|
||||
${cfg.activationScripts.launchd.text}
|
||||
${cfg.activationScripts.userLaunchd.text}
|
||||
${cfg.activationScripts.nix-daemon.text}
|
||||
${cfg.activationScripts.time.text}
|
||||
${cfg.activationScripts.networking.text}
|
||||
|
@ -138,7 +139,6 @@ in
|
|||
${cfg.activationScripts.etcChecks.text}
|
||||
${cfg.activationScripts.extraUserActivation.text}
|
||||
${cfg.activationScripts.userDefaults.text}
|
||||
${cfg.activationScripts.userLaunchd.text}
|
||||
|
||||
${cfg.activationScripts.postUserActivation.text}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ let
|
|||
mkTextDerivation = pkgs.writeText;
|
||||
};
|
||||
|
||||
launchdVariables = mapAttrsToList (name: value: ''
|
||||
launchctl setenv ${name} '${value}'
|
||||
launchdVariables = prefix: mapAttrsToList (name: value: ''
|
||||
${prefix} launchctl setenv ${name} '${value}'
|
||||
'');
|
||||
|
||||
launchdActivation = basedir: target: ''
|
||||
|
@ -31,19 +31,21 @@ let
|
|||
fi
|
||||
'';
|
||||
|
||||
userLaunchdActivation = target: ''
|
||||
if ! diff ${cfg.build.launchd}/user/Library/LaunchAgents/${target} ~/Library/LaunchAgents/${target} &> /dev/null; then
|
||||
if test -f ~/Library/LaunchAgents/${target}; then
|
||||
userLaunchdActivation = target: let
|
||||
user = lib.escapeShellArg config.system.primaryUser;
|
||||
in ''
|
||||
if ! diff ${cfg.build.launchd}/user/Library/LaunchAgents/${target} ~${user}/Library/LaunchAgents/${target} &> /dev/null; then
|
||||
if test -f ~${user}/Library/LaunchAgents/${target}; then
|
||||
echo "reloading user service $(basename ${target} .plist)" >&2
|
||||
launchctl unload ~/Library/LaunchAgents/${target} || true
|
||||
sudo --user=${user} -- launchctl unload ~${user}/Library/LaunchAgents/${target} || true
|
||||
else
|
||||
echo "creating user service $(basename ${target} .plist)" >&2
|
||||
fi
|
||||
if test -L ~/Library/LaunchAgents/${target}; then
|
||||
rm ~/Library/LaunchAgents/${target}
|
||||
if test -L ~${user}/Library/LaunchAgents/${target}; then
|
||||
sudo --user=${user} -- rm ~${user}/Library/LaunchAgents/${target}
|
||||
fi
|
||||
cp -f '${cfg.build.launchd}/user/Library/LaunchAgents/${target}' ~/Library/LaunchAgents/${target}
|
||||
launchctl load -w ~/Library/LaunchAgents/${target}
|
||||
sudo --user=${user} -- cp -f '${cfg.build.launchd}/user/Library/LaunchAgents/${target}' ~${user}/Library/LaunchAgents/${target}
|
||||
sudo --user=${user} -- launchctl load -w ~${user}/Library/LaunchAgents/${target}
|
||||
fi
|
||||
'';
|
||||
|
||||
|
@ -100,7 +102,7 @@ in
|
|||
# Set up launchd services in /Library/LaunchAgents and /Library/LaunchDaemons
|
||||
echo "setting up launchd services..." >&2
|
||||
|
||||
${concatStringsSep "\n" (launchdVariables config.launchd.envVariables)}
|
||||
${concatStringsSep "\n" (launchdVariables "" config.launchd.envVariables)}
|
||||
|
||||
${concatMapStringsSep "\n" (attr: launchdActivation "LaunchAgents" attr.target) launchAgents}
|
||||
${concatMapStringsSep "\n" (attr: launchdActivation "LaunchDaemons" attr.target) launchDaemons}
|
||||
|
@ -132,14 +134,16 @@ in
|
|||
done
|
||||
'';
|
||||
|
||||
system.activationScripts.userLaunchd.text = ''
|
||||
system.activationScripts.userLaunchd.text = let
|
||||
user = lib.escapeShellArg config.system.primaryUser;
|
||||
in mkIf (config.launchd.user.envVariables != { } || userLaunchAgents != [ ]) ''
|
||||
# Set up user launchd services in ~/Library/LaunchAgents
|
||||
echo "setting up user launchd services..."
|
||||
|
||||
${concatStringsSep "\n" (launchdVariables config.launchd.user.envVariables)}
|
||||
${concatStringsSep "\n" (launchdVariables "sudo --user=${user} --" config.launchd.user.envVariables)}
|
||||
|
||||
${optionalString (builtins.length userLaunchAgents > 0) ''
|
||||
mkdir -p ~/Library/LaunchAgents
|
||||
sudo --user=${user} -- mkdir -p ~${user}/Library/LaunchAgents
|
||||
''}
|
||||
${concatMapStringsSep "\n" (attr: userLaunchdActivation attr.target) userLaunchAgents}
|
||||
|
||||
|
@ -149,9 +153,9 @@ in
|
|||
|
||||
if [[ ! -e "${cfg.build.launchd}/user/Library/LaunchAgents/$f" ]]; then
|
||||
echo "removing user service $(basename "$f" .plist)" >&2
|
||||
launchctl unload ~/Library/LaunchAgents/"$f" || true
|
||||
if [[ -e ~/Library/LaunchAgents/"$f" ]]; then
|
||||
rm -f ~/Library/LaunchAgents/"$f"
|
||||
sudo --user=${user} -- launchctl unload ~${user}/Library/LaunchAgents/"$f" || true
|
||||
if [[ -e ~${user}/Library/LaunchAgents/"$f" ]]; then
|
||||
sudo --user=${user} -- rm -f ~${user}/Library/LaunchAgents/"$f"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
system.primaryUser = "test-launchd-user";
|
||||
|
||||
launchd.daemons.foo.command = "foo";
|
||||
launchd.agents.bar.command = "bar";
|
||||
launchd.user.agents.baz.command = "baz";
|
||||
|
@ -9,9 +11,9 @@
|
|||
echo "checking launchd load in /activate" >&2
|
||||
grep "launchctl load .* '/Library/LaunchDaemons/org.nixos.foo.plist" ${config.out}/activate
|
||||
grep "launchctl load .* '/Library/LaunchAgents/org.nixos.bar.plist" ${config.out}/activate
|
||||
echo "checking launchd load in /activate-user" >&2
|
||||
grep "launchctl load .* ~/Library/LaunchAgents/org.nixos.baz.plist" ${config.out}/activate-user
|
||||
echo "checking LaunchAgents creation /activate-user" >&2
|
||||
grep "mkdir -p ~/Library/LaunchAgents" ${config.out}/activate-user
|
||||
echo "checking launchd user agent load in /activate" >&2
|
||||
grep "sudo --user=test-launchd-user -- launchctl load .* ~test-launchd-user/Library/LaunchAgents/org.nixos.baz.plist" ${config.out}/activate
|
||||
echo "checking LaunchAgents creation /activate" >&2
|
||||
grep "sudo --user=test-launchd-user -- mkdir -p ~test-launchd-user/Library/LaunchAgents" ${config.out}/activate
|
||||
'';
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-aerospace-user";
|
||||
|
||||
services.aerospace.enable = true;
|
||||
services.aerospace.package = aerospace;
|
||||
services.aerospace.settings = {
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-jankyborders-user";
|
||||
|
||||
services.jankyborders.enable = true;
|
||||
services.jankyborders.package = jankyborders;
|
||||
services.jankyborders.width = 5.0;
|
||||
|
|
|
@ -16,6 +16,8 @@ let
|
|||
expectedNixPath = "${"nixpkgs=" + toString pkgs.path}";
|
||||
in
|
||||
{
|
||||
system.primaryUser = "test-lorri-user";
|
||||
|
||||
services.lorri.enable = true;
|
||||
test = ''
|
||||
PATH=${
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-offlineimap-user";
|
||||
|
||||
services.offlineimap.enable = true;
|
||||
services.offlineimap.package = offlineimap;
|
||||
services.offlineimap.runQuick = true;
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-privoxy-user";
|
||||
|
||||
services.privoxy.enable = true;
|
||||
services.privoxy.package = privoxy;
|
||||
services.privoxy.config = "forward / .";
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-redis-user";
|
||||
|
||||
services.redis.enable = true;
|
||||
services.redis.package = redis;
|
||||
services.redis.extraConfig = ''
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-skhd-user";
|
||||
|
||||
services.skhd.enable = true;
|
||||
services.skhd.package = skhd;
|
||||
services.skhd.skhdConfig = "alt + shift - r : chunkc quit";
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-spacebar-user";
|
||||
|
||||
services.spacebar.enable = true;
|
||||
services.spacebar.package = spacebar;
|
||||
services.spacebar.config = { background_color = "0xff202020"; };
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-spotify-user";
|
||||
|
||||
services.spotifyd.enable = true;
|
||||
services.spotifyd.package = spotifyd;
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-synapse-bt-user";
|
||||
|
||||
services.synapse-bt.enable = true;
|
||||
services.synapse-bt.package = synapse-bt;
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-synergy-user";
|
||||
|
||||
services.synergy.package = synergy;
|
||||
|
||||
services.synergy.client.enable = true;
|
||||
|
|
|
@ -7,6 +7,8 @@ let
|
|||
in
|
||||
|
||||
{
|
||||
system.primaryUser = "test-yabai-user";
|
||||
|
||||
services.yabai.enable = true;
|
||||
services.yabai.package = yabai;
|
||||
services.yabai.config = { focus_follows_mouse = "autoraise"; };
|
||||
|
|
Loading…
Add table
Reference in a new issue