From 719de878f75b293eb3a8ab30943ae6ecf458c0a4 Mon Sep 17 00:00:00 2001 From: David Baynard Date: Fri, 7 Jul 2023 10:39:12 +0100 Subject: [PATCH] imapnotify: Add launchd agent (#3291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * imapnotify: expose package (and exe) options There are multiple packages that provide an imapnotify interface. Those packages have differently named executables. This can now be customized. This change also means test configurations can use stub packages. * imapnotify: use/create config in configHome Exposing the configuration file makes testing imapnotify configurations much easier. It also allows for golden tests in home-manager. * imapnotify: extend with launchd agent Now that home-manager supports launchd agents, the imapnotify service can be configured (and enabled) for darwin. The configuration matches that of the linux/systemd version. In particular, by not setting a `UserName`, this runs as the user whose configuration includes the module. Due to the launchd `Program` implementation (it must take an absolute path) it is not possible to use that for the program and stub the path in tests. Instead, this uses `ProgramArguments` for the program name. The `ThrottleInterval` is equivalent to `RestartSec`. `KeepAlive` is equivalent to `Restart`. The `ExitTimeOut` default is 20 seconds, but goimapnotify should not time out — this is achieved by setting the `ExitTimeout` to 0. * imapnotify: add launchd plist test This only tests the generated plist (which is new), not the original systemd implementation, nor the json config file. (Note the lack of a newline at the end of the plist file.) --- modules/services/imapnotify.nix | 56 ++++++++++++++++--- tests/default.nix | 1 + .../modules/programs/goimapnotify/default.nix | 1 + .../modules/programs/goimapnotify/launchd.nix | 41 ++++++++++++++ .../programs/goimapnotify/launchd.plist | 29 ++++++++++ 5 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 tests/modules/programs/goimapnotify/default.nix create mode 100644 tests/modules/programs/goimapnotify/launchd.nix create mode 100644 tests/modules/programs/goimapnotify/launchd.plist diff --git a/modules/services/imapnotify.nix b/modules/services/imapnotify.nix index 0197ec54d..048e80974 100644 --- a/modules/services/imapnotify.nix +++ b/modules/services/imapnotify.nix @@ -8,6 +8,8 @@ let safeName = lib.replaceStrings [ "@" ":" "\\" "[" "]" ] [ "-" "-" "-" "" "" ]; + configName = account: "imapnotify-${safeName account.name}-config.json"; + imapnotifyAccounts = filter (a: a.imapnotify.enable) (attrValues config.accounts.email.accounts); @@ -19,9 +21,10 @@ let Unit = { Description = "imapnotify for ${name}"; }; Service = { - ExecStart = "${pkgs.goimapnotify}/bin/goimapnotify -conf ${ - genAccountConfig account - }"; + ExecStart = + "${getExe cfg.package} -conf '${config.xdg.configHome}/imapnotify/${ + configName account + }'"; Restart = "always"; RestartSec = 30; Type = "simple"; @@ -34,8 +37,32 @@ let }; }; + genAccountAgent = account: + let name = safeName account.name; + in { + name = "imapnotify-${name}"; + value = { + enable = true; + config = { + ProgramArguments = [ + "${getExe cfg.package}" + "-conf" + "${config.xdg.configHome}/imapnotify/${configName account}" + ]; + KeepAlive = true; + ThrottleInterval = 30; + ExitTimeOut = 0; + ProcessType = "Background"; + RunAtLoad = true; + } // optionalAttrs account.notmuch.enable { + EnvironmentVariables.NOTMUCH_CONFIG = + "${config.xdg.configHome}/notmuch/default/config"; + }; + }; + }; + genAccountConfig = account: - pkgs.writeText "imapnotify-${safeName account.name}-config.json" (let + pkgs.writeText (configName account) (let port = if account.imap.port != null then account.imap.port else if account.imap.tls.enable then @@ -62,7 +89,17 @@ in { meta.maintainers = [ maintainers.nickhu ]; options = { - services.imapnotify = { enable = mkEnableOption "imapnotify"; }; + services.imapnotify = { + enable = mkEnableOption "imapnotify"; + + package = mkOption { + type = types.package; + default = pkgs.goimapnotify; + defaultText = literalExpression "pkgs.goimapnotify"; + example = literalExpression "pkgs.imapnotify"; + description = "The imapnotify package to use"; + }; + }; accounts.email.accounts = mkOption { type = with types; attrsOf (submodule (import ./imapnotify-accounts.nix)); @@ -79,8 +116,6 @@ in { + concatMapStringsSep ", " (a: a.name) badAccounts; }; in [ - (lib.hm.assertions.assertPlatform "services.imapnotify" pkgs - lib.platforms.linux) (checkAccounts (a: a.maildir == null) "maildir configuration") (checkAccounts (a: a.imap == null) "IMAP configuration") (checkAccounts (a: a.passwordCommand == null) "password command") @@ -88,5 +123,12 @@ in { ]; systemd.user.services = listToAttrs (map genAccountUnit imapnotifyAccounts); + + launchd.agents = listToAttrs (map genAccountAgent imapnotifyAccounts); + + xdg.configFile = listToAttrs (map (account: { + name = "imapnotify/${configName account}"; + value.source = genAccountConfig account; + }) imapnotifyAccounts); }; } diff --git a/tests/default.nix b/tests/default.nix index ae11853bd..fb5afbc9d 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -145,6 +145,7 @@ import nmt { ] ++ lib.optionals isDarwin [ ./modules/launchd ./modules/targets-darwin + ./modules/programs/goimapnotify ] ++ lib.optionals isLinux [ ./modules/config/i18n ./modules/i18n/input-method diff --git a/tests/modules/programs/goimapnotify/default.nix b/tests/modules/programs/goimapnotify/default.nix new file mode 100644 index 000000000..a2adc553d --- /dev/null +++ b/tests/modules/programs/goimapnotify/default.nix @@ -0,0 +1 @@ +{ goimapnotify-launchd = ./launchd.nix; } diff --git a/tests/modules/programs/goimapnotify/launchd.nix b/tests/modules/programs/goimapnotify/launchd.nix new file mode 100644 index 000000000..c7a81a3af --- /dev/null +++ b/tests/modules/programs/goimapnotify/launchd.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + imports = [ ../../accounts/email-test-accounts.nix ]; + + config = { + accounts.email.accounts = { + "hm@example.com" = { + notmuch.enable = true; + imap.port = 993; + + imapnotify = { + enable = true; + boxes = [ "Inbox" ]; + onNotify = '' + ${pkgs.notmuch}/bin/notmuch new + ''; + }; + }; + }; + + services.imapnotify = { + enable = true; + package = (config.lib.test.mkStubPackage { + name = "goimapnotify"; + outPath = "@goimapnotify@"; + }); + }; + + nmt.script = let + serviceFileName = + "org.nix-community.home.imapnotify-hm-example.com.plist"; + in '' + serviceFile=LaunchAgents/${serviceFileName} + assertFileExists $serviceFile + assertFileContent $serviceFile ${./launchd.plist} + ''; + }; +} diff --git a/tests/modules/programs/goimapnotify/launchd.plist b/tests/modules/programs/goimapnotify/launchd.plist new file mode 100644 index 000000000..f8e45e8a3 --- /dev/null +++ b/tests/modules/programs/goimapnotify/launchd.plist @@ -0,0 +1,29 @@ + + + + + EnvironmentVariables + + NOTMUCH_CONFIG + /home/hm-user/.config/notmuch/default/config + + ExitTimeOut + 0 + KeepAlive + + Label + org.nix-community.home.imapnotify-hm-example.com + ProcessType + Background + ProgramArguments + + @goimapnotify@/bin/goimapnotify + -conf + /home/hm-user/.config/imapnotify/imapnotify-hm-example.com-config.json + + RunAtLoad + + ThrottleInterval + 30 + + \ No newline at end of file