Make repo locks recursive, eliminate all passing of lock/wlock
authorMatt Mackall <mpm@selenic.com>
Sat, 21 Jul 2007 16:02:10 -0500
changeset 4917 126f527b3ba3
parent 4916 5c5d23d93447
child 4918 e017d3a82e1d
Make repo locks recursive, eliminate all passing of lock/wlock
hgext/fetch.py
hgext/mq.py
hgext/transplant.py
mercurial/cmdutil.py
mercurial/commands.py
mercurial/hg.py
mercurial/localrepo.py
mercurial/merge.py
mercurial/patch.py
--- a/hgext/fetch.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/hgext/fetch.py	Sat Jul 21 16:02:10 2007 -0500
@@ -19,38 +19,38 @@
     merged, and the result of the merge is committed.  Otherwise, the
     working directory is updated.'''
 
-    def postincoming(other, modheads, lock, wlock):
+    def postincoming(other, modheads):
         if modheads == 0:
             return 0
         if modheads == 1:
-            return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
+            return hg.clean(repo, repo.changelog.tip())
         newheads = repo.heads(parent)
         newchildren = [n for n in repo.heads(parent) if n != parent]
         newparent = parent
         if newchildren:
             newparent = newchildren[0]
-            hg.clean(repo, newparent, wlock=wlock)
+            hg.clean(repo, newparent)
         newheads = [n for n in repo.heads() if n != newparent]
         err = False
         if newheads:
             ui.status(_('merging with new head %d:%s\n') %
                       (repo.changelog.rev(newheads[0]), short(newheads[0])))
-            err = hg.merge(repo, newheads[0], remind=False, wlock=wlock)
+            err = hg.merge(repo, newheads[0], remind=False)
         if not err and len(newheads) > 1:
             ui.status(_('not merging with %d other new heads '
                         '(use "hg heads" and "hg merge" to merge them)') %
                       (len(newheads) - 1))
         if not err:
-            mod, add, rem = repo.status(wlock=wlock)[:3]
+            mod, add, rem = repo.status()[:3]
             message = (cmdutil.logmessage(opts) or
                        (_('Automated merge with %s') % other.url()))
             n = repo.commit(mod + add + rem, message,
-                            opts['user'], opts['date'], lock=lock, wlock=wlock,
+                            opts['user'], opts['date'],
                             force_editor=opts.get('force_editor'))
             ui.status(_('new changeset %d:%s merges remote changes '
                         'with local\n') % (repo.changelog.rev(n),
                                            short(n)))
-    def pull(lock, wlock):
+    def pull():
         cmdutil.setremoteconfig(ui, opts)
 
         other = hg.repository(ui, ui.expandpath(source))
@@ -60,8 +60,8 @@
             raise util.Abort(_("fetch -r doesn't work for remote repositories yet"))
         elif opts['rev']:
             revs = [other.lookup(rev) for rev in opts['rev']]
-        modheads = repo.pull(other, heads=revs, lock=lock)
-        return postincoming(other, modheads, lock, wlock)
+        modheads = repo.pull(other, heads=revs)
+        return postincoming(other, modheads)
 
     parent, p2 = repo.dirstate.parents()
     if parent != repo.changelog.tip():
@@ -73,13 +73,13 @@
     try:
         wlock = repo.wlock()
         lock = repo.lock()
-        mod, add, rem = repo.status(wlock=wlock)[:3]
+        mod, add, rem = repo.status()[:3]
         if mod or add or rem:
             raise util.Abort(_('outstanding uncommitted changes'))
         if len(repo.heads()) > 1:
             raise util.Abort(_('multiple heads in this repository '
                                '(use "hg heads" and "hg merge" to merge)'))
-        return pull(lock, wlock)
+        return pull()
     finally:
         del lock, wlock
 
--- a/hgext/mq.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/hgext/mq.py	Sat Jul 21 16:02:10 2007 -0500
@@ -323,10 +323,10 @@
         patch.diff(repo, node1, node2, fns, match=matchfn,
                    fp=fp, changes=changes, opts=self.diffopts())
 
-    def mergeone(self, repo, mergeq, head, patch, rev, wlock):
+    def mergeone(self, repo, mergeq, head, patch, rev):
         # first try just applying the patch
         (err, n) = self.apply(repo, [ patch ], update_status=False,
-                              strict=True, merge=rev, wlock=wlock)
+                              strict=True, merge=rev)
 
         if err == 0:
             return (err, n)
@@ -337,15 +337,14 @@
         self.ui.warn("patch didn't work out, merging %s\n" % patch)
 
         # apply failed, strip away that rev and merge.
-        hg.clean(repo, head, wlock=wlock)
-        self.strip(repo, n, update=False, backup='strip', wlock=wlock)
+        hg.clean(repo, head)
+        self.strip(repo, n, update=False, backup='strip')
 
         ctx = repo.changectx(rev)
-        ret = hg.merge(repo, rev, wlock=wlock)
+        ret = hg.merge(repo, rev)
         if ret:
             raise util.Abort(_("update returned %d") % ret)
-        n = repo.commit(None, ctx.description(), ctx.user(),
-                        force=1, wlock=wlock)
+        n = repo.commit(None, ctx.description(), ctx.user(), force=1)
         if n == None:
             raise util.Abort(_("repo commit failed"))
         try:
@@ -381,7 +380,7 @@
                 return pp[1]
         return pp[0]
 
-    def mergepatch(self, repo, mergeq, series, wlock):
+    def mergepatch(self, repo, mergeq, series):
         if len(self.applied) == 0:
             # each of the patches merged in will have two parents.  This
             # can confuse the qrefresh, qdiff, and strip code because it
@@ -390,8 +389,7 @@
             # the first patch in the queue is never a merge patch
             #
             pname = ".hg.patches.merge.marker"
-            n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
-                            wlock=wlock)
+            n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
             self.removeundo(repo)
             self.applied.append(statusentry(revlog.hex(n), pname))
             self.applied_dirty = 1
@@ -412,7 +410,7 @@
                 self.ui.warn("patch %s is not applied\n" % patch)
                 return (1, None)
             rev = revlog.bin(info[1])
-            (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
+            (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
             if head:
                 self.applied.append(statusentry(revlog.hex(head), patch))
                 self.applied_dirty = 1
@@ -437,18 +435,15 @@
         return (True, files, fuzz)
 
     def apply(self, repo, series, list=False, update_status=True,
-              strict=False, patchdir=None, merge=None, wlock=None,
-              all_files={}):
-        lock = tr = None
+              strict=False, patchdir=None, merge=None, all_files={}):
+        wlock = lock = tr = None
         try:
-            if not wlock:
-                wlock = repo.wlock()
+            wlock = repo.wlock()
             lock = repo.lock()
             tr = repo.transaction()
             try:
                 ret = self._apply(tr, repo, series, list, update_status,
-                                  strict, patchdir, merge, wlock,
-                                  lock=lock, all_files=all_files)
+                                  strict, patchdir, merge, all_files=all_files)
                 tr.close()
                 self.save_dirty()
                 return ret
@@ -463,8 +458,7 @@
             del lock, wlock, tr
 
     def _apply(self, tr, repo, series, list=False, update_status=True,
-               strict=False, patchdir=None, merge=None, wlock=None,
-               lock=None, all_files={}):
+               strict=False, patchdir=None, merge=None, all_files={}):
         # TODO unify with commands.py
         if not patchdir:
             patchdir = self.path
@@ -511,9 +505,8 @@
                     repo.dirstate.merge(f)
                 p1, p2 = repo.dirstate.parents()
                 repo.dirstate.setparents(p1, merge)
-            files = patch.updatedir(self.ui, repo, files, wlock=wlock)
-            n = repo.commit(files, message, user, date, force=1, lock=lock,
-                            wlock=wlock)
+            files = patch.updatedir(self.ui, repo, files)
+            n = repo.commit(files, message, user, date, force=1)
 
             if n == None:
                 raise util.Abort(_("repo commit failed"))
@@ -623,10 +616,9 @@
         try:
             insert = self.full_series_end()
             if msg:
-                n = repo.commit(commitfiles, msg, force=True, wlock=wlock)
+                n = repo.commit(commitfiles, msg, force=True)
             else:
-                n = repo.commit(commitfiles,
-                                "[mq]: %s" % patch, force=True, wlock=wlock)
+                n = repo.commit(commitfiles, "[mq]: %s" % patch, force=True)
             if n == None:
                 raise util.Abort(_("repo commit failed"))
             self.full_series[insert:insert] = [patch]
@@ -648,17 +640,16 @@
         finally:
             del wlock
 
-    def strip(self, repo, rev, update=True, backup="all", wlock=None):
-        lock = None
+    def strip(self, repo, rev, update=True, backup="all"):
+        wlock = lock = None
         try:
-            if not wlock:
-                wlock = repo.wlock()
+            wlock = repo.wlock()
             lock = repo.lock()
 
             if update:
                 self.check_localchanges(repo, refresh=False)
                 urev = self.qparents(repo, rev)
-                hg.clean(repo, urev, wlock=wlock)
+                hg.clean(repo, urev)
                 repo.dirstate.write()
 
             self.removeundo(repo)
@@ -748,9 +739,8 @@
         raise util.Abort(_("patch %s not in series") % patch)
 
     def push(self, repo, patch=None, force=False, list=False,
-             mergeq=None, wlock=None):
-        if not wlock:
-            wlock = repo.wlock()
+             mergeq=None):
+        wlock = repo.wlock()
         try:
             patch = self.lookup(patch)
             # Suppose our series file is: A B C and the current 'top'
@@ -794,15 +784,14 @@
             all_files = {}
             try:
                 if mergeq:
-                    ret = self.mergepatch(repo, mergeq, s, wlock)
+                    ret = self.mergepatch(repo, mergeq, s)
                 else:
-                    ret = self.apply(repo, s, list, wlock=wlock,
-                                     all_files=all_files)
+                    ret = self.apply(repo, s, list, all_files=all_files)
             except:
                 self.ui.warn(_('cleaning up working directory...'))
                 node = repo.dirstate.parents()[0]
-                hg.revert(repo, node, None, wlock)
-                unknown = repo.status(wlock=wlock)[4]
+                hg.revert(repo, node, None)
+                unknown = repo.status()[4]
                 # only remove unknown files that we know we touched or
                 # created while patching
                 for f in unknown:
@@ -820,14 +809,12 @@
         finally:
             del wlock
 
-    def pop(self, repo, patch=None, force=False, update=True, all=False,
-            wlock=None):
+    def pop(self, repo, patch=None, force=False, update=True, all=False):
         def getfile(f, rev):
             t = repo.file(f).read(rev)
             repo.wfile(f, "w").write(t)
 
-        if not wlock:
-            wlock = repo.wlock()
+        wlock = repo.wlock()
         try:
             if patch:
                 # index, rev, patch
@@ -899,7 +886,7 @@
                     except: pass
                     repo.dirstate.forget(f)
                 repo.dirstate.setparents(qp, revlog.nullid)
-            self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
+            self.strip(repo, rev, update=False, backup='strip')
             del self.applied[start:end]
             if len(self.applied):
                 self.ui.write("Now at: %s\n" % self.applied[-1].name)
@@ -1075,9 +1062,9 @@
                     message = msg
 
                 self.strip(repo, top, update=False,
-                           backup='strip', wlock=wlock)
+                           backup='strip')
                 n = repo.commit(filelist, message, changes[1], match=matchfn,
-                                force=1, wlock=wlock)
+                                force=1)
                 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
                 self.applied_dirty = 1
                 self.removeundo(repo)
@@ -1097,8 +1084,8 @@
                     # forget the file copies in the dirstate
                     # push should readd the files later on
                     repo.dirstate.forget(a)
-                self.pop(repo, force=True, wlock=wlock)
-                self.push(repo, force=True, wlock=wlock)
+                self.pop(repo, force=True)
+                self.push(repo, force=True)
         finally:
             del wlock
 
@@ -1898,9 +1885,9 @@
         wlock = r.wlock()
         try:
             if r.dirstate[name] == 'r':
-                r.undelete([name], wlock)
-            r.copy(patch, name, wlock)
-            r.remove([patch], False, wlock)
+                r.undelete([name])
+            r.copy(patch, name)
+            r.remove([patch], False)
         finally:
             del wlock
 
--- a/hgext/transplant.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/hgext/transplant.py	Sat Jul 21 16:02:10 2007 -0500
@@ -119,9 +119,8 @@
                         continue
                     if pulls:
                         if source != repo:
-                            repo.pull(source, heads=pulls, lock=lock)
-                        merge.update(repo, pulls[-1], False, False, None,
-                                     wlock=wlock)
+                            repo.pull(source, heads=pulls)
+                        merge.update(repo, pulls[-1], False, False, None)
                         p1, p2 = repo.dirstate.parents()
                         pulls = []
 
@@ -132,7 +131,7 @@
                     # fail.
                     domerge = True
                     if not hasnode(repo, node):
-                        repo.pull(source, heads=[node], lock=lock)
+                        repo.pull(source, heads=[node])
 
                 if parents[1] != revlog.nullid:
                     self.ui.note(_('skipping merge changeset %s:%s\n')
@@ -147,11 +146,11 @@
                 del revmap[rev]
                 if patchfile or domerge:
                     try:
-                        n = self.applyone(repo, node, source.changelog.read(node),
+                        n = self.applyone(repo, node,
+                                          source.changelog.read(node),
                                           patchfile, merge=domerge,
                                           log=opts.get('log'),
-                                          filter=opts.get('filter'),
-                                          lock=lock, wlock=wlock)
+                                          filter=opts.get('filter'))
                         if n and domerge:
                             self.ui.status(_('%s merged at %s\n') % (revstr,
                                       revlog.short(n)))
@@ -162,8 +161,8 @@
                         if patchfile:
                             os.unlink(patchfile)
             if pulls:
-                repo.pull(source, heads=pulls, lock=lock)
-                merge.update(repo, pulls[-1], False, False, None, wlock=wlock)
+                repo.pull(source, heads=pulls)
+                merge.update(repo, pulls[-1], False, False, None)
         finally:
             self.saveseries(revmap, merges)
             self.transplants.write()
@@ -195,7 +194,7 @@
         return (user, date, msg)
 
     def applyone(self, repo, node, cl, patchfile, merge=False, log=False,
-                 filter=None, lock=None, wlock=None):
+                 filter=None):
         '''apply the patch in patchfile to the repository as a transplant'''
         (manifest, user, (time, timezone), files, message) = cl[:5]
         date = "%d %d" % (time, timezone)
@@ -221,7 +220,7 @@
                         self.ui.warn(_('%s: empty changeset') % revlog.hex(node))
                         return None
                 finally:
-                    files = patch.updatedir(self.ui, repo, files, wlock=wlock)
+                    files = patch.updatedir(self.ui, repo, files)
             except Exception, inst:
                 if filter:
                     os.unlink(patchfile)
@@ -239,8 +238,7 @@
             p1, p2 = repo.dirstate.parents()
             repo.dirstate.setparents(p1, node)
 
-        n = repo.commit(files, message, user, date, lock=lock, wlock=wlock,
-                        extra=extra)
+        n = repo.commit(files, message, user, date, extra=extra)
         if not merge:
             self.transplants.set(n, node)
 
@@ -282,8 +280,7 @@
                                  revlog.hex(parents[0]))
             if merge:
                 repo.dirstate.setparents(p1, parents[1])
-            n = repo.commit(None, message, user, date, wlock=wlock,
-                            extra=extra)
+            n = repo.commit(None, message, user, date, extra=extra)
             if not n:
                 raise util.Abort(_('commit failed'))
             if not merge:
--- a/mercurial/cmdutil.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/mercurial/cmdutil.py	Sat Jul 21 16:02:10 2007 -0500
@@ -628,8 +628,7 @@
         if bestname:
             yield bestname, a, bestscore
 
-def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
-              similarity=None):
+def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
     if dry_run is None:
         dry_run = opts.get('dry_run')
     if similarity is None:
@@ -649,8 +648,8 @@
             if repo.ui.verbose or not exact:
                 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
     if not dry_run:
-        repo.add(add, wlock=wlock)
-        repo.remove(remove, wlock=wlock)
+        repo.add(add)
+        repo.remove(remove)
     if similarity > 0:
         for old, new, score in findrenames(repo, add, remove, similarity):
             oldrel, oldexact = mapping[old]
@@ -660,7 +659,7 @@
                                  '(%d%% similar)\n') %
                                (oldrel, newrel, score * 100))
             if not dry_run:
-                repo.copy(old, new, wlock=wlock)
+                repo.copy(old, new)
 
 def service(opts, parentfn=None, initfn=None, runfn=None):
     '''Run a command as a service.'''
--- a/mercurial/commands.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/mercurial/commands.py	Sat Jul 21 16:02:10 2007 -0500
@@ -466,7 +466,7 @@
     except ValueError, inst:
         raise util.Abort(str(inst))
 
-def docopy(ui, repo, pats, opts, wlock):
+def docopy(ui, repo, pats, opts):
     # called with the repo lock held
     #
     # hgsep => pathname that uses "/" to separate directories
@@ -527,14 +527,14 @@
             try:
                 restore = repo.dirstate[abstarget] == 'r'
                 if restore and not opts.get('dry_run'):
-                    repo.undelete([abstarget], wlock)
+                    repo.undelete([abstarget])
                 try:
                     if not opts.get('dry_run'):
                         util.copyfile(src, target)
                     restore = False
                 finally:
                     if restore:
-                        repo.remove([abstarget], wlock=wlock)
+                        repo.remove([abstarget])
             except IOError, inst:
                 if inst.errno == errno.ENOENT:
                     ui.warn(_('%s: deleted in working copy\n') % relsrc)
@@ -553,9 +553,9 @@
                               "data will be stored for %s.\n")
                             % (repo.pathto(origsrc, cwd), reltarget))
                 if abstarget not in repo.dirstate and not opts.get('dry_run'):
-                    repo.add([abstarget], wlock)
+                    repo.add([abstarget])
             elif not opts.get('dry_run'):
-                repo.copy(origsrc, abstarget, wlock)
+                repo.copy(origsrc, abstarget)
         copied.append((abssrc, relsrc, exact))
 
     # pat: ossep
@@ -677,7 +677,7 @@
     """
     wlock = repo.wlock(False)
     try:
-        errs, copied = docopy(ui, repo, pats, opts, wlock)
+        errs, copied = docopy(ui, repo, pats, opts)
     finally:
         del wlock
     return errs
@@ -1627,7 +1627,7 @@
                     p2 = repo.lookup(p2 or hex(nullid))
 
                     if p1 != wp[0].node():
-                        hg.clean(repo, p1, wlock=wlock)
+                        hg.clean(repo, p1)
                     repo.dirstate.setparents(p1, p2)
                 elif p2:
                     try:
@@ -1645,12 +1645,11 @@
                     fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
                                        files=files)
                 finally:
-                    files = patch.updatedir(ui, repo, files, wlock=wlock)
-                n = repo.commit(files, message, user, date, wlock=wlock,
-                                lock=lock)
+                    files = patch.updatedir(ui, repo, files)
+                n = repo.commit(files, message, user, date)
                 if opts.get('exact'):
                     if hex(n) != nodeid:
-                        repo.rollback(wlock=wlock, lock=lock)
+                        repo.rollback()
                         raise util.Abort(_('patch is damaged' +
                                            ' or loses information'))
             finally:
@@ -2261,14 +2260,14 @@
     """
     wlock = repo.wlock(False)
     try:
-        errs, copied = docopy(ui, repo, pats, opts, wlock)
+        errs, copied = docopy(ui, repo, pats, opts)
         names = []
         for abs, rel, exact in copied:
             if ui.verbose or not exact:
                 ui.status(_('removing %s\n') % rel)
             names.append(abs)
         if not opts.get('dry_run'):
-            repo.remove(names, True, wlock=wlock)
+            repo.remove(names, True)
         return errs
     finally:
         del wlock
@@ -2359,7 +2358,7 @@
             names[abs] = (rel, exact)
             target_only[abs] = True
 
-        changes = repo.status(match=names.has_key, wlock=wlock)[:5]
+        changes = repo.status(match=names.has_key)[:5]
         modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
 
         revert = ([], _('reverting %s\n'))
@@ -2432,7 +2431,7 @@
         if not opts.get('dry_run'):
             for f in forget[0]:
                 repo.dirstate.forget(f)
-            r = hg.revert(repo, node, update.has_key, wlock)
+            r = hg.revert(repo, node, update.has_key)
             for f in add[0]:
                 repo.dirstate.add(f)
             for f in undelete[0]:
--- a/mercurial/hg.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/mercurial/hg.py	Sat Jul 21 16:02:10 2007 -0500
@@ -237,7 +237,7 @@
 def update(repo, node):
     """update the working directory to node, merging linear changes"""
     pl = repo.parents()
-    stats = _merge.update(repo, node, False, False, None, None)
+    stats = _merge.update(repo, node, False, False, None)
     _showstats(repo, stats)
     if stats[3]:
         repo.ui.status(_("There are unresolved merges with"
@@ -251,15 +251,15 @@
                        % (pl[0].rev(), repo.changectx(node).rev()))
     return stats[3]
 
-def clean(repo, node, wlock=None, show_stats=True):
+def clean(repo, node, show_stats=True):
     """forcibly switch the working directory to node, clobbering changes"""
-    stats = _merge.update(repo, node, False, True, None, wlock)
+    stats = _merge.update(repo, node, False, True, None)
     if show_stats: _showstats(repo, stats)
     return stats[3]
 
-def merge(repo, node, force=None, remind=True, wlock=None):
+def merge(repo, node, force=None, remind=True):
     """branch merge with node, resolving changes"""
-    stats = _merge.update(repo, node, True, force, False, wlock)
+    stats = _merge.update(repo, node, True, force, False)
     _showstats(repo, stats)
     if stats[3]:
         pl = repo.parents()
@@ -272,9 +272,9 @@
         repo.ui.status(_("(branch merge, don't forget to commit)\n"))
     return stats[3]
 
-def revert(repo, node, choose, wlock):
+def revert(repo, node, choose):
     """revert changes to revision in node without updating dirstate"""
-    return _merge.update(repo, node, False, True, choose, wlock)[3]
+    return _merge.update(repo, node, False, True, choose)[3]
 
 def verify(repo):
     """verify the consistency of a repository"""
--- a/mercurial/localrepo.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/mercurial/localrepo.py	Sat Jul 21 16:02:10 2007 -0500
@@ -530,12 +530,11 @@
         finally:
             del l
 
-    def rollback(self, wlock=None, lock=None):
+    def rollback(self):
+        wlock = lock = None
         try:
-            if not wlock:
-                wlock = self.wlock()
-            if not lock:
-                lock = self.lock()
+            wlock = self.wlock()
+            lock = self.lock()
             if os.path.exists(self.sjoin("undo")):
                 self.ui.status(_("rolling back last transaction\n"))
                 transaction.rollback(self.sopener, self.sjoin("undo"))
@@ -570,13 +569,23 @@
         return l
 
     def lock(self, wait=True):
-        return self._lock(self.sjoin("lock"), wait, None, self.invalidate,
-                          _('repository %s') % self.origroot)
+        if self._lockref and self._lockref():
+            return self._lockref()
+
+        l = self._lock(self.sjoin("lock"), wait, None, self.invalidate,
+                       _('repository %s') % self.origroot)
+        self._lockref = weakref.ref(l)
+        return l
 
     def wlock(self, wait=True):
-        return self._lock(self.join("wlock"), wait, self.dirstate.write,
-                          self.dirstate.invalidate,
-                          _('working directory of %s') % self.origroot)
+        if self._wlockref and self._wlockref():
+            return self._wlockref()
+
+        l = self._lock(self.join("wlock"), wait, self.dirstate.write,
+                       self.dirstate.invalidate, _('working directory of %s') %
+                       self.origroot)
+        self._wlockref = weakref.ref(l)
+        return l
 
     def filecommit(self, fn, manifest1, manifest2, linkrev, transaction, changelist):
         """
@@ -638,16 +647,16 @@
         changelist.append(fn)
         return fl.add(t, meta, transaction, linkrev, fp1, fp2)
 
-    def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None, extra={}):
+    def rawcommit(self, files, text, user, date, p1=None, p2=None, extra={}):
         if p1 is None:
             p1, p2 = self.dirstate.parents()
         return self.commit(files=files, text=text, user=user, date=date,
-                           p1=p1, p2=p2, wlock=wlock, extra=extra)
+                           p1=p1, p2=p2, extra=extra)
 
     def commit(self, files=None, text="", user=None, date=None,
-               match=util.always, force=False, lock=None, wlock=None,
-               force_editor=False, p1=None, p2=None, extra={}):
-        tr = None
+               match=util.always, force=False, force_editor=False,
+               p1=None, p2=None, extra={}):
+        wlock = lock = tr = None
         try:
             commit = []
             remove = []
@@ -707,10 +716,8 @@
 
             self.hook("precommit", throw=True, parent1=xp1, parent2=xp2)
 
-            if not wlock:
-                wlock = self.wlock()
-            if not lock:
-                lock = self.lock()
+            wlock = self.wlock()
+            lock = self.lock()
             tr = self.transaction()
 
             # check in files
@@ -854,7 +861,7 @@
                 yield src, fn
 
     def status(self, node1=None, node2=None, files=[], match=util.always,
-                wlock=None, list_ignored=False, list_clean=False):
+               list_ignored=False, list_clean=False):
         """return status of files between two nodes or node and working directory
 
         If node1 is None, use the first dirstate parent instead.
@@ -908,18 +915,17 @@
 
                     # update dirstate for files that are actually clean
                     if fixup:
-                        fixlock = wlock
+                        wlock = None
                         try:
-                            if not fixlock:
-                                try:
-                                    fixlock = self.wlock(False)
-                                except lock.LockException:
-                                    pass
-                            if fixlock:
+                            try:
+                                wlock = self.wlock(False)
+                            except lock.LockException:
+                                pass
+                            if wlock:
                                 for f in fixup:
                                     self.dirstate.normal(f)
                         finally:
-                            del fixlock
+                            del wlock
             else:
                 # we are comparing working dir against non-parent
                 # generate a pseudo-manifest for the working dir
@@ -966,10 +972,9 @@
             l.sort()
         return (modified, added, removed, deleted, unknown, ignored, clean)
 
-    def add(self, list, wlock=None):
+    def add(self, list):
+        wlock = self.wlock()
         try:
-            if not wlock:
-                wlock = self.wlock()
             for f in list:
                 p = self.wjoin(f)
                 try:
@@ -992,10 +997,9 @@
         finally:
             del wlock
 
-    def forget(self, list, wlock=None):
+    def forget(self, list):
+        wlock = self.wlock()
         try:
-            if not wlock:
-                wlock = self.wlock()
             for f in list:
                 if self.dirstate[f] != 'a':
                     self.ui.warn(_("%s not added!\n") % f)
@@ -1004,7 +1008,8 @@
         finally:
             del wlock
 
-    def remove(self, list, unlink=False, wlock=None):
+    def remove(self, list, unlink=False):
+        wlock = None
         try:
             if unlink:
                 for f in list:
@@ -1013,8 +1018,7 @@
                     except OSError, inst:
                         if inst.errno != errno.ENOENT:
                             raise
-            if not wlock:
-                wlock = self.wlock()
+            wlock = self.wlock()
             for f in list:
                 if unlink and os.path.exists(self.wjoin(f)):
                     self.ui.warn(_("%s still exists!\n") % f)
@@ -1027,13 +1031,13 @@
         finally:
             del wlock
 
-    def undelete(self, list, wlock=None):
+    def undelete(self, list):
+        wlock = None
         try:
             p = self.dirstate.parents()[0]
             mn = self.changelog.read(p)[0]
             m = self.manifest.read(mn)
-            if not wlock:
-                wlock = self.wlock()
+            wlock = self.wlock()
             for f in list:
                 if self.dirstate[f] != 'r':
                     self.ui.warn("%s not removed!\n" % f)
@@ -1044,7 +1048,8 @@
         finally:
             del wlock
 
-    def copy(self, source, dest, wlock=None):
+    def copy(self, source, dest):
+        wlock = None
         try:
             p = self.wjoin(dest)
             if not (os.path.exists(p) or os.path.islink(p)):
@@ -1053,8 +1058,7 @@
                 self.ui.warn(_("copy failed: %s is not a file or a "
                                "symbolic link\n") % dest)
             else:
-                if not wlock:
-                    wlock = self.wlock()
+                wlock = self.wlock()
                 if dest not in self.dirstate:
                     self.dirstate.add(dest)
                 self.dirstate.copy(source, dest)
@@ -1336,10 +1340,9 @@
         else:
             return subset
 
-    def pull(self, remote, heads=None, force=False, lock=None):
+    def pull(self, remote, heads=None, force=False):
+        lock = self.lock()
         try:
-            if not lock:
-                lock = self.lock()
             fetch = self.findincoming(remote, force=force)
             if fetch == [nullid]:
                 self.ui.status(_("requesting all changes\n"))
--- a/mercurial/merge.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/mercurial/merge.py	Sat Jul 21 16:02:10 2007 -0500
@@ -496,20 +496,17 @@
                 if f:
                     repo.dirstate.forget(f)
 
-def update(repo, node, branchmerge, force, partial, wlock):
+def update(repo, node, branchmerge, force, partial):
     """
     Perform a merge between the working directory and the given node
 
     branchmerge = whether to merge between branches
     force = whether to force branch merging or file overwriting
     partial = a function to filter file lists (dirstate not updated)
-    wlock = working dir lock, if already held
     """
 
+    wlock = repo.wlock()
     try:
-        if not wlock:
-            wlock = repo.wlock()
-
         wc = repo.workingctx()
         if node is None:
             # tip of current branch
--- a/mercurial/patch.py	Sat Jul 21 16:02:10 2007 -0500
+++ b/mercurial/patch.py	Sat Jul 21 16:02:10 2007 -0500
@@ -1013,7 +1013,7 @@
         ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
         ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'))
 
-def updatedir(ui, repo, patches, wlock=None):
+def updatedir(ui, repo, patches):
     '''Update dirstate after patch application according to metadata'''
     if not patches:
         return
@@ -1035,11 +1035,11 @@
     for src, dst, after in copies:
         if not after:
             copyfile(src, dst, repo.root)
-        repo.copy(src, dst, wlock=wlock)
+        repo.copy(src, dst)
     removes = removes.keys()
     if removes:
         removes.sort()
-        repo.remove(removes, True, wlock=wlock)
+        repo.remove(removes, True)
     for f in patches:
         ctype, gp = patches[f]
         if gp and gp.mode:
@@ -1050,7 +1050,7 @@
                 repo.wwrite(gp.path, '', x and 'x' or '')
             else:
                 util.set_exec(dst, x)
-    cmdutil.addremove(repo, cfiles, wlock=wlock)
+    cmdutil.addremove(repo, cfiles)
     files = patches.keys()
     files.extend([r for r in removes if r not in files])
     files.sort()