##// END OF EJS Templates
py3: catch specific OSError subclasses instead of checking errno...
py3: catch specific OSError subclasses instead of checking errno Contrary to the previous changesets in this series, this covers cases where errno was checked for multiple values. EACCES -> PermissionError ENOENT -> FileNotFoundError ENOTDIR -> NotADirectoryError EISDIR -> IsADirectoryError

File last commit:

r49730:6000f5b2 default
r50205:050dc873 default
Show More
timestamp.py
127 lines | 3.8 KiB | text/x-python | PythonLexer
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 # Copyright Mercurial Contributors
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081 import functools
dirstate: move "get fs now" in the timestamp utility module...
r49202 import os
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 import stat
dirstate: drop comparison primitive on the timestamp class...
r49226 from .. import error
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079
rangemask = 0x7FFFFFFF
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081 @functools.total_ordering
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 class timestamp(tuple):
"""
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081 A Unix timestamp with optional nanoseconds precision,
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 modulo 2**31 seconds.
Simon Sapin
dirstate: Document Timestamp.second_ambiguous...
r49271 A 3-tuple containing:
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079
`truncated_seconds`: seconds since the Unix epoch,
truncated to its lower 31 bits
`subsecond_nanoseconds`: number of nanoseconds since `truncated_seconds`.
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081 When this is zero, the sub-second precision is considered unknown.
Simon Sapin
dirstate: Document Timestamp.second_ambiguous...
r49271
`second_ambiguous`: whether this timestamp is still "reliable"
(see `reliable_mtime_of`) if we drop its sub-second component.
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 """
def __new__(cls, value):
dirstate-item: add a "second_ambiguous` flag in the mtime tuple...
r49227 truncated_seconds, subsec_nanos, second_ambiguous = value
value = (truncated_seconds & rangemask, subsec_nanos, second_ambiguous)
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 return super(timestamp, cls).__new__(cls, value)
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081 def __eq__(self, other):
dirstate: drop comparison primitive on the timestamp class...
r49226 raise error.ProgrammingError(
'timestamp should never be compared directly'
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081 )
def __gt__(self, other):
dirstate: drop comparison primitive on the timestamp class...
r49226 raise error.ProgrammingError(
'timestamp should never be compared directly'
)
Simon Sapin
dirstate: ignore sub-second component when either is zero in mtime...
r49081
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079
dirstate: move "get fs now" in the timestamp utility module...
r49202 def get_fs_now(vfs):
"""return a timestamp for "now" in the current vfs
This will raise an exception if no temporary files could be created.
"""
tmpfd, tmpname = vfs.mkstemp()
try:
return mtime_of(os.fstat(tmpfd))
finally:
os.close(tmpfd)
vfs.unlink(tmpname)
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 def zero():
"""
Returns the `timestamp` at the Unix epoch.
"""
return tuple.__new__(timestamp, (0, 0))
def mtime_of(stat_result):
"""
Takes an `os.stat_result`-like object and returns a `timestamp` object
for its modification time.
"""
Simon Sapin
dirstate-v2: actually use sub-second mtime precision...
r49082 try:
# TODO: add this attribute to `osutil.stat` objects,
# see `mercurial/cext/osutil.c`.
#
# This attribute is also not available on Python 2.
nanos = stat_result.st_mtime_ns
except AttributeError:
# https://docs.python.org/2/library/os.html#os.stat_float_times
# "For compatibility with older Python versions,
# accessing stat_result as a tuple always returns integers."
secs = stat_result[stat.ST_MTIME]
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079
Simon Sapin
dirstate-v2: actually use sub-second mtime precision...
r49082 subsec_nanos = 0
else:
billion = int(1e9)
secs = nanos // billion
subsec_nanos = nanos % billion
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079
dirstate-item: add a "second_ambiguous` flag in the mtime tuple...
r49227 return timestamp((secs, subsec_nanos, False))
status: move the boundary comparison logic within the timestamp module...
r49224
def reliable_mtime_of(stat_result, present_mtime):
Simon Sapin
dirstate: Document Timestamp.second_ambiguous...
r49271 """Same as `mtime_of`, but return `None` or a `Timestamp` with
`second_ambiguous` set if the date might be ambiguous.
status: move the boundary comparison logic within the timestamp module...
r49224
A modification time is reliable if it is older than "present_time" (or
Simon Sapin
rhg: Update the dirstate on disk after status...
r49250 sufficiently in the future).
status: move the boundary comparison logic within the timestamp module...
r49224
Otherwise a concurrent modification might happens with the same mtime.
"""
file_mtime = mtime_of(stat_result)
file_second = file_mtime[0]
status: keep second-ambiguous mtimes during fixup...
r49232 file_ns = file_mtime[1]
status: move the boundary comparison logic within the timestamp module...
r49224 boundary_second = present_mtime[0]
status: keep second-ambiguous mtimes during fixup...
r49232 boundary_ns = present_mtime[1]
status: move the boundary comparison logic within the timestamp module...
r49224 # If the mtime of the ambiguous file is younger (or equal) to the starting
# point of the `status` walk, we cannot garantee that another, racy, write
# will not happen right after with the same mtime and we cannot cache the
# information.
#
status: keep second-ambiguous mtimes during fixup...
r49232 # However if the mtime is far away in the future, this is likely some
status: move the boundary comparison logic within the timestamp module...
r49224 # mismatch between the current clock and previous file system operation. So
# mtime more than one days in the future are considered fine.
status: keep second-ambiguous mtimes during fixup...
r49232 if boundary_second == file_second:
if file_ns and boundary_ns:
if file_ns < boundary_ns:
return timestamp((file_second, file_ns, True))
return None
elif boundary_second < file_second < (3600 * 24 + boundary_second):
status: move the boundary comparison logic within the timestamp module...
r49224 return None
else:
return file_mtime