From 7f976da06840c268cc291a021bab7532b923713c Mon Sep 17 00:00:00 2001
From: piegames <git@piegames.de>
Date: Tue, 19 May 2020 14:44:44 +0200
Subject: [PATCH] files: ignore conflict when files are identical

When the target file exists but has the exact same content then we
will now skip creation of the link from the source file.

Fixes #1213
---
 modules/files.nix | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/modules/files.nix b/modules/files.nix
index 1ecc18217..6106d8157 100644
--- a/modules/files.nix
+++ b/modules/files.nix
@@ -106,7 +106,12 @@ in
               $VERBOSE_ECHO "Skipping collision check for $targetPath"
             elif [[ -e "$targetPath" \
                 && ! "$(readlink "$targetPath")" == $homeFilePattern ]] ; then
-              if [[ ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
+              # The target file already exists and it isn't a symlink owned by Home Manager.
+              if cmp -s $sourcePath $targetPath; then
+                # First compare the files' content. If they're equal, we're fine.
+                warnEcho "Existing file '$targetPath' is in the way of '$sourcePath', will be skipped since they are the same"
+              elif [[ ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
+                # Next, try to move the file to a backup location if configured and possible
                 backup="$targetPath.$HOME_MANAGER_BACKUP_EXT"
                 if [[ -e "$backup" ]]; then
                   errorEcho "Existing file '$backup' would be clobbered by backing up '$targetPath'"
@@ -115,6 +120,7 @@ in
                   warnEcho "Existing file '$targetPath' is in the way of '$sourcePath', will be moved to '$backup'"
                 fi
               else
+                # Fail if nothing else works
                 errorEcho "Existing file '$targetPath' is in the way of '$sourcePath'"
                 collision=1
               fi
@@ -169,11 +175,19 @@ in
             relativePath="''${sourcePath#$newGenFiles/}"
             targetPath="$HOME/$relativePath"
             if [[ -e "$targetPath" && ! -L "$targetPath" && -n "$HOME_MANAGER_BACKUP_EXT" ]] ; then
+              # The target exists, back it up
               backup="$targetPath.$HOME_MANAGER_BACKUP_EXT"
               $DRY_RUN_CMD mv $VERBOSE_ARG "$targetPath" "$backup" || errorEcho "Moving '$targetPath' failed!"
             fi
-            $DRY_RUN_CMD mkdir -p $VERBOSE_ARG "$(dirname "$targetPath")"
-            $DRY_RUN_CMD ln -nsf $VERBOSE_ARG "$sourcePath" "$targetPath"
+
+            if [[ -e "$targetPath" && ! -L "$targetPath" ]] && cmp -s $sourcePath $targetPath ; then
+              # The target exists but is identical – don't do anything.
+              $VERBOSE_ECHO "Skipping '$targetPath' as it is identical to '$sourcePath'"
+            else
+              # Place that symlink, --force
+              $DRY_RUN_CMD mkdir -p $VERBOSE_ARG "$(dirname "$targetPath")"
+              $DRY_RUN_CMD ln -nsf $VERBOSE_ARG "$sourcePath" "$targetPath"
+            fi
           done
         '';