##// END OF EJS Templates
logtoprocess: rewrite dict building in py3-compatible way
Yuya Nishihara -
r40654:b2e5a554 default
parent child Browse files
Show More
@@ -1,89 +1,90 b''
1 # logtoprocess.py - send ui.log() data to a subprocess
1 # logtoprocess.py - send ui.log() data to a subprocess
2 #
2 #
3 # Copyright 2016 Facebook, Inc.
3 # Copyright 2016 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
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 Each positional argument to the method results in a `MSG[N]` key in the
13 environment, starting at 1 (so `MSG1`, `MSG2`, etc.). Each keyword argument
13 environment, starting at 1 (so `MSG1`, `MSG2`, etc.). Each keyword argument
14 is set as a `OPT_UPPERCASE_KEY` variable (so the key is uppercased, and
14 is set as a `OPT_UPPERCASE_KEY` variable (so the key is uppercased, and
15 prefixed with `OPT_`). The original event name is passed in the `EVENT`
15 prefixed with `OPT_`). The original event name is passed in the `EVENT`
16 environment variable, and the process ID of mercurial is given in `HGPID`.
16 environment variable, and the process ID 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', 'baz', spam='eggs'), a script configured
19 for the `foo` event can expect an environment with `MSG1=bar`, `MSG2=baz`, and
19 for the `foo` event can expect an environment with `MSG1=bar`, `MSG2=baz`, and
20 `OPT_SPAM=eggs`.
20 `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 "$MSG2$MSG3" > /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.
32
32
33 """
33 """
34
34
35 from __future__ import absolute_import
35 from __future__ import absolute_import
36
36
37 import itertools
38 import os
37 import os
39
38
39 from mercurial import (
40 pycompat,
41 )
40 from mercurial.utils import (
42 from mercurial.utils import (
41 procutil,
43 procutil,
42 )
44 )
43
45
44 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
46 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
45 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
47 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
46 # be specifying the version(s) of Mercurial they are tested with, or
48 # be specifying the version(s) of Mercurial they are tested with, or
47 # leave the attribute unspecified.
49 # leave the attribute unspecified.
48 testedwith = 'ships-with-hg-core'
50 testedwith = 'ships-with-hg-core'
49
51
50 def uisetup(ui):
52 def uisetup(ui):
51
53
52 class logtoprocessui(ui.__class__):
54 class logtoprocessui(ui.__class__):
53 def log(self, event, *msg, **opts):
55 def log(self, event, *msg, **opts):
54 """Map log events to external commands
56 """Map log events to external commands
55
57
56 Arguments are passed on as environment variables.
58 Arguments are passed on as environment variables.
57
59
58 """
60 """
59 script = self.config('logtoprocess', event)
61 script = self.config('logtoprocess', event)
60 if script:
62 if script:
61 if msg:
63 if msg:
62 # try to format the log message given the remaining
64 # try to format the log message given the remaining
63 # arguments
65 # arguments
64 try:
66 try:
65 # Format the message as blackbox does
67 # Format the message as blackbox does
66 formatted = msg[0] % msg[1:]
68 formatted = msg[0] % msg[1:]
67 except (TypeError, KeyError):
69 except (TypeError, KeyError):
68 # Failed to apply the arguments, ignore
70 # Failed to apply the arguments, ignore
69 formatted = msg[0]
71 formatted = msg[0]
70 messages = (formatted,) + msg[1:]
72 messages = (formatted,) + msg[1:]
71 else:
73 else:
72 messages = msg
74 messages = msg
75 env = {
76 b'EVENT': event,
77 b'HGPID': os.getpid(),
78 }
73 # positional arguments are listed as MSG[N] keys in the
79 # positional arguments are listed as MSG[N] keys in the
74 # environment
80 # environment
75 msgpairs = (
81 env.update((b'MSG%d' % i, m) for i, m in enumerate(messages, 1))
76 ('MSG{0:d}'.format(i), m)
77 for i, m in enumerate(messages, 1))
78 # keyword arguments get prefixed with OPT_ and uppercased
82 # keyword arguments get prefixed with OPT_ and uppercased
79 optpairs = (
83 env.update((b'OPT_%s' % key.upper(), value)
80 ('OPT_{0}'.format(key.upper()), value)
84 for key, value in pycompat.byteskwargs(opts).items())
81 for key, value in opts.iteritems())
82 env = dict(itertools.chain(msgpairs, optpairs),
83 EVENT=event, HGPID=os.getpid())
84 fullenv = procutil.shellenviron(env)
85 fullenv = procutil.shellenviron(env)
85 procutil.runbgcommand(script, fullenv, shell=True)
86 procutil.runbgcommand(script, fullenv, shell=True)
86 return super(logtoprocessui, self).log(event, *msg, **opts)
87 return super(logtoprocessui, self).log(event, *msg, **opts)
87
88
88 # Replace the class for this instance and all clones created from it:
89 # Replace the class for this instance and all clones created from it:
89 ui.__class__ = logtoprocessui
90 ui.__class__ = logtoprocessui
General Comments 0
You need to be logged in to leave comments. Login now