mercurial/lock.py
changeset 35208 1b758105b5c7
parent 32088 0d892d820a51
child 35209 9153871d50e0
--- a/mercurial/lock.py	Wed Nov 29 21:00:02 2017 -0500
+++ b/mercurial/lock.py	Wed Nov 29 20:36:29 2017 -0500
@@ -14,6 +14,8 @@
 import time
 import warnings
 
+from .i18n import _
+
 from . import (
     encoding,
     error,
@@ -39,6 +41,50 @@
                 raise
     return result
 
+def trylock(ui, vfs, lockname, timeout, *args, **kwargs):
+    """return an acquired lock or raise an a LockHeld exception
+
+    This function is responsible to issue warnings about the held lock while
+    trying to acquires it."""
+
+    def printwarning(printer, locker):
+        """issue the usual "waiting on lock" message through any channel"""
+        # show more details for new-style locks
+        if ':' in locker:
+            host, pid = locker.split(":", 1)
+            msg = _("waiting for lock on %s held by process %r "
+                    "on host %r\n") % (l.desc, pid, host)
+        else:
+            msg = _("waiting for lock on %s held by %r\n") % (l.desc, locker)
+        printer(msg)
+
+    l = lock(vfs, lockname, 0, *args, dolock=False, **kwargs)
+
+    warningidx = 0
+    if not timeout:
+        warningidx = -1
+
+    delay = 0
+    while True:
+        try:
+            l._trylock()
+            break
+        except error.LockHeld as inst:
+            if delay == warningidx:
+                printwarning(ui.warn, inst.locker)
+            if timeout <= delay:
+                raise error.LockHeld(errno.ETIMEDOUT, inst.filename,
+                                     l.desc, inst.locker)
+            time.sleep(1)
+            delay += 1
+
+    l.delay = delay
+    if l.delay:
+        ui.warn(_("got lock after %s seconds\n") % l.delay)
+    if l.acquirefn:
+        l.acquirefn()
+    return l
+
 class lock(object):
     '''An advisory lock held by one process to control access to a set
     of files.  Non-cooperating processes or incorrectly written scripts
@@ -60,7 +106,8 @@
     _host = None
 
     def __init__(self, vfs, file, timeout=-1, releasefn=None, acquirefn=None,
-                 desc=None, inheritchecker=None, parentlock=None):
+                 desc=None, inheritchecker=None, parentlock=None,
+                 dolock=True):
         self.vfs = vfs
         self.f = file
         self.held = 0
@@ -74,9 +121,10 @@
         self._inherited = False
         self.postrelease  = []
         self.pid = self._getpid()
-        self.delay = self.lock()
-        if self.acquirefn:
-            self.acquirefn()
+        if dolock:
+            self.delay = self.lock()
+            if self.acquirefn:
+                self.acquirefn()
 
     def __enter__(self):
         return self