Mercurial > public > mercurial-scm > hg-stable
diff mercurial/commandserver.py @ 40636:054d0fcba2c4
commandserver: add experimental option to use separate message channel
This is loosely based on the idea of the TortoiseHg's pipeui extension,
which attaches ui.label to message text so the command-server client can
capture prompt text, for example.
https://bitbucket.org/tortoisehg/thg/src/4.7.2/tortoisehg/util/pipeui.py
I was thinking that this functionality could be generalized to templating,
but changed mind as doing template stuff would be unnecessarily complex.
It's merely a status message, a simple serialization option should suffice.
Since this slightly changes the command-server protocol, it's gated by a
config knob. If the config is enabled, and if it's supported by the server,
"message-encoding: <name>" is advertised so the client can stop parsing
'o'/'e' channel data and read encoded messages from the 'm' channel. As we
might add new message encodings in future releases, client can specify a list
of encoding names in preferred order.
This patch includes 'cbor' encoding as example. Perhaps, 'json' should be
supported as well.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 18 Jan 2015 18:49:59 +0900 |
parents | 9683dfb6f13a |
children | 83dd8c63a0c6 |
line wrap: on
line diff
--- a/mercurial/commandserver.py Wed Nov 07 22:37:51 2018 +0900 +++ b/mercurial/commandserver.py Sun Jan 18 18:49:59 2015 +0900 @@ -26,9 +26,11 @@ from . import ( encoding, error, + pycompat, util, ) from .utils import ( + cborutil, procutil, ) @@ -70,6 +72,30 @@ raise AttributeError(attr) return getattr(self.out, attr) +class channeledmessage(object): + """ + Write encoded message and metadata to out in the following format: + + data length (unsigned int), + encoded message and metadata, as a flat key-value dict. + """ + + # teach ui that write() can take **opts + structured = True + + def __init__(self, out, channel, encodename, encodefn): + self._cout = channeledoutput(out, channel) + self.encoding = encodename + self._encodefn = encodefn + + def write(self, data, **opts): + opts = pycompat.byteskwargs(opts) + opts[b'data'] = data + self._cout.write(self._encodefn(opts)) + + def __getattr__(self, attr): + return getattr(self._cout, attr) + class channeledinput(object): """ Read data from in_. @@ -156,6 +182,20 @@ raise AttributeError(attr) return getattr(self.in_, attr) +_messageencoders = { + b'cbor': lambda v: b''.join(cborutil.streamencode(v)), +} + +def _selectmessageencoder(ui): + # experimental config: cmdserver.message-encodings + encnames = ui.configlist(b'cmdserver', b'message-encodings') + for n in encnames: + f = _messageencoders.get(n) + if f: + return n, f + raise error.Abort(b'no supported message encodings: %s' + % b' '.join(encnames)) + class server(object): """ Listens for commands on fin, runs them and writes the output on a channel @@ -189,6 +229,14 @@ self.cin = channeledinput(fin, fout, 'I') self.cresult = channeledoutput(fout, 'r') + # TODO: add this to help/config.txt when stabilized + # ``channel`` + # Use separate channel for structured output. (Command-server only) + self.cmsg = None + if ui.config(b'ui', b'message-output') == b'channel': + encname, encfn = _selectmessageencoder(ui) + self.cmsg = channeledmessage(fout, b'm', encname, encfn) + self.client = fin def cleanup(self): @@ -254,7 +302,7 @@ ui.setconfig('ui', 'nontty', 'true', 'commandserver') req = dispatch.request(args[:], copiedui, self.repo, self.cin, - self.cout, self.cerr) + self.cout, self.cerr, self.cmsg) try: ret = dispatch.dispatch(req) & 255 @@ -289,6 +337,8 @@ hellomsg += '\n' hellomsg += 'encoding: ' + encoding.encoding hellomsg += '\n' + if self.cmsg: + hellomsg += 'message-encoding: %s\n' % self.cmsg.encoding hellomsg += 'pid: %d' % procutil.getpid() if util.safehasattr(os, 'getpgid'): hellomsg += '\n'