diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
commit | 458120dd40db6b4df55a4e96b650e16798ef06a0 (patch) | |
tree | 8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/hg/hgext/inotify/client.py | |
parent | 3a742c699f6806c1145aea5149bf15de15a0afd7 (diff) |
add hg and python
Diffstat (limited to 'sys/src/cmd/hg/hgext/inotify/client.py')
-rw-r--r-- | sys/src/cmd/hg/hgext/inotify/client.py | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/sys/src/cmd/hg/hgext/inotify/client.py b/sys/src/cmd/hg/hgext/inotify/client.py new file mode 100644 index 000000000..800d4a3aa --- /dev/null +++ b/sys/src/cmd/hg/hgext/inotify/client.py @@ -0,0 +1,160 @@ +# client.py - inotify status client +# +# 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. + +from mercurial.i18n import _ +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(os.path.join(self.root, '.hg', '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.dirstate, self.root) + 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): + self.ui = ui + self.dirstate = repo.dirstate + self.root = repo.root + self.sock = socket.socket(socket.AF_UNIX) + + def _connect(self): + sockpath = os.path.join(self.root, '.hg', '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 _send(self, type, data): + """Sends protocol version number, and the data""" + self.sock.sendall(chr(common.version) + type + data) + + self.sock.shutdown(socket.SHUT_WR) + + def _receive(self, type): + """ + Read data, check version number, extract headers, + and returns a tuple (data descriptor, header) + Raises QueryFailed on error + """ + cs = common.recvcs(self.sock) + try: + version = ord(cs.read(1)) + except TypeError: + # empty answer, assume the server crashed + self.ui.warn(_('received empty answer from inotify server')) + raise QueryFailed('server crashed') + + if version != common.version: + self.ui.warn(_('(inotify: received response from incompatible ' + 'server version %d)\n') % version) + raise QueryFailed('incompatible server version') + + readtype = cs.read(4) + if readtype != type: + self.ui.warn(_('(inotify: received \'%s\' response when expecting' + ' \'%s\')\n') % (readtype, type)) + raise QueryFailed('wrong response type') + + hdrfmt = common.resphdrfmts[type] + hdrsize = common.resphdrsizes[type] + try: + resphdr = struct.unpack(hdrfmt, cs.read(hdrsize)) + except struct.error: + raise QueryFailed('unable to retrieve query response headers') + + return cs, resphdr + + def query(self, type, req): + self._connect() + + self._send(type, req) + + return self._receive(type) + + @start_server + def statusquery(self, names, match, ignored, clean, unknown=True): + + 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()) + + cs, resphdr = self.query('STAT', req) + + def readnames(nbytes): + if nbytes: + names = cs.read(nbytes) + if names: + return filter(match, names.split('\0')) + return [] + return map(readnames, resphdr) + + @start_server + def debugquery(self): + cs, resphdr = self.query('DBUG', '') + + nbytes = resphdr[0] + names = cs.read(nbytes) + return names.split('\0') |