{ sysLib, lib, pkgs, cfg, }: let esa = lib.strings.escapeShellArg; expandHomePath = path: if lib.strings.hasPrefix "~" path then "${cfg.userSourceDir}${lib.strings.removePrefix "~" path}" else builtins.throw '' BUG: Every pathname needs to start with a '~'. This should have been checked by the NixOS module system? ''; getIgnored = paths_to_ignore: path: serialiseArgs { ignore = builtins.filter (x: x != null) (builtins.map (getIgnoredSingle path) paths_to_ignore); }; getIgnoredSingle = path: pathToIgnore: let clean_path_to_ignore = expandHomePath pathToIgnore; commonPath = builtins.substring 0 (builtins.stringLength path) clean_path_to_ignore; in if commonPath == path then let preFinalPath = builtins.substring (builtins.stringLength commonPath) (builtins.stringLength clean_path_to_ignore) clean_path_to_ignore; finalPath = if lib.strings.hasPrefix "/" preFinalPath then lib.strings.removePrefix "/" preFinalPath else preFinalPath; in "BelowPath ${finalPath}" else null; serialiseArg = key: val: if builtins.typeOf val == "string" then esa "-${key}=${lib.strings.escape ["="] val}" else if builtins.typeOf val == "list" then lib.strings.concatStringsSep " " (builtins.map (serialiseArg key) val) else builtins.throw "Unsupported type: ${builtins.typeOf val}"; serialiseArgs = args: lib.strings.concatStringsSep " " ( lib.attrsets.mapAttrsToList serialiseArg args ); mkScriptLine = pathname: let path = expandHomePath pathname; in lib.strings.concatStringsSep " " [ "unison" "${serialiseArgs cfg.unisonOptions}" "$EXTRA_OPTIONS" "${getIgnored cfg.pathsToIgnore path}" "${esa path}" (esa "ssh://${cfg.foreign.userName}@${cfg.foreign.address}/${path}") ]; script = lib.strings.concatStringsSep "\n" (builtins.map mkScriptLine cfg.pathsToSync); in sysLib.writeShellScript { name = "unison-sync"; src = builtins.toFile "unison-backup" ('' #!/usr/bin/env dash # shellcheck source=/dev/null SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH export UNISON=${esa cfg.dataDir}; EXTRA_OPTIONS="$UNISON_EXTRA_OPTIONS $*" '' + script); dependencies = with pkgs; [ unison openssh # needed to connect to the other server less # needed to show diffs diffutils # needed to compute diffs ]; }