Mercurial > public > mercurial-scm > hg
comparison mercurial/util.py @ 47400:9b841267253c
util: add `nb_bytes` argument to `copyfile` to partially copy a file
When set, this allow to copy only the first `nb_bytes` of a file. This will be
useful for censor/strip operation with revlogv2.
Differential Revision: https://phab.mercurial-scm.org/D10798
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Sun, 30 May 2021 18:08:52 +0200 |
parents | bcafcd779d2e |
children | 9ea525216edb |
comparison
equal
deleted
inserted
replaced
47399:34cc102c73f5 | 47400:9b841267253c |
---|---|
1907 b'xfs', | 1907 b'xfs', |
1908 b'zfs', | 1908 b'zfs', |
1909 } | 1909 } |
1910 | 1910 |
1911 | 1911 |
1912 def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False): | 1912 def copyfile( |
1913 src, dest, hardlink=False, copystat=False, checkambig=False, nb_bytes=None | |
1914 ): | |
1913 """copy a file, preserving mode and optionally other stat info like | 1915 """copy a file, preserving mode and optionally other stat info like |
1914 atime/mtime | 1916 atime/mtime |
1915 | 1917 |
1916 checkambig argument is used with filestat, and is useful only if | 1918 checkambig argument is used with filestat, and is useful only if |
1917 destination file is guarded by any lock (e.g. repo.lock or | 1919 destination file is guarded by any lock (e.g. repo.lock or |
1918 repo.wlock). | 1920 repo.wlock). |
1919 | 1921 |
1920 copystat and checkambig should be exclusive. | 1922 copystat and checkambig should be exclusive. |
1923 | |
1924 nb_bytes: if set only copy the first `nb_bytes` of the source file. | |
1921 """ | 1925 """ |
1922 assert not (copystat and checkambig) | 1926 assert not (copystat and checkambig) |
1923 oldstat = None | 1927 oldstat = None |
1924 if os.path.lexists(dest): | 1928 if os.path.lexists(dest): |
1925 if checkambig: | 1929 if checkambig: |
1935 if fstype not in _hardlinkfswhitelist: | 1939 if fstype not in _hardlinkfswhitelist: |
1936 hardlink = False | 1940 hardlink = False |
1937 if hardlink: | 1941 if hardlink: |
1938 try: | 1942 try: |
1939 oslink(src, dest) | 1943 oslink(src, dest) |
1944 if nb_bytes is not None: | |
1945 m = "the `nb_bytes` argument is incompatible with `hardlink`" | |
1946 raise error.ProgrammingError(m) | |
1940 return | 1947 return |
1941 except (IOError, OSError): | 1948 except (IOError, OSError): |
1942 pass # fall back to normal copy | 1949 pass # fall back to normal copy |
1943 if os.path.islink(src): | 1950 if os.path.islink(src): |
1944 os.symlink(os.readlink(src), dest) | 1951 os.symlink(os.readlink(src), dest) |
1945 # copytime is ignored for symlinks, but in general copytime isn't needed | 1952 # copytime is ignored for symlinks, but in general copytime isn't needed |
1946 # for them anyway | 1953 # for them anyway |
1954 if nb_bytes is not None: | |
1955 m = "cannot use `nb_bytes` on a symlink" | |
1956 raise error.ProgrammingError(m) | |
1947 else: | 1957 else: |
1948 try: | 1958 try: |
1949 shutil.copyfile(src, dest) | 1959 shutil.copyfile(src, dest) |
1950 if copystat: | 1960 if copystat: |
1951 # copystat also copies mode | 1961 # copystat also copies mode |
1958 # stat of copied file is ambiguous to original one | 1968 # stat of copied file is ambiguous to original one |
1959 advanced = ( | 1969 advanced = ( |
1960 oldstat.stat[stat.ST_MTIME] + 1 | 1970 oldstat.stat[stat.ST_MTIME] + 1 |
1961 ) & 0x7FFFFFFF | 1971 ) & 0x7FFFFFFF |
1962 os.utime(dest, (advanced, advanced)) | 1972 os.utime(dest, (advanced, advanced)) |
1973 # We could do something smarter using `copy_file_range` call or similar | |
1974 if nb_bytes is not None: | |
1975 with open(dest, mode='r+') as f: | |
1976 f.truncate(nb_bytes) | |
1963 except shutil.Error as inst: | 1977 except shutil.Error as inst: |
1964 raise error.Abort(stringutil.forcebytestr(inst)) | 1978 raise error.Abort(stringutil.forcebytestr(inst)) |
1965 | 1979 |
1966 | 1980 |
1967 def copyfiles(src, dst, hardlink=None, progress=None): | 1981 def copyfiles(src, dst, hardlink=None, progress=None): |