Patchwork D10798: util: add `nb_bytes` argument to `copyfile` to partially copy a file

login
register
mail settings
Submitter phabricator
Date May 30, 2021, 5:31 p.m.
Message ID <differential-rev-PHID-DREV-gtye2jg3xkftdbvlemop-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49118/
State Superseded
Headers show

Comments

phabricator - May 30, 2021, 5:31 p.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  When set, this allow to copy only the first `nb_bytes` of a file. This will be
  useful for censor/strip operation with revlogv2.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10798

AFFECTED FILES
  mercurial/util.py

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -1909,7 +1909,9 @@ 
 }
 
 
-def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
+def copyfile(
+    src, dest, hardlink=False, copystat=False, checkambig=False, nb_bytes=None
+):
     """copy a file, preserving mode and optionally other stat info like
     atime/mtime
 
@@ -1918,6 +1920,8 @@ 
     repo.wlock).
 
     copystat and checkambig should be exclusive.
+
+    nb_bytes: if set only copy the first `nb_bytes` of the source file.
     """
     assert not (copystat and checkambig)
     oldstat = None
@@ -1937,6 +1941,9 @@ 
     if hardlink:
         try:
             oslink(src, dest)
+            if nb_bytes is not None:
+                m = "the `nb_bytes` argument is incompatible with nb_bytes"
+                raise error.ProgrammingError(m)
             return
         except (IOError, OSError):
             pass  # fall back to normal copy
@@ -1944,6 +1951,9 @@ 
         os.symlink(os.readlink(src), dest)
         # copytime is ignored for symlinks, but in general copytime isn't needed
         # for them anyway
+        if nb_bytes is not None:
+            m = "cannot use `nb_bytes` on a symlink"
+            raise error.ProgrammingError(m)
     else:
         try:
             shutil.copyfile(src, dest)
@@ -1960,6 +1970,10 @@ 
                             oldstat.stat[stat.ST_MTIME] + 1
                         ) & 0x7FFFFFFF
                         os.utime(dest, (advanced, advanced))
+            # We could do something smarter using `copy_file_range` call or similar
+            if nb_bytes is not None:
+                with open(dest, mode='r+') as f:
+                    f.truncate(nb_bytes)
         except shutil.Error as inst:
             raise error.Abort(stringutil.forcebytestr(inst))