##// END OF EJS Templates
procutil: make stream detection in make_line_buffered more correct and strict...
procutil: make stream detection in make_line_buffered more correct and strict In make_line_buffered(), we don’t want to wrap the stream if we know that lines get flushed to the underlying raw stream already. Previously, the heuristic was too optimistic. It assumed that any stream which is not an instance of io.BufferedIOBase doesn’t need wrapping. However, there are buffered streams that aren’t instances of io.BufferedIOBase, like Mercurial’s own winstdout. The new logic is different in two ways: First, only for the check, if unwraps any combination of WriteAllWrapper and winstdout. Second, it skips wrapping the stream only if it is an instance of io.RawIOBase (or already wrapped). If it is an instance of io.BufferedIOBase, it gets wrapped. In any other case, the function raises an exception. This ensures that, if an unknown stream is passed or we add another wrapper in the future, we don’t wrap the stream if it’s already line buffered or not wrap the stream if it’s not line buffered. In fact, this was already helpful during development of this change. Without it, I possibly would have forgot that WriteAllWrapper needs to be ignored for the check, leading to unnecessary wrapping if stdout is unbuffered. The alternative would have been to always wrap unknown streams. However, I don’t think that anyone would benefit from being less strict. We can expect streams from the standard library to be subclassing either io.RawIOBase or io.BufferedIOBase, so running Mercurial in the standard way should not regress by this change. Py2exe might replace sys.stdout and sys.stderr, but that currently breaks Mercurial anyway and also these streams don’t claim to be interactive, so this function is not called for them.

File last commit:

r49801:642e31cb default
r50273:094a5fa3 6.2 stable
Show More
logtoprocess.py
82 lines | 2.8 KiB | text/x-python | PythonLexer
Martijn Pieters
logtoprocess: new experimental extension...
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.
Jun Wu
logtoprocess: use lowercase for docstring title
r31601 """send ui.log() data to a subprocess (EXPERIMENTAL)
Martijn Pieters
logtoprocess: new experimental extension...
r28901
This extension lets you specify a shell command per ui.log() event,
sending all remaining arguments to as environment variables to that command.
Yuya Nishihara
logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)...
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`.
Martijn Pieters
logtoprocess: new experimental extension...
r28901
Yuya Nishihara
logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)...
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`.
Martijn Pieters
logtoprocess: new experimental extension...
r28901
Scripts are configured in the `[logtoprocess]` section, each key an event name.
For example::
[logtoprocess]
Yuya Nishihara
logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)...
r40656 commandexception = echo "$MSG1" > /var/log/mercurial_exceptions.log
Martijn Pieters
logtoprocess: new experimental extension...
r28901
would log the warning message and traceback of any failed command dispatch.
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 Scripts are run asynchronously as detached daemon processes; mercurial will
Martijn Pieters
logtoprocess: new experimental extension...
r28901 not ensure that they exit cleanly.
"""
import os
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 5 of 5)
r30638
Augie Fackler
formatting: blacken the codebase...
r43346 from mercurial.utils import procutil
Matt Harbison
py3: convert arguments, cwd and env to native strings when spawning subprocess...
r39851
Augie Fackler
extensions: change magic "shipped with hg" string...
r29841 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
Martijn Pieters
logtoprocess: new experimental extension...
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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
Martijn Pieters
logtoprocess: new experimental extension...
r28901
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class processlogger:
Yuya Nishihara
logtoprocess: extract logger class from ui wrapper...
r40713 """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):
Yuya Nishihara
ui: manage logger instances and event filtering by core ui...
r40761 script = self._scripts[event]
Valentin Gatien-Baron
logtoprocess: avoid traceback when running long commands...
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)'
Yuya Nishihara
logtoprocess: extract logger class from ui wrapper...
r40713 env = {
b'EVENT': event,
b'HGPID': os.getpid(),
Yuya Nishihara
ui: pass in formatted message to logger.log()...
r40793 b'MSG1': msg,
Yuya Nishihara
logtoprocess: extract logger class from ui wrapper...
r40713 }
# keyword arguments get prefixed with OPT_ and uppercased
Augie Fackler
formatting: blacken the codebase...
r43346 env.update(
(b'OPT_%s' % key.upper(), value) for key, value in opts.items()
)
Yuya Nishihara
logtoprocess: extract logger class from ui wrapper...
r40713 fullenv = procutil.shellenviron(env)
procutil.runbgcommand(script, fullenv, shell=True)
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
ui: manage logger instances and event filtering by core ui...
r40761 def uipopulate(ui):
ui.setlogger(b'logtoprocess', processlogger(ui))