mirror of
https://github.com/nix-community/home-manager
synced 2024-11-27 05:29:46 +01:00
9f9e277b60
These (and the `*MD` functions apart from `literalMD`) are now no-ops in nixpkgs and serve no purpose other than to add additional noise and potentially mislead people into thinking unmarked DocBook documentation will still be accepted. Note that if backporting changes including documentation to 23.05, the `mdDoc` calls will need to be re-added. To reproduce this commit, run: $ NIX_PATH=nixpkgs=flake:nixpkgs/e7e69199f0372364a6106a1e735f68604f4c5a25 \ nix shell nixpkgs#coreutils \ -c find . -name '*.nix' \ -exec nix run -- github:emilazy/nix-doc-munge/98dadf1f77351c2ba5dcb709a2a171d655f15099 \ --strip {} + $ ./format
213 lines
6.5 KiB
Nix
213 lines
6.5 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
inherit (pkgs.stdenv.hostPlatform) isDarwin;
|
|
inherit (lib.generators) toPlist;
|
|
|
|
cfg = config.launchd;
|
|
labelPrefix = "org.nix-community.home.";
|
|
dstDir = "${config.home.homeDirectory}/Library/LaunchAgents";
|
|
|
|
launchdConfig = { config, name, ... }: {
|
|
options = {
|
|
enable = mkEnableOption name;
|
|
config = mkOption {
|
|
type = types.submodule (import ./launchd.nix);
|
|
default = { };
|
|
example = literalExpression ''
|
|
{
|
|
ProgramArguments = [ "/usr/bin/say" "Good afternoon" ];
|
|
StartCalendarInterval = [
|
|
{
|
|
Hour = 12;
|
|
Minute = 0;
|
|
}
|
|
];
|
|
}
|
|
'';
|
|
description = ''
|
|
Define a launchd job. See {manpage}`launchd.plist(5)` for details.
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = { config.Label = mkDefault "${labelPrefix}${name}"; };
|
|
};
|
|
|
|
toAgent = config: pkgs.writeText "${config.Label}.plist" (toPlist { } config);
|
|
|
|
agentPlists =
|
|
mapAttrs' (n: v: nameValuePair "${v.config.Label}.plist" (toAgent v.config))
|
|
(filterAttrs (n: v: v.enable) cfg.agents);
|
|
|
|
agentsDrv = pkgs.runCommand "home-manager-agents" { } ''
|
|
mkdir -p "$out"
|
|
|
|
declare -A plists
|
|
plists=(${
|
|
concatStringsSep " "
|
|
(mapAttrsToList (name: value: "['${name}']='${value}'") agentPlists)
|
|
})
|
|
|
|
for dest in "''${!plists[@]}"; do
|
|
src="''${plists[$dest]}"
|
|
ln -s "$src" "$out/$dest"
|
|
done
|
|
'';
|
|
in {
|
|
meta.maintainers = with maintainers; [ midchildan ];
|
|
|
|
options.launchd = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = isDarwin;
|
|
defaultText = literalExpression "pkgs.stdenv.hostPlatform.isDarwin";
|
|
description = ''
|
|
Whether to enable Home Manager to define per-user daemons by making use
|
|
of launchd's LaunchAgents.
|
|
'';
|
|
};
|
|
|
|
agents = mkOption {
|
|
type = with types; attrsOf (submodule launchdConfig);
|
|
default = { };
|
|
description = "Define LaunchAgents.";
|
|
};
|
|
};
|
|
|
|
config = mkMerge [
|
|
{
|
|
assertions = [{
|
|
assertion = (cfg.enable && agentPlists != { }) -> isDarwin;
|
|
message = let names = lib.concatStringsSep ", " (attrNames agentPlists);
|
|
in "Must use Darwin for modules that require Launchd: " + names;
|
|
}];
|
|
}
|
|
|
|
(mkIf isDarwin {
|
|
home.extraBuilderCommands = ''
|
|
ln -s "${agentsDrv}" $out/LaunchAgents
|
|
'';
|
|
|
|
home.activation.checkLaunchAgents =
|
|
hm.dag.entryBefore [ "writeBoundary" ] ''
|
|
checkLaunchAgents() {
|
|
local oldDir newDir dstDir err
|
|
oldDir=""
|
|
err=0
|
|
if [[ -n "''${oldGenPath:-}" ]]; then
|
|
oldDir="$(readlink -m "$oldGenPath/LaunchAgents")" || err=$?
|
|
if (( err )); then
|
|
oldDir=""
|
|
fi
|
|
fi
|
|
newDir=${escapeShellArg agentsDrv}
|
|
dstDir=${escapeShellArg dstDir}
|
|
|
|
local oldSrcPath newSrcPath dstPath agentFile agentName
|
|
|
|
find -L "$newDir" -maxdepth 1 -name '*.plist' -type f -print0 \
|
|
| while IFS= read -rd "" newSrcPath; do
|
|
agentFile="''${newSrcPath##*/}"
|
|
agentName="''${agentFile%.plist}"
|
|
dstPath="$dstDir/$agentFile"
|
|
oldSrcPath="$oldDir/$agentFile"
|
|
|
|
if [[ ! -e "$dstPath" ]]; then
|
|
continue
|
|
fi
|
|
|
|
if ! cmp --quiet "$oldSrcPath" "$dstPath"; then
|
|
errorEcho "Existing file '$dstPath' is in the way of '$newSrcPath'"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
checkLaunchAgents
|
|
'';
|
|
|
|
# NOTE: Launch Agent configurations can't be symlinked from the Nix store
|
|
# because it needs to be owned by the user running it.
|
|
home.activation.setupLaunchAgents =
|
|
hm.dag.entryAfter [ "writeBoundary" ] ''
|
|
setupLaunchAgents() {
|
|
local oldDir newDir dstDir domain err
|
|
oldDir=""
|
|
err=0
|
|
if [[ -n "''${oldGenPath:-}" ]]; then
|
|
oldDir="$(readlink -m "$oldGenPath/LaunchAgents")" || err=$?
|
|
if (( err )); then
|
|
oldDir=""
|
|
fi
|
|
fi
|
|
newDir="$(readlink -m "$newGenPath/LaunchAgents")"
|
|
dstDir=${escapeShellArg dstDir}
|
|
domain="gui/$UID"
|
|
err=0
|
|
|
|
local srcPath dstPath agentFile agentName i bootout_retries
|
|
bootout_retries=10
|
|
|
|
find -L "$newDir" -maxdepth 1 -name '*.plist' -type f -print0 \
|
|
| while IFS= read -rd "" srcPath; do
|
|
agentFile="''${srcPath##*/}"
|
|
agentName="''${agentFile%.plist}"
|
|
dstPath="$dstDir/$agentFile"
|
|
|
|
if cmp --quiet "$srcPath" "$dstPath"; then
|
|
continue
|
|
fi
|
|
if [[ -f "$dstPath" ]]; then
|
|
for (( i = 0; i < bootout_retries; i++ )); do
|
|
$DRY_RUN_CMD /bin/launchctl bootout "$domain/$agentName" || err=$?
|
|
if [[ -v DRY_RUN ]]; then
|
|
break
|
|
fi
|
|
if (( err != 9216 )) &&
|
|
! /bin/launchctl print "$domain/$agentName" &> /dev/null; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
if (( i == bootout_retries )); then
|
|
warnEcho "Failed to stop '$domain/$agentName'"
|
|
return 1
|
|
fi
|
|
fi
|
|
$DRY_RUN_CMD install -Dm444 -T "$srcPath" "$dstPath"
|
|
$DRY_RUN_CMD /bin/launchctl bootstrap "$domain" "$dstPath"
|
|
done
|
|
|
|
if [[ ! -e "$oldDir" ]]; then
|
|
return
|
|
fi
|
|
|
|
find -L "$oldDir" -maxdepth 1 -name '*.plist' -type f -print0 \
|
|
| while IFS= read -rd "" srcPath; do
|
|
agentFile="''${srcPath##*/}"
|
|
agentName="''${agentFile%.plist}"
|
|
dstPath="$dstDir/$agentFile"
|
|
if [[ -e "$newDir/$agentFile" ]]; then
|
|
continue
|
|
fi
|
|
|
|
$DRY_RUN_CMD /bin/launchctl bootout "$domain/$agentName" || :
|
|
if [[ ! -e "$dstPath" ]]; then
|
|
continue
|
|
fi
|
|
if ! cmp --quiet "$srcPath" "$dstPath"; then
|
|
warnEcho "Skipping deletion of '$dstPath', since its contents have diverged"
|
|
continue
|
|
fi
|
|
$DRY_RUN_CMD rm -f $VERBOSE_ARG "$dstPath"
|
|
done
|
|
}
|
|
|
|
setupLaunchAgents
|
|
'';
|
|
})
|
|
];
|
|
}
|