diff options
Diffstat (limited to 'modules/home.legacy/conf/unison/default.nix')
-rw-r--r-- | modules/home.legacy/conf/unison/default.nix | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/modules/home.legacy/conf/unison/default.nix b/modules/home.legacy/conf/unison/default.nix new file mode 100644 index 00000000..ae682235 --- /dev/null +++ b/modules/home.legacy/conf/unison/default.nix @@ -0,0 +1,187 @@ +{ + 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; + }; +} |