From a124dae35a088ab18747effa9442467b90937e9a Mon Sep 17 00:00:00 2001 From: pacien Date: Tue, 23 Jul 2019 00:15:45 +0200 Subject: [PATCH] muchsync: add module --- modules/modules.nix | 1 + modules/services/muchsync.nix | 211 ++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 modules/services/muchsync.nix diff --git a/modules/modules.nix b/modules/modules.nix index ef11de548..05f3bb50b 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -112,6 +112,7 @@ let (loadModule ./services/mbsync.nix { }) (loadModule ./services/mpd.nix { }) (loadModule ./services/mpdris2.nix { condition = hostPlatform.isLinux; }) + (loadModule ./services/muchsync.nix { condition = hostPlatform.isLinux; }) (loadModule ./services/network-manager-applet.nix { }) (loadModule ./services/nextcloud-client.nix { }) (loadModule ./services/owncloud-client.nix { }) diff --git a/modules/services/muchsync.nix b/modules/services/muchsync.nix new file mode 100644 index 000000000..72bf737c2 --- /dev/null +++ b/modules/services/muchsync.nix @@ -0,0 +1,211 @@ +{ config, lib, pkgs, ... }: + +with lib; + +# Documentation was partially copied from the muchsync manual. +# See http://www.muchsync.org/muchsync.html + +let + cfg = config.services.muchsync; + syncOptions = { + options = { + frequency = mkOption { + type = types.str; + default = "*:0/5"; + description = '' + How often to run muchsync. This + value is passed to the systemd timer configuration as the + OnCalendar option. See + + systemd.time + 7 + + for more information about the format. + ''; + }; + + sshCommand = mkOption { + type = types.str; + default = "${pkgs.openssh}/bin/ssh -CTaxq"; + defaultText = "ssh -CTaxq"; + description = '' + Specifies a command line to pass to /bin/sh + to execute a command on another machine. + + Note that because this string is passed to the shell, + special characters including spaces may need to be escaped. + ''; + }; + + upload = mkOption { + type = types.bool; + default = true; + description = '' + Whether to propagate local changes to the remote. + ''; + }; + + local = { + checkForModifiedFiles = mkOption { + type = types.bool; + default = false; + description = '' + Check for locally modified files. + Without this option, muchsync assumes that files in a maildir are + never edited. + + disables certain + optimizations so as to make muchsync at least check the timestamp on + every file, which will detect modified files at the cost of a longer + startup time. + + This option is useful if your software regularly modifies the + contents of mail files (e.g., because you are running offlineimap + with "synclabels = yes"). + ''; + }; + + importNew = mkOption { + type = types.bool; + default = true; + description = '' + Whether to begin the synchronisation by running + notmuch new locally. + ''; + }; + }; + + remote = { + host = mkOption { + type = types.str; + description = '' + Remote SSH host to synchronize with. + ''; + }; + + muchsyncPath = mkOption { + type = types.str; + default = ""; + defaultText = "$PATH/muchsync"; + description = '' + Specifies the path to muchsync on the server. + Ordinarily, muchsync should be in the default PATH on the server + so this option is not required. + However, this option is useful if you have to install muchsync in + a non-standard place or wish to test development versions of the + code. + ''; + }; + + checkForModifiedFiles = mkOption { + type = types.bool; + default = false; + description = '' + Check for modified files on the remote side. + Without this option, muchsync assumes that files in a maildir are + never edited. + + disables certain + optimizations so as to make muchsync at least check the timestamp on + every file, which will detect modified files at the cost of a longer + startup time. + + This option is useful if your software regularly modifies the + contents of mail files (e.g., because you are running offlineimap + with "synclabels = yes"). + ''; + }; + + importNew = mkOption { + type = types.bool; + default = true; + description = '' + Whether to begin the synchronisation by running + notmuch new on the remote side. + ''; + }; + }; + }; + }; + +in { + meta.maintainers = with maintainers; [ pacien ]; + + options.services.muchsync = { + remotes = mkOption { + type = with types; attrsOf (submodule syncOptions); + default = { }; + example = literalExample '' + { + server = { + frequency = "*:0/10"; + remote.host = "server.tld"; + }; + } + ''; + description = '' + Muchsync remotes to synchronise with. + ''; + }; + }; + + config = let + mapRemotes = gen: with attrsets; mapAttrs' + (name: remoteCfg: nameValuePair "muchsync-${name}" (gen name remoteCfg)) + cfg.remotes; + in mkIf (cfg.remotes != { }) { + assertions = [ + { + assertion = config.programs.notmuch.enable; + message = '' + The muchsync module requires 'programs.notmuch.enable = true'. + ''; + } + ]; + + systemd.user.services = mapRemotes (name: remoteCfg: { + Unit = { + Description = "muchsync sync service (${name})"; + }; + Service = { + CPUSchedulingPolicy = "idle"; + IOSchedulingClass = "idle"; + Environment = [ + ''"PATH=${pkgs.notmuch}/bin"'' + ''"NOTMUCH_CONFIG=${config.home.sessionVariables.NOTMUCH_CONFIG}"'' + ''"NMBGIT=${config.home.sessionVariables.NMBGIT}"'' + ]; + ExecStart = concatStringsSep " " ( + [ "${pkgs.muchsync}/bin/muchsync" ] + ++ [ "-s ${escapeShellArg remoteCfg.sshCommand}" ] + ++ optional (!remoteCfg.upload) "--noup" + + # local configuration + ++ optional remoteCfg.local.checkForModifiedFiles "-F" + ++ optional (!remoteCfg.local.importNew) "--nonew" + + # remote configuration + ++ [ (escapeShellArg remoteCfg.remote.host) ] + ++ optional (remoteCfg.remote.muchsyncPath != "") + "-r ${escapeShellArg remoteCfg.remote.muchsyncPath}" + ++ optional remoteCfg.remote.checkForModifiedFiles "-F" + ++ optional (!remoteCfg.remote.importNew) "--nonew" + ); + }; + }); + + systemd.user.timers = mapRemotes (name: remoteCfg: { + Unit = { + Description = "muchsync periodic sync (${name})"; + }; + Timer = { + Unit = "muchsync-${name}.service"; + OnCalendar = remoteCfg.frequency; + Persistent = true; + }; + Install = { + WantedBy = [ "timers.target" ]; + }; + }); + }; +}