From 07ad6a4f76d9402ae8af1507b4158b52aa59fcea Mon Sep 17 00:00:00 2001
From: Robert Helgesson <robert@rycee.net>
Date: Thu, 20 May 2021 22:12:45 +0200
Subject: [PATCH] files: fix use of onChange with directory source

Previously, the comparison would not handle directory comparison
correctly, always finding that the source and target differed. This
would trigger the `onChange` script on each activation.

Fixes #2004
---
 modules/files.nix         | 23 ++++++++++++++++++++++-
 modules/lib/file-type.nix |  3 +++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/modules/files.nix b/modules/files.nix
index 09ecf715..9eb4fd05 100644
--- a/modules/files.nix
+++ b/modules/files.nix
@@ -39,6 +39,17 @@ in
   };
 
   config = {
+    assertions = [(
+      let
+        conflicts = mapAttrsToList (n: v: n)
+          (filterAttrs (n: v: v.recursive && v.onChange != "") cfg);
+      in {
+        assertion = conflicts == [];
+        message = ''
+          Cannot use 'home.file.<name>.onChange' when 'home.file.<name>.recursive' is enabled:
+              ${concatStringsSep ", " conflicts}'';
+      })];
+
     lib.file.mkOutOfStoreSymlink = path:
       let
         pathStr = toString path;
@@ -236,12 +247,22 @@ in
 
     home.activation.checkFilesChanged = hm.dag.entryBefore ["linkGeneration"] (
       ''
+        function _cmp() {
+          if [[ -d $1 && -d $2 ]]; then
+            diff -rq "$1" "$2" &> /dev/null
+          else
+            cmp --quiet "$1" "$2"
+          fi
+        }
         declare -A changedFiles
       '' + concatMapStrings (v: ''
-        cmp --quiet "${sourceStorePath v}" "${homeDirectory}/${v.target}" \
+        _cmp "${sourceStorePath v}" "${homeDirectory}/${v.target}" \
           && changedFiles["${v.target}"]=0 \
           || changedFiles["${v.target}"]=1
       '') (filter (v: v.onChange != "") (attrValues cfg))
+      + ''
+        unset -f _cmp
+      ''
     );
 
     home.activation.onFilesChange = hm.dag.entryAfter ["linkGeneration"] (
diff --git a/modules/lib/file-type.nix b/modules/lib/file-type.nix
index 56a3a128..d0ae1f31 100644
--- a/modules/lib/file-type.nix
+++ b/modules/lib/file-type.nix
@@ -82,6 +82,9 @@ with lib;
             generations. The script will be run
             <emphasis>after</emphasis> the new files have been linked
             into place.
+            </para><para>
+            Note, this option cannot be used when <literal>recursive</literal>
+            is enabled.
           '';
         };