--- a/mercurial/dirstate.py Tue Oct 26 10:23:14 2021 -0400
+++ b/mercurial/dirstate.py Thu Oct 28 17:26:03 2021 +0200
@@ -242,68 +242,59 @@
return self._rootdir + f
def flagfunc(self, buildfallback):
- if not (self._checklink and self._checkexec):
- fallback = buildfallback()
+ """build a callable that returns flags associated with a filename
- def check_both(x):
- """This platform supports symlinks and exec permissions"""
+ The information is extracted from three possible layers:
+ 1. the file system if it supports the information
+ 2. the "fallback" information stored in the dirstate if any
+ 3. a more expensive mechanism inferring the flags from the parents.
+ """
+
+ # small hack to cache the result of buildfallback()
+ fallback_func = []
+
+ def get_flags(x):
+ entry = None
+ fallback_value = None
try:
st = os.lstat(self._join(x))
+ except OSError:
+ return b''
+
+ if self._checklink:
if util.statislink(st):
return b'l'
+ else:
+ entry = self.get_entry(x)
+ if entry.has_fallback_symlink:
+ if entry.fallback_symlink:
+ return b'l'
+ else:
+ if not fallback_func:
+ fallback_func.append(buildfallback())
+ fallback_value = fallback_func[0](x)
+ if b'l' in fallback_value:
+ return b'l'
+
+ if self._checkexec:
if util.statisexec(st):
return b'x'
- except OSError:
- pass
- return b''
-
- def check_link(x):
- """This platform only supports symlinks"""
- if os.path.islink(self._join(x)):
- return b'l'
- entry = self.get_entry(x)
- if entry.has_fallback_exec:
- if entry.fallback_exec:
- return b'x'
- elif b'x' in fallback(x):
- return b'x'
+ else:
+ if entry is None:
+ entry = self.get_entry(x)
+ if entry.has_fallback_exec:
+ if entry.fallback_exec:
+ return b'x'
+ else:
+ if fallback_value is None:
+ if not fallback_func:
+ fallback_func.append(buildfallback())
+ fallback_value = fallback_func[0](x)
+ if b'x' in fallback_value:
+ return b'x'
return b''
- def check_exec(x):
- """This platform only supports exec permissions"""
- if b'l' in fallback(x):
- return b'l'
- entry = self.get_entry(x)
- if entry.has_fallback_symlink:
- if entry.fallback_symlink:
- return b'l'
- if util.isexec(self._join(x)):
- return b'x'
- return b''
-
- def check_fallback(x):
- """This platform supports neither symlinks nor exec permissions, so
- check the fallback in the dirstate if it exists, otherwise figure it
- out the more expensive way from the parents."""
- entry = self.get_entry(x)
- if entry.has_fallback_symlink:
- if entry.fallback_symlink:
- return b'l'
- if entry.has_fallback_exec:
- if entry.fallback_exec:
- return b'x'
- elif entry.has_fallback_symlink:
- return b''
- return fallback(x)
-
- if self._checklink and self._checkexec:
- return check_both
- elif self._checklink:
- return check_link
- elif self._checkexec:
- return check_exec
- else:
- return check_fallback
+ return get_flags
@propertycache
def _cwd(self):