about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--flake/nixosConfigurations/common.nix33
-rw-r--r--hosts/apzu/default.nix1
-rw-r--r--hosts/tiamat/default.nix1
-rw-r--r--modules/by-name/un/unison/module.nix92
-rw-r--r--modules/by-name/un/unison/shellScript.nix95
-rw-r--r--modules/home.legacy/conf/default.nix1
-rw-r--r--modules/home.legacy/conf/unison/default.nix187
7 files changed, 221 insertions, 189 deletions
diff --git a/flake/nixosConfigurations/common.nix b/flake/nixosConfigurations/common.nix
index 585e883b..2ff85521 100644
--- a/flake/nixosConfigurations/common.nix
+++ b/flake/nixosConfigurations/common.nix
@@ -1,6 +1,6 @@
 # This file contains common configuration applied to every host.
 # It should only `enable` options defined in the `modules` directory.
-{...}: {
+{config, ...}: {
   soispha = {
     boot.enable = true;
     cleanup.enable = true;
@@ -37,6 +37,37 @@
       snapper.enable = true;
       steam.enable = false;
       systemDiff.enable = true;
+      unison = {
+        enable = true;
+
+        foreign.userName = "soispha";
+        dataDir = "${config.home-manager.users.soispha.xdg.dataHome}/unison";
+        userSourceDir = "/srv/home/soispha";
+        pathsToIgnore = [
+          # already synchronized by the taskserver
+          "~/.local/share/task"
+
+          # Should not be synchronized
+          "~/.local/share/unison"
+
+          # Is just to big to be synchronized (# TODO: Work around that <2024-08-31> )
+          "~/media/music"
+        ];
+
+        pathsToSync = [
+          "~/.local/state/mpv"
+          "~/.local/state/nvim"
+          "~/.local/share"
+          "~/.local/.Trash-1000"
+
+          "~/.mozilla/.Trash-1000"
+          "~/.mozilla/firefox"
+
+          "~/media"
+          "~/school"
+          "~/repos"
+        ];
+      };
     };
 
     programs = {
diff --git a/hosts/apzu/default.nix b/hosts/apzu/default.nix
index 98c83325..d1a83fec 100644
--- a/hosts/apzu/default.nix
+++ b/hosts/apzu/default.nix
@@ -19,6 +19,7 @@
       hostName = "apzu";
       mode = "NetworkManager";
     };
+    services.unison.foreign.address = "tiamat.fritz.box";
     nixpkgs = {
       enable = true;
       systemName = "x86_64-linux";
diff --git a/hosts/tiamat/default.nix b/hosts/tiamat/default.nix
index b679ec62..3e531c7d 100644
--- a/hosts/tiamat/default.nix
+++ b/hosts/tiamat/default.nix
@@ -19,6 +19,7 @@
         backupDiskUuid = "c06ce163-2955-4388-b212-dfec4448fcf4";
         enable = true;
       };
+      unison.foreign.address = "apzu.fritz.box";
     };
     locale = {
       enable = true;
diff --git a/modules/by-name/un/unison/module.nix b/modules/by-name/un/unison/module.nix
new file mode 100644
index 00000000..baf92b02
--- /dev/null
+++ b/modules/by-name/un/unison/module.nix
@@ -0,0 +1,92 @@
+{
+  lib,
+  config,
+  pkgs,
+  sysLib,
+  ...
+}: let
+  cfg = config.soispha.services.unison;
+
+  script = import ./shellScript.nix {inherit sysLib lib pkgs cfg;};
+in {
+  options.soispha.services.unison = let
+    homePath = lib.types.strMatching "^~.*";
+  in {
+    enable = lib.mkEnableOption "a unison home sync script";
+
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        This directory is used by unison to store it's data.
+      '';
+    };
+
+    foreign = {
+      address = lib.mkOption {
+        type = lib.types.str;
+        description = ''
+          The address to contact via ssh, when syncing.
+        '';
+      };
+      userName = lib.mkOption {
+        type = lib.types.str;
+        description = ''
+          The user name to try to login with at the foreign host.
+        '';
+      };
+    };
+
+    userSourceDir = lib.mkOption {
+      description = ''
+        The directory to replace the `~` in the relative user paths with.
+        If using `impermanence`, this should be the path to the persistent home directory.
+      '';
+    };
+
+    pathsToIgnore = lib.mkOption {
+      type = lib.types.listOf homePath;
+      default = [];
+      description = ''
+        A list of the paths that should not be synced.
+        Beware that this applies not only to this path, but also to all paths under it.
+      '';
+    };
+    pathsToSync = lib.mkOption {
+      type = lib.types.listOf homePath;
+      default = [];
+      description = ''
+        A list of the paths that should be synced.
+        Beware that this applies not only to this path, but also to all paths under it.
+      '';
+    };
+
+    unisonOptions = lib.mkOption {
+      internal = true;
+      default = {
+        sshcmd = "ssh";
+        ui = "text";
+        auto = "true";
+        # This is a trap, thanks to the HM links
+        # TODO: Auto-ignore all `home.file` paths <2024-10-24>
+        links = "false";
+
+        backupdir = "${cfg.dataDir}/backups";
+        backuploc = "central";
+      };
+      type = lib.types.attrsOf lib.types.str;
+      description = "The options passed to every unison call.";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      home.sessionVariables = {
+        UNISON = cfg.dataDir;
+      };
+      home.packages = [
+        pkgs.unison
+        script
+      ];
+    };
+  };
+}
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
+    ];
+  }
diff --git a/modules/home.legacy/conf/default.nix b/modules/home.legacy/conf/default.nix
index 217944ce..161c04a1 100644
--- a/modules/home.legacy/conf/default.nix
+++ b/modules/home.legacy/conf/default.nix
@@ -37,7 +37,6 @@
     ./taskwarrior
     ./timewarrior
     ./tridactyl
