hgext/logtoprocess.py
author Manuel Jacob <me@manueljacob.de>
Tue, 31 May 2022 02:19:07 +0200
changeset 49297 402f9f0f9387
parent 48946 642e31cb55f0
child 51863 f4733654f144
permissions -rw-r--r--
tests: remove Python 2 special cases in test-stdio.py
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     1
# logtoprocess.py - send ui.log() data to a subprocess
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     2
#
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     3
# Copyright 2016 Facebook, Inc.
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     4
#
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
31601
8e7feaad2d8d logtoprocess: use lowercase for docstring title
Jun Wu <quark@fb.com>
parents: 30638
diff changeset
     7
"""send ui.log() data to a subprocess (EXPERIMENTAL)
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     8
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
     9
This extension lets you specify a shell command per ui.log() event,
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    10
sending all remaining arguments to as environment variables to that command.
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    11
40622
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    12
Positional arguments construct a log message, which is passed in the `MSG1`
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    13
environment variables. Each keyword argument is set as a `OPT_UPPERCASE_KEY`
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    14
variable (so the key is uppercased, and prefixed with `OPT_`). The original
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    15
event name is passed in the `EVENT` environment variable, and the process ID
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    16
of mercurial is given in `HGPID`.
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    17
40622
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    18
So given a call `ui.log('foo', 'bar %s\n', 'baz', spam='eggs'), a script
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    19
configured for the `foo` event can expect an environment with `MSG1=bar baz`,
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    20
and `OPT_SPAM=eggs`.
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    21
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    22
Scripts are configured in the `[logtoprocess]` section, each key an event name.
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    23
For example::
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    24
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    25
  [logtoprocess]
40622
d2c997b8001f logtoprocess: drop support for ui.log() call with invalid msg arguments (BC)
Yuya Nishihara <yuya@tcha.org>
parents: 40620
diff changeset
    26
  commandexception = echo "$MSG1" > /var/log/mercurial_exceptions.log
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    27
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    28
would log the warning message and traceback of any failed command dispatch.
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    29
30332
318a24b52eeb spelling: fixes of non-dictionary words
Mads Kiilerich <madski@unity3d.com>
parents: 29841
diff changeset
    30
Scripts are run asynchronously as detached daemon processes; mercurial will
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    31
not ensure that they exit cleanly.
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    32
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    33
"""
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    34
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    35
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    36
import os
30638
1c5cbf28f007 py3: replace os.environ with encoding.environ (part 5 of 5)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30332
diff changeset
    37
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40761
diff changeset
    38
from mercurial.utils import procutil
39826
c31ce080eb75 py3: convert arguments, cwd and env to native strings when spawning subprocess
Matt Harbison <matt_harbison@yahoo.com>
parents: 35063
diff changeset
    39
29841
d5883fd055c6 extensions: change magic "shipped with hg" string
Augie Fackler <augie@google.com>
parents: 29463
diff changeset
    40
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    41
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    42
# be specifying the version(s) of Mercurial they are tested with, or
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    43
# leave the attribute unspecified.
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    44
testedwith = b'ships-with-hg-core'
28901
a368da441b32 logtoprocess: new experimental extension
Martijn Pieters <mjpieters@fb.com>
parents:
diff changeset
    45
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40761
diff changeset
    46
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
    47
class processlogger:
40677
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    48
    """Map log events to external commands
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    49
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    50
    Arguments are passed on as environment variables.
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    51
    """
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    52
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    53
    def __init__(self, ui):
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    54
        self._scripts = dict(ui.configitems(b'logtoprocess'))
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    55
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    56
    def tracked(self, event):
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    57
        return bool(self._scripts.get(event))
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    58
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    59
    def log(self, ui, event, msg, opts):
40730
55b053af7196 ui: manage logger instances and event filtering by core ui
Yuya Nishihara <yuya@tcha.org>
parents: 40677
diff changeset
    60
        script = self._scripts[event]
44417
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    61
        maxmsg = 100000
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    62
        if len(msg) > maxmsg:
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    63
            # Each env var has a 128KiB limit on linux. msg can be long, in
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    64
            # particular for command event, where it's the full command line.
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    65
            # Prefer truncating the message than raising "Argument list too
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    66
            # long" error.
7c0b8652fd8c logtoprocess: avoid traceback when running long commands
Valentin Gatien-Baron <vgatien-baron@janestreet.com>
parents: 43077
diff changeset
    67
            msg = msg[:maxmsg] + b' (truncated)'
40677
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    68
        env = {
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    69
            b'EVENT': event,
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    70
            b'HGPID': os.getpid(),
40760
ffd574c144d2 ui: pass in formatted message to logger.log()
Yuya Nishihara <yuya@tcha.org>
parents: 40730
diff changeset
    71
            b'MSG1': msg,
40677
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    72
        }
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    73
        # keyword arguments get prefixed with OPT_ and uppercased
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40761
diff changeset
    74
        env.update(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40761
diff changeset
    75
            (b'OPT_%s' % key.upper(), value) for key, value in opts.items()
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40761
diff changeset
    76
        )
40677
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    77
        fullenv = procutil.shellenviron(env)
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    78
        procutil.runbgcommand(script, fullenv, shell=True)
2b859742ea15 logtoprocess: extract logger class from ui wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 40622
diff changeset
    79
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40761
diff changeset
    80
40730
55b053af7196 ui: manage logger instances and event filtering by core ui
Yuya Nishihara <yuya@tcha.org>
parents: 40677
diff changeset
    81
def uipopulate(ui):
55b053af7196 ui: manage logger instances and event filtering by core ui
Yuya Nishihara <yuya@tcha.org>
parents: 40677
diff changeset
    82
    ui.setlogger(b'logtoprocess', processlogger(ui))