@@ -230,6 +230,7 @@ def reposetup(ui, repo):
if util.safehasattr(ui, 'setrepo'):
ui.setrepo(repo)
+ repo._wlockfreeprefix.add('blackbox.log')
@command('^blackbox',
[('l', 'limit', 10, _('the number of events to show')),
@@ -69,6 +69,7 @@ def extsetup(ui):
def reposetup(ui, repo):
if repo.local():
repo.journal = journalstorage(repo)
+ repo._wlockfreeprefix.add('namejournal')
def runcommand(orig, lui, repo, cmd, fullargs, *args):
"""Track the command line options for recording in the journal"""
@@ -122,6 +122,10 @@ def uisetup(ui):
cmdutil.extraexport.append('pullurl')
cmdutil.extraexportmap['pullurl'] = _addpullheader
+def reposetup(ui, repo):
+ if not repo.local():
+ return
+ repo._wlockfreeprefix.add('last-email.txt')
def prompt(ui, prompt, default=None, rest=':'):
if default:
@@ -272,6 +272,25 @@ class localrepository(object):
# 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 = set([# 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
@@ -291,10 +310,14 @@ class localrepository(object):
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
+ _vfsward = None
+ if (self.ui.configbool('devel', 'all-warnings') or
+ self.ui.configbool('devel', 'check-locks')):
+ _vfsward = self._getvfsward()
+ self.vfs = vfsmod.vfs(self.path, ward=_vfsward)
# 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
@@ -405,6 +428,36 @@ class localrepository(object):
# generic mapping between names and nodes
self.names = namespaces.namespaces()
+ def _getvfsward(self):
+ """build a ward for self.vfs"""
+ rref = weakref.ref(self)
+ def checkvfs(f, mode, atomictemp):
+ repo = rref()
+ if (repo is None
+ or not util.safehasattr(repo, '_wlockref')
+ or not util.safehasattr(repo, '_lockref')):
+ return
+ if mode in ('r', 'rb'):
+ return
+ assert f.startswith(repo.path)
+ # truncate name relative to the repository (.hg)
+ relname = f[len(repo.path) + 1:]
+ if relname.startswith('journal.'):
+ # journal is covered by 'lock'
+ if repo._currentlock(repo._lockref) is None:
+ repo.ui.develwarn('write with no lock: "%s"' % relname,
+ stacklevel=2)
+ elif repo._currentlock(repo._wlockref) is None:
+ # rest of vfs file are covered by 'wlock'
+ #
+ # exclude special files
+ for prefix in self._wlockfreeprefix:
+ if relname.startswith(prefix):
+ return
+ repo.ui.develwarn('write with no wlock: "%s"' % relname,
+ stacklevel=2)
+ return checkvfs
+
def close(self):
self._writecaches()
@@ -44,6 +44,11 @@
> wl.release()
> lo.release()
>
+ > @command(b'no-wlock-write', [], '')
+ > def nowlockwrite(ui, repo):
+ > with repo.vfs(b'branch', 'a'):
+ > pass
+ >
> @command(b'stripintr', [], '')
> def stripintr(ui, repo):
> lo = repo.lock()
@@ -104,6 +109,11 @@
$ hg properlocking
$ hg nowaitlocking
+Writing without lock
+
+ $ hg no-wlock-write
+ devel-warn: write with no wlock: "branch" at: $TESTTMP/buggylocking.py:* (nowlockwrite) (glob)
+
Stripping from a transaction
$ echo a > a