Patchwork [1,of,2,STABLE?,V2] copyfile: add an optional parameter to copy other stat data

mail settings
Submitter Siddharth Agarwal
Date Dec. 12, 2015, 7:03 p.m.
Message ID <>
Download mbox | patch
Permalink /patch/11993/
State Accepted
Headers show


Siddharth Agarwal - Dec. 12, 2015, 7:03 p.m.
# HG changeset patch
# User Siddharth Agarwal <>
# Date 1449946804 28800
#      Sat Dec 12 11:00:04 2015 -0800
# Branch stable
# Node ID 2398f014d0f3cb09364f551d0158d096c26c84fb
# Parent  59d5f619e69ec43f1957eddd85d4e1deddd64925
# Available At
#              hg pull -r 2398f014d0f3
copyfile: add an optional parameter to copy other stat data

Contrary to the comment, I didn't see any evidence that we were copying
atime/mtime at all. This adds a parameter to copyfile to optionally copy it and
other stat data, with the default being to not copy it.

Many systems don't support changing the timestamp of a symlink, but we don't
need that in general anyway -- copystat is mostly useful for editors, most of
which will dereference symlinks anyway.


diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -16,7 +16,7 @@  hide platform-specific details from the 
 import i18n
 _ = i18n._
 import error, osutil, encoding, parsers
-import errno, shutil, sys, tempfile, traceback
+import errno, shutil, stat, sys, tempfile, traceback
 import re as remod
 import os, time, datetime, calendar, textwrap, signal, collections
 import stat
@@ -806,8 +806,9 @@  def checksignature(func):
     return check
-def copyfile(src, dest, hardlink=False):
-    "copy a file, preserving mode and atime/mtime"
+def copyfile(src, dest, hardlink=False, copystat=False):
+    '''copy a file, preserving mode and optionally other stat info like
+    atime/mtime'''
     if os.path.lexists(dest):
     # hardlinks are problematic on CIFS, quietly ignore this flag
@@ -820,10 +821,16 @@  def copyfile(src, dest, hardlink=False):
             pass # fall back to normal copy
     if os.path.islink(src):
         os.symlink(os.readlink(src), dest)
+        # copytime is ignored for symlinks, but in general copytime isn't needed
+        # for them anyway
             shutil.copyfile(src, dest)
-            shutil.copymode(src, dest)
+            if copystat:
+                # copystat also copies mode
+                shutil.copystat(src, dest)
+            else:
+                shutil.copymode(src, dest)
         except shutil.Error as inst:
             raise Abort(str(inst))