about summary refs log tree commit diff stats
path: root/modules/by-name/un/unison/shellScript.nix
diff options
context:
space:
mode:
Diffstat (limited to 'modules/by-name/un/unison/shellScript.nix')
-rw-r--r--modules/by-name/un/unison/shellScript.nix95
1 files changed, 95 insertions, 0 deletions
diff --git a/modules/by-name/un/unison/shellScript.nix b/modules/by-name/un/unison/shellScript.nix
new file mode 100644
index 00000000..5ff0c219
--- /dev/null
+++ b/modules/by-name/un/unison/shellScript.nix
@@ -0,0 +1,95 @@
+{
+  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};
+
+        if [ "$1" = "links" ]; then
+          shift 1;
+          EXTRA_OPTIONS="-links=true";
+        fi
+        EXTRA_OPTIONS="$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
+    ];
+  }