changeset 51697:e760a36a6013 stable

windows: implement `util.cachestat` to fix numerous dirstate problems I got here by bisecting the issue1790 related failure on Windows to keep an entry from being marked "unset" in `test-dirstate.t` back to eedbf8256263. There were a handful of other tests failing with an unexpected dirstate entry state like this, as well as numerous "skip updating dirstate: identity mismatch" messages added to various tests, as well as an issue with dirstate wrapping with the largefiles extension[1], all of which appear to be fixed by this. In total, ~25 tests are fully fixed on Windows with this change on default. This is basically a copy/paste of the posix implementation, but we drop the `st_mode` comparison- I think the only reason we care about the mode on posix is to detect +/-x mode changes, but the executable bits on Windows are synthesized based on the name of the file[2]. None of the other parts of the codebase are equipped to handle executable bits in the filesystem on Windows anyway, so it doesn't make sense to worry about them here. Note that `st_uid` and `st_gid` seem to always be 0 on Windows (and I can't find them being initialized), so they can probably be dropped from the comparison. But I doubt they matter any more on posix, since we don't track ownership. The `st_ino`, `st_dev`, and `st_nlink` attributes all seem to have reasonable values for comparing like on posix[3]. Also note that `st_ctime` is apparently deprecated in 3.12+ (for reasons I haven't explored)[4]. [1] https://foss.heptapod.net/mercurial/mercurial-devel/-/merge_requests/884 [2] https://github.com/python/cpython/blob/aab3210271136ad8e8fecd927b806602c463e1f2/Modules/posixmodule.c#L1948 [3] https://github.com/python/cpython/blob/aab3210271136ad8e8fecd927b806602c463e1f2/Python/fileutils.c#L1158 [4] https://github.com/python/cpython/blob/aab3210271136ad8e8fecd927b806602c463e1f2/Modules/posixmodule.c#L2200
author Matt Harbison <matt_harbison@yahoo.com>
date Wed, 16 Oct 2024 18:06:36 -0400
parents cd788962c6d9
children d906406658a9
files mercurial/windows.py
diffstat 1 files changed, 30 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/windows.py	Mon Oct 14 16:46:25 2024 +0200
+++ b/mercurial/windows.py	Wed Oct 16 18:06:36 2024 -0400
@@ -18,6 +18,7 @@
 import winreg  # pytype: disable=import-error
 
 from typing import (
+    Any,
     AnyStr,
     BinaryIO,
     Iterable,
@@ -675,11 +676,38 @@
 
 
 class cachestat:
+    stat: os.stat_result
+
     def __init__(self, path: bytes) -> None:
-        pass
+        self.stat = os.stat(path)
 
     def cacheable(self) -> bool:
-        return False
+        return bool(self.stat.st_ino)
+
+    __hash__ = object.__hash__
+
+    def __eq__(self, other: Any) -> bool:
+        try:
+            # Only dev, ino, size, mtime and atime are likely to change. Out
+            # of these, we shouldn't compare atime but should compare the
+            # rest. However, one of the other fields changing indicates
+            # something fishy going on, so return False if anything but atime
+            # changes.
+            return (
+                self.stat.st_ino == other.stat.st_ino
+                and self.stat.st_dev == other.stat.st_dev
+                and self.stat.st_nlink == other.stat.st_nlink
+                and self.stat.st_uid == other.stat.st_uid
+                and self.stat.st_gid == other.stat.st_gid
+                and self.stat.st_size == other.stat.st_size
+                and self.stat[stat.ST_MTIME] == other.stat[stat.ST_MTIME]
+                and self.stat[stat.ST_CTIME] == other.stat[stat.ST_CTIME]
+            )
+        except AttributeError:
+            return False
+
+    def __ne__(self, other: Any) -> bool:
+        return not self == other
 
 
 def lookupreg(