Mercurial > hg-stable
changeset 8552:06561793778e
inotify: Separate query sending logic from Server starting.
Use a decorator around the public statusquery method of Client:
start_server(query_to_server):
try:
query_to_server()
except QueryFailed:
[error recovery, inotify Server (re)starting]
query_to_server()
This way, introducing a new xxxquery Client method is easy:
one has only to code the protocol part of xxxquery, ignoring errors,
and decorating it using start_server to handle server recovery
and (re)starts
author | Nicolas Dumazet <nicdumz.commits@gmail.com> |
---|---|
date | Tue, 07 Apr 2009 19:30:01 +0900 |
parents | 7089d9727867 |
children | e387ecd7a6ed |
files | hgext/inotify/__init__.py hgext/inotify/client.py |
diffstat | 2 files changed, 68 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/inotify/__init__.py Tue Apr 07 18:39:34 2009 +0900 +++ b/hgext/inotify/__init__.py Tue Apr 07 19:30:01 2009 +0900 @@ -13,9 +13,9 @@ from mercurial.i18n import _ from mercurial import cmdutil, util -import errno, os, server, socket +import os, server from weakref import proxy -from client import client +from client import client, QueryFailed def serve(ui, repo, **opts): '''start an inotify server for this repository''' @@ -55,12 +55,16 @@ files = match.files() if '.' in files: files = [] - cli = client(ui, repo) - try: - if not ignored and not self.inotifyserver: + if not ignored and not self.inotifyserver: + cli = client(ui, repo) + try: result = cli.statusquery(files, match, False, - clean, unknown) - if result and ui.config('inotify', 'debug'): + clean, unknown) + except QueryFailed, instr: + ui.debug(str(instr)) + pass + else: + if ui.config('inotify', 'debug'): r2 = super(inotifydirstate, self).status( match, False, clean, unknown) for c,a,b in zip('LMARDUIC', result, r2): @@ -71,46 +75,7 @@ if f not in a: ui.warn('*** inotify: %s -%s\n' % (c, f)) result = r2 - - if result is not None: - return result - except (OSError, socket.error), err: - autostart = ui.configbool('inotify', 'autostart', True) - - if err[0] == errno.ECONNREFUSED: - ui.warn(_('(found dead inotify server socket; ' - 'removing it)\n')) - os.unlink(repo.join('inotify.sock')) - if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart: - ui.debug(_('(starting inotify server)\n')) - try: - try: - server.start(ui, repo) - except server.AlreadyStartedException, inst: - # another process may have started its own - # inotify server while this one was starting. - ui.debug(str(inst)) - except Exception, inst: - ui.warn(_('could not start inotify server: ' - '%s\n') % inst) - else: - # server is started, send query again - try: - return cli.statusquery(files, match, ignored, - clean, unknown) - except socket.error, err: - ui.warn(_('could not talk to new inotify ' - 'server: %s\n') % err[-1]) - elif err[0] in (errno.ECONNREFUSED, errno.ENOENT): - # silently ignore normal errors if autostart is False - ui.debug(_('(inotify server not running)\n')) - else: - ui.warn(_('failed to contact inotify server: %s\n') - % err[-1]) - ui.traceback() - # replace by old status function - self.status = super(inotifydirstate, self).status - + return result return super(inotifydirstate, self).status( match, ignored, clean, unknown)
--- a/hgext/inotify/client.py Tue Apr 07 18:39:34 2009 +0900 +++ b/hgext/inotify/client.py Tue Apr 07 19:30:01 2009 +0900 @@ -8,8 +8,58 @@ # GNU General Public License version 2, incorporated herein by reference. from mercurial.i18n import _ -import common -import os, socket, struct +import common, server +import errno, os, socket, struct + +class QueryFailed(Exception): pass + +def start_server(function): + """ + Decorator. + Tries to call function, if it fails, try to (re)start inotify server. + Raise QueryFailed if something went wrong + """ + def decorated_function(self, *args): + result = None + try: + return function(self, *args) + except (OSError, socket.error), err: + autostart = self.ui.configbool('inotify', 'autostart', True) + + if err[0] == errno.ECONNREFUSED: + self.ui.warn(_('(found dead inotify server socket; ' + 'removing it)\n')) + os.unlink(self.repo.join('inotify.sock')) + if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart: + self.ui.debug(_('(starting inotify server)\n')) + try: + try: + server.start(self.ui, self.repo) + except server.AlreadyStartedException, inst: + # another process may have started its own + # inotify server while this one was starting. + self.ui.debug(str(inst)) + except Exception, inst: + self.ui.warn(_('could not start inotify server: ' + '%s\n') % inst) + else: + try: + return function(self, *args) + except socket.error, err: + self.ui.warn(_('could not talk to new inotify ' + 'server: %s\n') % err[-1]) + elif err[0] in (errno.ECONNREFUSED, errno.ENOENT): + # silently ignore normal errors if autostart is False + self.ui.debug(_('(inotify server not running)\n')) + else: + self.ui.warn(_('failed to contact inotify server: %s\n') + % err[-1]) + + self.ui.traceback() + raise QueryFailed('inotify query failed') + + return decorated_function + class client(object): def __init__(self, ui, repo): @@ -38,14 +88,14 @@ """ Read data, check version number, extract headers, and returns a tuple (data descriptor, header) - Returns (None, None) on error + Raises QueryFailed on error """ cs = common.recvcs(self.sock) version = ord(cs.read(1)) if version != common.version: self.ui.warn(_('(inotify: received response from incompatible ' 'server version %d)\n') % version) - return None, None + raise QueryFailed('incompatible server version') # only one type of request is supported for now type = 'STAT' @@ -54,7 +104,7 @@ try: resphdr = struct.unpack(hdrfmt, cs.read(hdrsize)) except struct.error: - return None, None + raise QueryFailed('unable to retrieve query response headers') return cs, resphdr @@ -65,6 +115,7 @@ return self._receive() + @start_server def statusquery(self, names, match, ignored, clean, unknown=True): def genquery(): @@ -81,9 +132,6 @@ cs, resphdr = self.query(req) - if not cs: - return None - def readnames(nbytes): if nbytes: names = cs.read(nbytes)