extdiff: copy back execbit-only changes to the working directory
authorMatt Harbison <matt_harbison@yahoo.com>
Thu, 11 May 2017 22:33:45 -0400
changeset 32283 8a1ff5ed620e
parent 32282 0c0c9b12de52
child 32284 16d424b97125
extdiff: copy back execbit-only changes to the working directory Some tools like BeyondCompare allow the file mode to be changed. The change was previously applied if the content of the file changed (either according to size or mtime), but was not being copied back for a mode-only change. That would seem to indicate handling this in an 'elif' branch, but I opted not to in order to avoid copying back the mode without the content changes when mtime and size are unchanged. (Yes, that's a rare corner case, but all the more reason not to have a subtle difference in behavior.) The only way I can think to handle this undetected change is to set each file in the non-wdir() snapshot to readonly, and check for that attribute (as well as mtime) when deciding to copy back. That would avoid the overhead of copying the whole file when only the mode changed. But a chmod in a diff tool is likely rare. See also affd753ddaf1.
hgext/extdiff.py
tests/test-extdiff.t
--- a/hgext/extdiff.py	Sat May 13 12:14:24 2017 -0700
+++ b/hgext/extdiff.py	Thu May 11 22:33:45 2017 -0400
@@ -280,7 +280,11 @@
             # all changes.  A size check will detect more cases, but not all.
             # The only certain way to detect every case is to diff all files,
             # which could be expensive.
-            if cpstat.st_mtime != st.st_mtime or cpstat.st_size != st.st_size:
+            # copyfile() carries over the permission, so the mode check could
+            # be in an 'elif' branch, but for the case where the file has
+            # changed without affecting mtime or size.
+            if (cpstat.st_mtime != st.st_mtime or cpstat.st_size != st.st_size
+                or (cpstat.st_mode & 0o100) != (st.st_mode & 0o100)):
                 ui.debug('file changed while diffing. '
                          'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
                 util.copyfile(copy_fn, working_fn)
--- a/tests/test-extdiff.t	Sat May 13 12:14:24 2017 -0700
+++ b/tests/test-extdiff.t	Thu May 11 22:33:45 2017 -0400
@@ -329,6 +329,7 @@
   > # Mimic a tool that syncs all attrs, including mtime
   > cp $1/a $2/a
   > touch -r $1/a $2/a
+  > chmod +x $2/a
   > echo "** custom diff **"
   > EOF
 #if execbit
@@ -366,6 +367,32 @@
   $ cat a
   a
 
+#if execbit
+  $ [ -x a ]
+
+  $ cat > 'dir/tool.sh' << 'EOF'
+  > #!/bin/sh
+  > chmod -x $2/a
+  > echo "** custom diff **"
+  > EOF
+
+  $ hg --debug tl --config extdiff.tl= --config merge-tools.tl.executable=$tool
+  making snapshot of 2 files from rev * (glob)
+    a
+    b
+  making snapshot of 2 files from working directory
+    a
+    b
+  running '$TESTTMP/a/dir/tool.sh a.* a' in */extdiff.* (glob)
+  ** custom diff **
+  file changed while diffing. Overwriting: $TESTTMP/a/a (src: */extdiff.*/a/a) (glob)
+  cleaning up temp directory
+  [1]
+
+  $ [ -x a ]
+  [1]
+#endif
+
   $ cd ..
 
 #if symlink