-    ./unison
     ./xdg
     ./yambar
     ./yt
diff --git a/modules/home.legacy/conf/unison/default.nix b/modules/home.legacy/conf/unison/default.nix
deleted file mode 100644
index ae682235..00000000
--- a/modules/home.legacy/conf/unison/default.nix
+++ /dev/null
@@ -1,187 +0,0 @@
-{
-  lib,
-  config,
-  nixosConfig,
-  sysLib,
-  pkgs,
-  ...
-}: let
-  unisonPath = "${config.xdg.dataHome}/unison";
-
-  # These are only used for the script
-  unisonOptions = {
-    sshcmd = "ssh";
-    ui = "text";
-    auto = "true";
-    # This is useless, with hm links
-    links = "false";
-
-    backupdir = "${unisonPath}/backups";
-    backuploc = "central";
-    backupcurr = paths_to_merge;
-    # merge =
-    #   builtins.map (x: ''${x} -> diff3 --text --merge CURRENT1 CURRENTARCH CURRENT2 > NEW'')
-    #   paths_to_merge;
-  };
-
-  paths_to_merge = mkPathName {
-    file_names = ["log" "history" "harpoon.json" "file_frecency.bin" "main.shada"];
-    extensions = ["log"];
-  };
-
-  paths_to_keep = [
-    "~/.local/state/mpv"
-    "~/.local/state/nvim"
-    "~/.local/share"
-    "~/.local/.Trash-1000"
-
-    "~/.mozilla/.Trash-1000"
-    "~/.mozilla/firefox"
-
-    "~/media"
-    "~/school"
-    "~/repos"
-  ];
-  paths_to_ignore = [
-    # already synchronized by the taskserver
-    "~/.local/share/task"
-
-    # Should not be synchronized
-    "~/.local/share/unison"
-
-    # Is just to big to be synchronized (# TODO: Work around that <2024-08-31> )
-    "~/media/music"
-  ];
-
-  hostName = let
-    hn = nixosConfig.networking.hostName;
-  in
-    if hn == "tiamat"
-    then "apzu"
-    else if hn == "apzu"
-    then "tiamat"
-    else builtins.throw "Host (${hn}) not yet covered in the unison host mapping.";
-
-  mkPathName = {
-    file_names,
-    extensions,
-  }:
-    builtins.map (x: ''Name ${x}'') (
-      (builtins.map (x: ''*.${x}'') extensions)
-      ++ file_names
-    );
-
-  unitName = name: builtins.replaceStrings ["/"] ["-"] name;
-
-  mkPath = path:
-    if lib.strings.hasPrefix "~" path
-    then "${builtins.elemAt (builtins.attrNames config.home.persistence)
-      0}${lib.strings.removePrefix "~" path}"
-    else
-      builtins.throw
-      "Every pathname needs to start with a '~'";
-
-  mkPair = pathname: let
-    path = mkPath pathname;
-  in {
-    name = unitName "${pathname}";
-    value = {
-      stateDirectory = unisonPath;
-      roots = [
-        "${path}"
-        "ssh://${config.home.username}@${hostName}.fritz.box/${path}"
-      ];
-    };
-  };
-
-  getIgnoredSingle = path: path_to_ignore: let
-    clean_path_to_ignore = mkPath path_to_ignore;
-    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;
-
-  getIgnored = paths_to_ignore: path:
-    serialiseArgs {
-      ignore =
-        builtins.filter (x: x != null) (builtins.map (getIgnoredSingle path) paths_to_ignore);
-    };
-
-  serialiseArg = key: val:
-    if builtins.typeOf val == "string"
-    then lib.strings.escapeShellArg "-${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
-    );
-
-  esa = a: lib.strings.escapeShellArg a;
-
-  mkScriptLine = pathname: let
-    path =
-      mkPath pathname;
-  in
-    lib.strings.concatStringsSep " " [
-      "unison"
-      "${serialiseArgs unisonOptions}"
-      "$EXTRA_OPTIONS"
-      "${getIgnored paths_to_ignore path}"
-      "${esa path}"
-      (esa "ssh://${config.home.username}@${hostName}.fritz.box/${path}")
-    ];
-
-  script = lib.strings.concatStringsSep "\n" (builtins.map mkScriptLine paths_to_keep);
-
-  pairs = builtins.listToAttrs (builtins.map mkPair paths_to_keep);
-in {
-  home.sessionVariables = {
-    UNISON = unisonPath;
-  };
-  home.packages = [
-    pkgs.unison
-    (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 unisonPath};
-
-          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
-      ];
-    })
-  ];
-  services.unison = {
-    enable = false;
-    inherit pairs;
-  };
-}