Mercurial > hg
changeset 8551:7089d9727867
inotify: modular architecture for inotify clients
Put the socket init, query generation and response analysis in
a more generic client class.
author | Nicolas Dumazet <nicdumz.commits@gmail.com> |
---|---|
date | Tue, 07 Apr 2009 18:39:34 +0900 |
parents | cbd3a104637f |
children | 06561793778e |
files | hgext/inotify/__init__.py hgext/inotify/client.py |
diffstat | 2 files changed, 81 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/inotify/__init__.py Sat May 23 13:43:11 2009 +0200 +++ b/hgext/inotify/__init__.py Tue Apr 07 18:39:34 2009 +0900 @@ -13,8 +13,9 @@ from mercurial.i18n import _ from mercurial import cmdutil, util -import client, errno, os, server, socket +import errno, os, server, socket from weakref import proxy +from client import client def serve(ui, repo, **opts): '''start an inotify server for this repository''' @@ -54,10 +55,11 @@ files = match.files() if '.' in files: files = [] + cli = client(ui, repo) try: if not ignored and not self.inotifyserver: - result = client.query(ui, repo, files, match, False, - clean, unknown) + result = cli.statusquery(files, match, False, + clean, unknown) if result and ui.config('inotify', 'debug'): r2 = super(inotifydirstate, self).status( match, False, clean, unknown) @@ -94,8 +96,8 @@ else: # server is started, send query again try: - return client.query(ui, repo, files, match, - ignored, clean, unknown) + 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])
--- a/hgext/inotify/client.py Sat May 23 13:43:11 2009 +0200 +++ b/hgext/inotify/client.py Tue Apr 07 18:39:34 2009 +0900 @@ -2,6 +2,7 @@ # # Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com> # Copyright 2007, 2008 Brendan Cully <brendan@kublai.com> +# Copyright 2009 Nicolas Dumazet <nicdumz@gmail.com> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2, incorporated herein by reference. @@ -10,56 +11,84 @@ import common import os, socket, struct -def query(ui, repo, names, match, ignored, clean, unknown=True): - sock = socket.socket(socket.AF_UNIX) - sockpath = repo.join('inotify.sock') - try: - sock.connect(sockpath) - except socket.error, err: - if err[0] == "AF_UNIX path too long": - sockpath = os.readlink(sockpath) - sock.connect(sockpath) - else: - raise +class client(object): + def __init__(self, ui, repo): + self.ui = ui + self.repo = repo + self.sock = socket.socket(socket.AF_UNIX) + + def _connect(self): + sockpath = self.repo.join('inotify.sock') + try: + self.sock.connect(sockpath) + except socket.error, err: + if err[0] == "AF_UNIX path too long": + sockpath = os.readlink(sockpath) + self.sock.connect(sockpath) + else: + raise - def genquery(): - for n in names: - yield n - states = 'almrx!' - if ignored: - raise ValueError('this is insanity') - if clean: states += 'c' - if unknown: states += '?' - yield states + def _send(self, data): + """Sends protocol version number, and the data""" + self.sock.sendall(chr(common.version) + data) + + self.sock.shutdown(socket.SHUT_WR) - req = '\0'.join(genquery()) + def _receive(self): + """ + Read data, check version number, extract headers, + and returns a tuple (data descriptor, header) + Returns (None, None) 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 - sock.sendall(chr(common.version)) - sock.sendall(req) - sock.shutdown(socket.SHUT_WR) + # only one type of request is supported for now + type = 'STAT' + hdrfmt = common.resphdrfmts[type] + hdrsize = common.resphdrsizes[type] + try: + resphdr = struct.unpack(hdrfmt, cs.read(hdrsize)) + except struct.error: + return None, None - cs = common.recvcs(sock) - version = ord(cs.read(1)) + return cs, resphdr + + def query(self, req): + self._connect() - if version != common.version: - ui.warn(_('(inotify: received response from incompatible server ' - 'version %d)\n') % version) - return None + self._send(req) + + return self._receive() + + def statusquery(self, names, match, ignored, clean, unknown=True): - # only one type of request is supported for now - type = 'STAT' - hdrfmt = common.resphdrfmts[type] - hdrsize = common.resphdrsizes[type] - try: - resphdr = struct.unpack(hdrfmt, cs.read(hdrsize)) - except struct.error: - return None + def genquery(): + for n in names: + yield n + states = 'almrx!' + if ignored: + raise ValueError('this is insanity') + if clean: states += 'c' + if unknown: states += '?' + yield states + + req = '\0'.join(genquery()) - def readnames(nbytes): - if nbytes: - names = cs.read(nbytes) - if names: - return filter(match, names.split('\0')) - return [] + cs, resphdr = self.query(req) + + if not cs: + return None - return map(readnames, resphdr) + def readnames(nbytes): + if nbytes: + names = cs.read(nbytes) + if names: + return filter(match, names.split('\0')) + return [] + + return map(readnames, resphdr)