logtoprocess.py
82 lines
| 2.8 KiB
| text/x-python
|
PythonLexer
/ hgext / logtoprocess.py
|
r28901 | # logtoprocess.py - send ui.log() data to a subprocess | ||
# | ||||
# Copyright 2016 Facebook, Inc. | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
|
r31601 | """send ui.log() data to a subprocess (EXPERIMENTAL) | ||
|
r28901 | |||
This extension lets you specify a shell command per ui.log() event, | ||||
sending all remaining arguments to as environment variables to that command. | ||||
|
r40656 | Positional arguments construct a log message, which is passed in the `MSG1` | ||
environment variables. Each keyword argument is set as a `OPT_UPPERCASE_KEY` | ||||
variable (so the key is uppercased, and prefixed with `OPT_`). The original | ||||
event name is passed in the `EVENT` environment variable, and the process ID | ||||
of mercurial is given in `HGPID`. | ||||
|
r28901 | |||
|
r40656 | So given a call `ui.log('foo', 'bar %s\n', 'baz', spam='eggs'), a script | ||
configured for the `foo` event can expect an environment with `MSG1=bar baz`, | ||||
and `OPT_SPAM=eggs`. | ||||
|
r28901 | |||
Scripts are configured in the `[logtoprocess]` section, each key an event name. | ||||
For example:: | ||||
[logtoprocess] | ||||
|
r40656 | commandexception = echo "$MSG1" > /var/log/mercurial_exceptions.log | ||
|
r28901 | |||
would log the warning message and traceback of any failed command dispatch. | ||||
|
r30332 | Scripts are run asynchronously as detached daemon processes; mercurial will | ||
|
r28901 | not ensure that they exit cleanly. | ||
""" | ||||
import os | ||||
|
r30638 | |||
|
r43346 | from mercurial.utils import procutil | ||
|
r39851 | |||
|
r29841 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | ||
|
r28901 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | ||
# be specifying the version(s) of Mercurial they are tested with, or | ||||
# leave the attribute unspecified. | ||||
|
r43347 | testedwith = b'ships-with-hg-core' | ||
|
r28901 | |||
|
r43346 | |||
|
r40713 | class processlogger(object): | ||
"""Map log events to external commands | ||||
Arguments are passed on as environment variables. | ||||
""" | ||||
def __init__(self, ui): | ||||
self._scripts = dict(ui.configitems(b'logtoprocess')) | ||||
def tracked(self, event): | ||||
return bool(self._scripts.get(event)) | ||||
def log(self, ui, event, msg, opts): | ||||
|
r40761 | script = self._scripts[event] | ||
|
r44904 | maxmsg = 100000 | ||
if len(msg) > maxmsg: | ||||
# Each env var has a 128KiB limit on linux. msg can be long, in | ||||
# particular for command event, where it's the full command line. | ||||
# Prefer truncating the message than raising "Argument list too | ||||
# long" error. | ||||
msg = msg[:maxmsg] + b' (truncated)' | ||||
|
r40713 | env = { | ||
b'EVENT': event, | ||||
b'HGPID': os.getpid(), | ||||
|
r40793 | b'MSG1': msg, | ||
|
r40713 | } | ||
# keyword arguments get prefixed with OPT_ and uppercased | ||||
|
r43346 | env.update( | ||
(b'OPT_%s' % key.upper(), value) for key, value in opts.items() | ||||
) | ||||
|
r40713 | fullenv = procutil.shellenviron(env) | ||
procutil.runbgcommand(script, fullenv, shell=True) | ||||
|
r43346 | |||
|
r40761 | def uipopulate(ui): | ||
ui.setlogger(b'logtoprocess', processlogger(ui)) | ||||