diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -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): diff --git a/tests/test-share.t b/tests/test-share.t --- a/tests/test-share.t +++ b/tests/test-share.t @@ -47,8 +47,8 @@ [1] $ ls -1 .hg/wcache || true checkisexec (execbit !) - checklink (symlink !) - checklink-target (symlink !) + checklink (symlink no-rust !) + checklink-target (symlink no-rust !) manifestfulltextcache (reporevlogstore !) $ ls -1 ../repo1/.hg/cache branch2-served diff --git a/tests/test-subrepo.t b/tests/test-subrepo.t --- a/tests/test-subrepo.t +++ b/tests/test-subrepo.t @@ -1275,8 +1275,8 @@ ../shared/subrepo-2/.hg/sharedpath ../shared/subrepo-2/.hg/wcache ../shared/subrepo-2/.hg/wcache/checkisexec (execbit !) - ../shared/subrepo-2/.hg/wcache/checklink (symlink !) - ../shared/subrepo-2/.hg/wcache/checklink-target (symlink !) + ../shared/subrepo-2/.hg/wcache/checklink (symlink no-rust !) + ../shared/subrepo-2/.hg/wcache/checklink-target (symlink no-rust !) ../shared/subrepo-2/.hg/wcache/manifestfulltextcache (reporevlogstore !) ../shared/subrepo-2/file $ hg -R ../shared in