copyfile: preserve stat info (mtime, etc.) when doing copies/renames
authorKyle Lippincott <spectral@google.com>
Thu, 08 Mar 2018 11:44:03 -0800
changeset 37088 08890706366e
parent 37087 e4640ec346ac
child 37089 9938992c5bae
copyfile: preserve stat info (mtime, etc.) when doing copies/renames Differential Revision: https://phab.mercurial-scm.org/D2729
hgext/largefiles/overrides.py
mercurial/cmdutil.py
tests/test-rename.t
--- a/hgext/largefiles/overrides.py	Thu Mar 22 22:58:31 2018 -0400
+++ b/hgext/largefiles/overrides.py	Thu Mar 08 11:44:03 2018 -0800
@@ -667,7 +667,7 @@
         try:
             origcopyfile = util.copyfile
             copiedfiles = []
-            def overridecopyfile(src, dest):
+            def overridecopyfile(src, dest, *args, **kwargs):
                 if (lfutil.shortname in src and
                     dest.startswith(repo.wjoin(lfutil.shortname))):
                     destlfile = dest.replace(lfutil.shortname, '')
@@ -675,7 +675,7 @@
                         raise IOError('',
                             _('destination largefile already exists'))
                 copiedfiles.append((src, dest))
-                origcopyfile(src, dest)
+                origcopyfile(src, dest, *args, **kwargs)
 
             util.copyfile = overridecopyfile
             result += orig(ui, repo, listpats, opts, rename)
--- a/mercurial/cmdutil.py	Thu Mar 22 22:58:31 2018 -0400
+++ b/mercurial/cmdutil.py	Thu Mar 08 11:44:03 2018 -0800
@@ -1192,7 +1192,9 @@
                     os.rename(src, tmp)
                     os.rename(tmp, target)
                 else:
-                    util.copyfile(src, target)
+                    # Preserve stat info on renames, not on copies; this matches
+                    # Linux CLI behavior.
+                    util.copyfile(src, target, copystat=rename)
                 srcexists = True
             except IOError as inst:
                 if inst.errno == errno.ENOENT:
--- a/tests/test-rename.t	Thu Mar 22 22:58:31 2018 -0400
+++ b/tests/test-rename.t	Thu Mar 08 11:44:03 2018 -0800
@@ -657,3 +657,36 @@
   [255]
   $ hg status -C
 
+check that stat information such as mtime is preserved on rename - it's unclear
+whether the `touch` and `stat` commands are portable, so we mimic them using
+python.  Not all platforms support precision of even one-second granularity, so
+we allow a rather generous fudge factor here; 1234567890 is 2009, and the
+primary thing we care about is that it's not the machine's current time;
+hopefully it's really unlikely for a machine to have such a broken clock that
+this test fails. :)
+
+  $ mkdir mtime
+Create the file (as empty), then update its mtime and atime to be 1234567890.
+  >>> import os
+  >>> filename = "mtime/f"
+  >>> mtime = 1234567890
+  >>> open(filename, "w").close()
+  >>> os.utime(filename, (mtime, mtime))
+  $ hg ci -qAm 'add mtime dir'
+"hg cp" does not preserve the mtime, so it should be newer than the 2009
+timestamp.
+  $ hg cp -q mtime mtime_cp
+  >>> from __future__ import print_function
+  >>> import os
+  >>> filename = "mtime_cp/f"
+  >>> print(os.stat(filename).st_mtime < 1234567999)
+  False
+"hg mv" preserves the mtime, so it should be ~equal to the 2009 timestamp
+(modulo some fudge factor due to not every system supporting 1s-level
+precision).
+  $ hg mv -q mtime mtime_mv
+  >>> from __future__ import print_function
+  >>> import os
+  >>> filename = "mtime_mv/f"
+  >>> print(os.stat(filename).st_mtime < 1234567999)
+  True