Mercurial > public > mercurial-scm > hg-stable
diff mercurial/commandserver.py @ 22994:840be5ca03e1
cmdserver: add service that listens on unix domain socket and forks process
Typical use case of 'unix' mode is a background hg daemon.
$ hg serve --cmdserver unix --cwd / -a /tmp/hg-`id -u`.sock
Unlike 'pipe' mode in which parent process keeps stdio channel, 'unix' server
can be detached. So clients can freely connect and disconnect from server,
saving Python start-up time.
It might be better to write "--cmdserver socket -a unix:/sockpath" instead
of "--cmdserver unix -a /sockpath" in case hgweb gets the ability to listen
on unix domain socket.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 04 Oct 2014 16:46:50 +0900 |
parents | a0e81aa94125 |
children | 19f5273c9f3e |
line wrap: on
line diff
--- a/mercurial/commandserver.py Sat Sep 27 19:18:20 2014 +0900 +++ b/mercurial/commandserver.py Sat Oct 04 16:46:50 2014 +0900 @@ -7,7 +7,7 @@ from i18n import _ import struct -import sys, os +import sys, os, errno, traceback, SocketServer import dispatch, encoding, util logfile = None @@ -256,8 +256,59 @@ def run(self): return self.server.serve() +class _requesthandler(SocketServer.StreamRequestHandler): + def handle(self): + ui = self.server.ui + repo = self.server.repo + sv = server(ui, repo, self.rfile, self.wfile) + try: + try: + sv.serve() + # handle exceptions that may be raised by command server. most of + # known exceptions are caught by dispatch. + except util.Abort, inst: + ui.warn(_('abort: %s\n') % inst) + except IOError, inst: + if inst.errno != errno.EPIPE: + raise + except KeyboardInterrupt: + pass + except: # re-raises + # also write traceback to error channel. otherwise client cannot + # see it because it is written to server's stderr by default. + traceback.print_exc(file=sv.cerr) + raise + +class unixservice(object): + """ + Listens on unix domain socket and forks server per connection + """ + def __init__(self, ui, repo, opts): + self.ui = ui + self.repo = repo + self.address = opts['address'] + if not util.safehasattr(SocketServer, 'UnixStreamServer'): + raise util.Abort(_('unsupported platform')) + if not self.address: + raise util.Abort(_('no socket path specified with --address')) + + def init(self): + class cls(SocketServer.ForkingMixIn, SocketServer.UnixStreamServer): + ui = self.ui + repo = self.repo + self.server = cls(self.address, _requesthandler) + self.ui.status(_('listening at %s\n') % self.address) + self.ui.flush() # avoid buffering of status message + + def run(self): + try: + self.server.serve_forever() + finally: + os.unlink(self.address) + _servicemap = { 'pipe': pipeservice, + 'unix': unixservice, } def createservice(ui, repo, opts):