comparison hgext/logtoprocess.py @ 40622:d2c997b8001f

logtoprocess: drop support for ui.log() call with invalid msg arguments (BC) Before, the logtoprocess extension put a formatted message into $MSG1, and its arguments to $MSG2... If the specified arguments couldn't be formatted because of a caller bug, an unformatted message was passed in to $MSG1 instead of exploding. This behavior doesn't make sense. Since I'm planning to formalize the ui.log() interface such that we'll no longer have to extend the ui class, I want to remove any features not conforming to the ui.log() API. So this patch removes the support for ill-formed arguments, and $MSG{n} (where n > 1) parameters which seems useless as long as the message can be formatted. The $MSG1 variable isn't renamed for the maximum compatibility. In future patches, a formatted msg will be passed to a processlogger object, instead of overriding the ui.log() function. .. bc:: The logtoprocess extension no longer supports invalid ``ui.log()`` arguments. A log message is always formatted and passed in to the ``$MSG1`` environment variable.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 11 Nov 2018 12:55:58 +0900
parents b2e5a554bc7b
children 2b859742ea15
comparison
equal deleted inserted replaced
40621:175b590b1f51 40622:d2c997b8001f
7 """send ui.log() data to a subprocess (EXPERIMENTAL) 7 """send ui.log() data to a subprocess (EXPERIMENTAL)
8 8
9 This extension lets you specify a shell command per ui.log() event, 9 This extension lets you specify a shell command per ui.log() event,
10 sending all remaining arguments to as environment variables to that command. 10 sending all remaining arguments to as environment variables to that command.
11 11
12 Each positional argument to the method results in a `MSG[N]` key in the 12 Positional arguments construct a log message, which is passed in the `MSG1`
13 environment, starting at 1 (so `MSG1`, `MSG2`, etc.). Each keyword argument 13 environment variables. Each keyword argument is set as a `OPT_UPPERCASE_KEY`
14 is set as a `OPT_UPPERCASE_KEY` variable (so the key is uppercased, and 14 variable (so the key is uppercased, and prefixed with `OPT_`). The original
15 prefixed with `OPT_`). The original event name is passed in the `EVENT` 15 event name is passed in the `EVENT` environment variable, and the process ID
16 environment variable, and the process ID of mercurial is given in `HGPID`. 16 of mercurial is given in `HGPID`.
17 17
18 So given a call `ui.log('foo', 'bar', 'baz', spam='eggs'), a script configured 18 So given a call `ui.log('foo', 'bar %s\n', 'baz', spam='eggs'), a script
19 for the `foo` event can expect an environment with `MSG1=bar`, `MSG2=baz`, and 19 configured for the `foo` event can expect an environment with `MSG1=bar baz`,
20 `OPT_SPAM=eggs`. 20 and `OPT_SPAM=eggs`.
21 21
22 Scripts are configured in the `[logtoprocess]` section, each key an event name. 22 Scripts are configured in the `[logtoprocess]` section, each key an event name.
23 For example:: 23 For example::
24 24
25 [logtoprocess] 25 [logtoprocess]
26 commandexception = echo "$MSG2$MSG3" > /var/log/mercurial_exceptions.log 26 commandexception = echo "$MSG1" > /var/log/mercurial_exceptions.log
27 27
28 would log the warning message and traceback of any failed command dispatch. 28 would log the warning message and traceback of any failed command dispatch.
29 29
30 Scripts are run asynchronously as detached daemon processes; mercurial will 30 Scripts are run asynchronously as detached daemon processes; mercurial will
31 not ensure that they exit cleanly. 31 not ensure that they exit cleanly.
58 Arguments are passed on as environment variables. 58 Arguments are passed on as environment variables.
59 59
60 """ 60 """
61 script = self.config('logtoprocess', event) 61 script = self.config('logtoprocess', event)
62 if script: 62 if script:
63 if msg:
64 # try to format the log message given the remaining
65 # arguments
66 try:
67 # Format the message as blackbox does
68 formatted = msg[0] % msg[1:]
69 except (TypeError, KeyError):
70 # Failed to apply the arguments, ignore
71 formatted = msg[0]
72 messages = (formatted,) + msg[1:]
73 else:
74 messages = msg
75 env = { 63 env = {
76 b'EVENT': event, 64 b'EVENT': event,
77 b'HGPID': os.getpid(), 65 b'HGPID': os.getpid(),
66 b'MSG1': msg[0] % msg[1:],
78 } 67 }
79 # positional arguments are listed as MSG[N] keys in the
80 # environment
81 env.update((b'MSG%d' % i, m) for i, m in enumerate(messages, 1))
82 # keyword arguments get prefixed with OPT_ and uppercased 68 # keyword arguments get prefixed with OPT_ and uppercased
83 env.update((b'OPT_%s' % key.upper(), value) 69 env.update((b'OPT_%s' % key.upper(), value)
84 for key, value in pycompat.byteskwargs(opts).items()) 70 for key, value in pycompat.byteskwargs(opts).items())
85 fullenv = procutil.shellenviron(env) 71 fullenv = procutil.shellenviron(env)
86 procutil.runbgcommand(script, fullenv, shell=True) 72 procutil.runbgcommand(script, fullenv, shell=True)