diff -r 456626e9c3d1 -r 9bb4decd43b0 mercurial/localrepo.py --- a/mercurial/localrepo.py Tue Jul 11 12:27:58 2017 +0200 +++ b/mercurial/localrepo.py Tue Jul 11 12:38:17 2017 +0200 @@ -300,6 +300,26 @@ # only functions defined in module of enabled extensions are invoked featuresetupfuncs = set() + # list of prefix for file which can be written without 'wlock' + # Extensions should extend this list when needed + _wlockfreeprefix = { + # We migh consider requiring 'wlock' for the next + # two, but pretty much all the existing code assume + # wlock is not needed so we keep them excluded for + # now. + 'hgrc', + 'requires', + # XXX cache is a complicatged business someone + # should investigate this in depth at some point + 'cache/', + # XXX shouldn't be dirstate covered by the wlock? + 'dirstate', + # XXX bisect was still a bit too messy at the time + # this changeset was introduced. Someone should fix + # the remainig bit and drop this line + 'bisect.state', + } + def __init__(self, baseui, path, create=False): self.requirements = set() self.filtername = None @@ -319,10 +339,13 @@ self.auditor = pathutil.pathauditor(self.root, self._checknested) self.nofsauditor = pathutil.pathauditor(self.root, self._checknested, realfs=False) - self.vfs = vfsmod.vfs(self.path) self.baseui = baseui self.ui = baseui.copy() self.ui.copy = baseui.copy # prevent copying repo configuration + self.vfs = vfsmod.vfs(self.path) + if (self.ui.configbool('devel', 'all-warnings') or + self.ui.configbool('devel', 'check-locks')): + self.vfs.audit = self._getvfsward(self.vfs.audit) # A list of callback to shape the phase if no data were found. # Callback are in the form: func(repo, roots) --> processed root. # This list it to be filled by extension during repo setup @@ -441,6 +464,38 @@ # Signature to cached matcher instance. self._sparsematchercache = {} + def _getvfsward(self, origfunc): + """build a ward for self.vfs""" + rref = weakref.ref(self) + def checkvfs(path, mode=None): + ret = origfunc(path, mode=mode) + repo = rref() + if (repo is None + or not util.safehasattr(repo, '_wlockref') + or not util.safehasattr(repo, '_lockref')): + return + if mode in (None, 'r', 'rb'): + return + if path.startswith(repo.path): + # truncate name relative to the repository (.hg) + path = path[len(repo.path) + 1:] + if path.startswith('journal.'): + # journal is covered by 'lock' + if repo._currentlock(repo._lockref) is None: + repo.ui.develwarn('write with no lock: "%s"' % path, + stacklevel=2) + elif repo._currentlock(repo._wlockref) is None: + # rest of vfs files are covered by 'wlock' + # + # exclude special files + for prefix in self._wlockfreeprefix: + if path.startswith(prefix): + return + repo.ui.develwarn('write with no wlock: "%s"' % path, + stacklevel=2) + return ret + return checkvfs + def close(self): self._writecaches()