diff --git a/hgext3rd/extutil.py b/hgext3rd/extutil.py --- a/hgext3rd/extutil.py +++ b/hgext3rd/extutil.py @@ -7,15 +7,20 @@ from __future__ import absolute_import +import contextlib import errno import fcntl import os import subprocess +import time from mercurial.i18n import _ from mercurial import ( error, + lock as lockmod, pycompat, + util, + vfs as vfsmod, ) if pycompat.iswindows: @@ -169,3 +174,50 @@ fcntl.lockf(fp, fcntl.LOCK_UN) fp.close() self.fp = None + +@contextlib.contextmanager +def flock(lockpath, description, timeout=-1): + """A flock based lock object. Currently it is always non-blocking. + + Note that since it is flock based, you can accidentally take it multiple + times within one process and the first one to be released will release all + of them. So the caller needs to be careful to not create more than one + instance per lock. + """ + + # best effort lightweight lock + try: + import fcntl + fcntl.flock + except ImportError: + # fallback to Mercurial lock + vfs = vfsmod.vfs(os.path.dirname(lockpath)) + with lockmod.lock(vfs, os.path.basename(lockpath), timeout=timeout): + yield + return + # make sure lock file exists + util.makedirs(os.path.dirname(lockpath)) + with open(lockpath, 'a'): + pass + lockfd = os.open(lockpath, os.O_RDONLY, 0o664) + start = time.time() + while True: + try: + fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB) + break + except IOError as ex: + if ex.errno == errno.EAGAIN: + if timeout != -1 and time.time() - start > timeout: + raise error.LockHeld(errno.EAGAIN, lockpath, description, + '') + else: + time.sleep(0.05) + continue + raise + + try: + yield + finally: + fcntl.flock(lockfd, fcntl.LOCK_UN) + os.close(lockfd) + diff --git a/hgext3rd/fbamend/hiddenoverride.py b/hgext3rd/fbamend/hiddenoverride.py --- a/hgext3rd/fbamend/hiddenoverride.py +++ b/hgext3rd/fbamend/hiddenoverride.py @@ -7,22 +7,17 @@ from __future__ import absolute_import -import contextlib -import errno -import os -import time +from hgext3rd import extutil from mercurial.node import short from mercurial import ( dispatch, error, extensions, - lock as lockmod, obsolete, repoview, scmutil, util, - vfs as vfsmod, ) def uisetup(ui): @@ -73,55 +68,9 @@ result.update(repo.unfiltered()._bookmarks.values()) return result -@contextlib.contextmanager -def flock(lockpath, description, timeout=-1): - """A flock based lock object. Currently it is always non-blocking. - - Note that since it is flock based, you can accidentally take it multiple - times within one process and the first one to be released will release all - of them. So the caller needs to be careful to not create more than one - instance per lock. - """ - - # best effort lightweight lock - try: - import fcntl - fcntl.flock - except ImportError: - # fallback to Mercurial lock - vfs = vfsmod.vfs(os.path.dirname(lockpath)) - with lockmod.lock(vfs, os.path.basename(lockpath), timeout=timeout): - yield - return - # make sure lock file exists - util.makedirs(os.path.dirname(lockpath)) - with open(lockpath, 'a'): - pass - lockfd = os.open(lockpath, os.O_RDONLY, 0o664) - start = time.time() - while True: - try: - fcntl.flock(lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB) - break - except IOError as ex: - if ex.errno == errno.EAGAIN: - if timeout != -1 and time.time() - start > timeout: - raise error.LockHeld(errno.EAGAIN, lockpath, description, - '') - else: - time.sleep(0.05) - continue - raise - - try: - yield - finally: - fcntl.flock(lockfd, fcntl.LOCK_UN) - os.close(lockfd) - def savepinnednodes(repo, newpin, newunpin, fullargs): # take a narrowed lock so it does not affect repo lock - with flock(repo.svfs.join('obsinhibit.lock'), 'save pinned nodes'): + with extutil.flock(repo.svfs.join('obsinhibit.lock'), 'save pinned nodes'): orignodes = loadpinnednodes(repo) nodes = set(orignodes) nodes |= set(newpin)