fix backtrace printed when cannot get lock.
change lock error handling code so exceptions have useful info and
exception handling in one place.
add test case for when cannot get lock.
--- a/mercurial/commands.py Sun Mar 26 22:54:05 2006 +0200
+++ b/mercurial/commands.py Tue Mar 28 09:01:07 2006 -0800
@@ -1244,12 +1244,8 @@
should properly record copied files, this information is not yet
fully used by merge, nor fully reported by log.
"""
- try:
- wlock = repo.wlock(0)
- errs, copied = docopy(ui, repo, pats, opts, wlock)
- except lock.LockHeld, inst:
- ui.warn(_("repository lock held by %s\n") % inst.args[0])
- errs = 1
+ wlock = repo.wlock(0)
+ errs, copied = docopy(ui, repo, pats, opts, wlock)
return errs
def debugancestor(ui, index, rev1, rev2):
@@ -2256,18 +2252,14 @@
should properly record rename files, this information is not yet
fully used by merge, nor fully reported by log.
"""
- try:
- wlock = repo.wlock(0)
- errs, copied = docopy(ui, repo, pats, opts, wlock)
- names = []
- for abs, rel, exact in copied:
- if ui.verbose or not exact:
- ui.status(_('removing %s\n') % rel)
- names.append(abs)
- repo.remove(names, True, wlock)
- except lock.LockHeld, inst:
- ui.warn(_("repository lock held by %s\n") % inst.args[0])
- errs = 1
+ wlock = repo.wlock(0)
+ errs, copied = docopy(ui, repo, pats, opts, wlock)
+ names = []
+ for abs, rel, exact in copied:
+ if ui.verbose or not exact:
+ ui.status(_('removing %s\n') % rel)
+ names.append(abs)
+ repo.remove(names, True, wlock)
return errs
def revert(ui, repo, *pats, **opts):
@@ -3252,6 +3244,15 @@
sys.exit(1)
except hg.RepoError, inst:
u.warn(_("abort: "), inst, "!\n")
+ except lock.LockHeld, inst:
+ if inst.errno == errno.ETIMEDOUT:
+ reason = _('timed out waiting for lock held by %s') % inst.locker
+ else:
+ reason = _('lock held by %s') % inst.locker
+ u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
+ except lock.LockUnavailable, inst:
+ u.warn(_("abort: could not lock %s: %s\n") %
+ (inst.desc or inst.filename, inst.strerror))
except revlog.RevlogError, inst:
u.warn(_("abort: "), inst, "!\n")
except SignalInterrupt:
--- a/mercurial/localrepo.py Sun Mar 26 22:54:05 2006 +0200
+++ b/mercurial/localrepo.py Tue Mar 28 09:01:07 2006 -0800
@@ -31,6 +31,7 @@
raise repo.RepoError(_("repository %s not found") % path)
self.root = os.path.abspath(path)
+ self.origroot = path
self.ui = ui.ui(parentui=parentui)
self.opener = util.opener(self.path)
self.wopener = util.opener(self.root)
@@ -261,32 +262,31 @@
self.tagscache = None
self.nodetagscache = None
- def do_lock(self, lockname, wait, releasefn=None, acquirefn=None):
+ def do_lock(self, lockname, wait, releasefn=None, acquirefn=None,
+ desc=None):
try:
- l = lock.lock(self.join(lockname), 0, releasefn)
+ l = lock.lock(self.join(lockname), 0, releasefn, desc=desc)
except lock.LockHeld, inst:
if not wait:
- raise inst
- self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0])
- try:
- # default to 600 seconds timeout
- l = lock.lock(self.join(lockname),
- int(self.ui.config("ui", "timeout") or 600),
- releasefn)
- except lock.LockHeld, inst:
- raise util.Abort(_("timeout while waiting for "
- "lock held by %s") % inst.args[0])
+ raise
+ self.ui.warn(_("waiting for lock on %s held by %s\n") %
+ (desc, inst.args[0]))
+ # default to 600 seconds timeout
+ l = lock.lock(self.join(lockname),
+ int(self.ui.config("ui", "timeout") or 600),
+ releasefn, desc=desc)
if acquirefn:
acquirefn()
return l
def lock(self, wait=1):
- return self.do_lock("lock", wait, acquirefn=self.reload)
+ return self.do_lock("lock", wait, acquirefn=self.reload,
+ desc=_('repository %s') % self.origroot)
def wlock(self, wait=1):
- return self.do_lock("wlock", wait,
- self.dirstate.write,
- self.wreload)
+ return self.do_lock("wlock", wait, self.dirstate.write,
+ self.wreload,
+ desc=_('working directory of %s') % self.origroot)
def checkfilemerge(self, filename, text, filelog, manifest1, manifest2):
"determine whether a new filenode is needed"
--- a/mercurial/lock.py Sun Mar 26 22:54:05 2006 +0200
+++ b/mercurial/lock.py Tue Mar 28 09:01:07 2006 -0800
@@ -8,10 +8,16 @@
from demandload import *
demandload(globals(), 'errno os socket time util')
-class LockException(Exception):
- pass
+class LockException(IOError):
+ def __init__(self, errno, strerror, filename, desc):
+ IOError.__init__(self, errno, strerror, filename)
+ self.desc = desc
+
class LockHeld(LockException):
- pass
+ def __init__(self, errno, filename, desc, locker):
+ LockException.__init__(self, errno, 'Lock held', filename, desc)
+ self.locker = locker
+
class LockUnavailable(LockException):
pass
@@ -24,7 +30,7 @@
# old-style lock: symlink to pid
# new-style lock: symlink to hostname:pid
- def __init__(self, file, timeout=-1, releasefn=None):
+ def __init__(self, file, timeout=-1, releasefn=None, desc=None):
self.f = file
self.held = 0
self.timeout = timeout
@@ -32,6 +38,7 @@
self.id = None
self.host = None
self.pid = None
+ self.desc = desc
self.lock()
def __del__(self):
@@ -49,7 +56,8 @@
if timeout > 0:
timeout -= 1
continue
- raise inst
+ raise LockHeld(errno.ETIMEDOUT, inst.filename, self.desc,
+ inst.locker)
def trylock(self):
if self.id is None:
@@ -64,9 +72,11 @@
if why.errno == errno.EEXIST:
locker = self.testlock()
if locker:
- raise LockHeld(locker)
+ raise LockHeld(errno.EAGAIN, self.f, self.desc,
+ locker)
else:
- raise LockUnavailable(why)
+ raise LockUnavailable(why.errno, why.strerror,
+ why.filename, self.desc)
def testlock(self):
'''return id of locker if lock is valid, else None.'''
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-lock-badness Tue Mar 28 09:01:07 2006 -0800
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+hg init a
+echo a > a/a
+hg --cwd a ci -A -m a
+hg clone a b
+echo b > b/b
+hg --cwd b ci -A -m b
+chmod 100 a/.hg
+hg --cwd b push ../a
+chmod 700 a/.hg
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-lock-badness.out Tue Mar 28 09:01:07 2006 -0800
@@ -0,0 +1,4 @@
+adding a
+adding b
+pushing to ../a
+abort: could not lock repository ../a: Permission denied