##// END OF EJS Templates
Merge with stable
Merge with stable

File last commit:

r10282:08a0f04b default
r10699:7b0a0d49 merge default
Show More
client.py
174 lines | 5.9 KiB | text/x-python | PythonLexer
Bryan O'Sullivan
Add inotify extension
r6239 # client.py - inotify status client
#
# Copyright 2006, 2007, 2008 Bryan O'Sullivan <bos@serpentine.com>
# Copyright 2007, 2008 Brendan Cully <brendan@kublai.com>
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 # Copyright 2009 Nicolas Dumazet <nicdumz@gmail.com>
Bryan O'Sullivan
Add inotify extension
r6239 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Bryan O'Sullivan
Add inotify extension
r6239
Martin Geisler
i18n: import _ instead of gettext
r7225 from mercurial.i18n import _
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 import common, server
import errno, os, socket, struct
Matt Mackall
many, many trivial check-code fixups
r10282 class QueryFailed(Exception):
pass
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552
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:
Nicolas Dumazet
inotify: improve error messages...
r9900 self.ui.warn(_('inotify-client: found dead inotify server '
'socket; removing it\n'))
Nicolas Dumazet
inotify: client: no repo use
r9351 os.unlink(os.path.join(self.root, '.hg', 'inotify.sock'))
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 if err[0] in (errno.ECONNREFUSED, errno.ENOENT) and autostart:
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('(starting inotify server)\n')
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 try:
try:
Nicolas Dumazet
inotify: use cmdutil.service instead of local daemonizing code
r9514 server.start(self.ui, self.dirstate, self.root,
dict(daemon=True, daemon_pipefds=''))
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 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:
Nicolas Dumazet
inotify: improve error messages...
r9900 self.ui.warn(_('inotify-client: could not start inotify '
'server: %s\n') % inst)
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 else:
try:
return function(self, *args)
except socket.error, err:
Nicolas Dumazet
inotify: improve error messages...
r9900 self.ui.warn(_('inotify-client: could not talk to new '
'inotify server: %s\n') % err[-1])
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 elif err[0] in (errno.ECONNREFUSED, errno.ENOENT):
# silently ignore normal errors if autostart is False
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('(inotify server not running)\n')
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 else:
Nicolas Dumazet
inotify: improve error messages...
r9900 self.ui.warn(_('inotify-client: failed to contact inotify '
'server: %s\n') % err[-1])
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552
self.ui.traceback()
raise QueryFailed('inotify query failed')
return decorated_function
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 class client(object):
def __init__(self, ui, repo):
self.ui = ui
Nicolas Dumazet
inotify: client: no repo use
r9351 self.dirstate = repo.dirstate
self.root = repo.root
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 self.sock = socket.socket(socket.AF_UNIX)
def _connect(self):
Nicolas Dumazet
inotify: client: no repo use
r9351 sockpath = os.path.join(self.root, '.hg', 'inotify.sock')
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 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
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 def _send(self, type, data):
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 """Sends protocol version number, and the data"""
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 self.sock.sendall(chr(common.version) + type + data)
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551
self.sock.shutdown(socket.SHUT_WR)
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 def _receive(self, type):
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 """
Read data, check version number, extract headers,
and returns a tuple (data descriptor, header)
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 Raises QueryFailed on error
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 """
cs = common.recvcs(self.sock)
Nicolas Dumazet
inotify: raise QueryFailed when the server crash...
r8788 try:
version = ord(cs.read(1))
except TypeError:
# empty answer, assume the server crashed
Nicolas Dumazet
inotify: improve error messages...
r9900 self.ui.warn(_('inotify-client: received empty answer from inotify '
'server'))
Nicolas Dumazet
inotify: raise QueryFailed when the server crash...
r8788 raise QueryFailed('server crashed')
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 if version != common.version:
self.ui.warn(_('(inotify: received response from incompatible '
'server version %d)\n') % version)
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 raise QueryFailed('incompatible server version')
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 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')
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 hdrfmt = common.resphdrfmts[type]
hdrsize = common.resphdrsizes[type]
try:
resphdr = struct.unpack(hdrfmt, cs.read(hdrsize))
except struct.error:
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 raise QueryFailed('unable to retrieve query response headers')
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 return cs, resphdr
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 def query(self, type, req):
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 self._connect()
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 self._send(type, req)
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 return self._receive(type)
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551
Nicolas Dumazet
inotify: Separate query sending logic from Server starting....
r8552 @start_server
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 def statusquery(self, names, match, ignored, clean, unknown=True):
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 def genquery():
for n in names:
yield n
states = 'almrx!'
if ignored:
raise ValueError('this is insanity')
Matt Mackall
many, many trivial check-code fixups
r10282 if clean:
states += 'c'
if unknown:
states += '?'
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551 yield states
req = '\0'.join(genquery())
Bryan O'Sullivan
Add inotify extension
r6239
Nicolas Dumazet
inotify: change protocol so that different query types can be supported.
r8553 cs, resphdr = self.query('STAT', req)
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551
def readnames(nbytes):
if nbytes:
names = cs.read(nbytes)
if names:
return filter(match, names.split('\0'))
return []
Nicolas Dumazet
inotify: mark directories visited during lookup (issue1844)...
r9854 results = map(readnames, resphdr[:-1])
if names:
nbytes = resphdr[-1]
vdirs = cs.read(nbytes)
if vdirs:
for vdir in vdirs.split('\0'):
match.dir(vdir)
return results
Nicolas Dumazet
inotify: modular architecture for inotify clients...
r8551
Nicolas Dumazet
inotify: introduce debuginotify, which lists which paths are under watch
r8555 @start_server
def debugquery(self):
cs, resphdr = self.query('DBUG', '')
nbytes = resphdr[0]
names = cs.read(nbytes)
return names.split('\0')