##// END OF EJS Templates
logtoprocess: extract logger class from ui wrapper...
Yuya Nishihara -
r40713:2b859742 default
parent child Browse files
Show More
@@ -1,76 +1,100 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 Positional arguments construct a log message, which is passed in the `MSG1`
12 Positional arguments construct a log message, which is passed in the `MSG1`
13 environment variables. Each keyword argument is set as a `OPT_UPPERCASE_KEY`
13 environment variables. Each keyword argument is set as a `OPT_UPPERCASE_KEY`
14 variable (so the key is uppercased, and prefixed with `OPT_`). The original
14 variable (so the key is uppercased, and prefixed with `OPT_`). The original
15 event name is passed in the `EVENT` environment variable, and the process ID
15 event name is passed in the `EVENT` environment variable, and the process ID
16 of mercurial is given in `HGPID`.
16 of mercurial is given in `HGPID`.
17
17
18 So given a call `ui.log('foo', 'bar %s\n', 'baz', spam='eggs'), a script
18 So given a call `ui.log('foo', 'bar %s\n', 'baz', spam='eggs'), a script
19 configured for the `foo` event can expect an environment with `MSG1=bar baz`,
19 configured for the `foo` event can expect an environment with `MSG1=bar baz`,
20 and `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 "$MSG1" > /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.
32
32
33 """
33 """
34
34
35 from __future__ import absolute_import
35 from __future__ import absolute_import
36
36
37 import os
37 import os
38
38
39 from mercurial import (
39 from mercurial import (
40 pycompat,
40 pycompat,
41 util,
41 )
42 )
42 from mercurial.utils import (
43 from mercurial.utils import (
43 procutil,
44 procutil,
44 )
45 )
45
46
46 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
47 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
47 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
48 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
48 # be specifying the version(s) of Mercurial they are tested with, or
49 # be specifying the version(s) of Mercurial they are tested with, or
49 # leave the attribute unspecified.
50 # leave the attribute unspecified.
50 testedwith = 'ships-with-hg-core'
51 testedwith = 'ships-with-hg-core'
51
52
52 def uisetup(ui):
53 class processlogger(object):
53
54 class logtoprocessui(ui.__class__):
55 def log(self, event, *msg, **opts):
56 """Map log events to external commands
54 """Map log events to external commands
57
55
58 Arguments are passed on as environment variables.
56 Arguments are passed on as environment variables.
57 """
59
58
60 """
59 def __init__(self, ui):
61 script = self.config('logtoprocess', event)
60 self._scripts = dict(ui.configitems(b'logtoprocess'))
62 if script:
61
62 def tracked(self, event):
63 return bool(self._scripts.get(event))
64
65 def log(self, ui, event, msg, opts):
66 script = self._scripts.get(event)
67 if not script:
68 return
63 env = {
69 env = {
64 b'EVENT': event,
70 b'EVENT': event,
65 b'HGPID': os.getpid(),
71 b'HGPID': os.getpid(),
66 b'MSG1': msg[0] % msg[1:],
72 b'MSG1': msg[0] % msg[1:],
67 }
73 }
68 # keyword arguments get prefixed with OPT_ and uppercased
74 # keyword arguments get prefixed with OPT_ and uppercased
69 env.update((b'OPT_%s' % key.upper(), value)
75 env.update((b'OPT_%s' % key.upper(), value)
70 for key, value in pycompat.byteskwargs(opts).items())
76 for key, value in pycompat.byteskwargs(opts).items())
71 fullenv = procutil.shellenviron(env)
77 fullenv = procutil.shellenviron(env)
72 procutil.runbgcommand(script, fullenv, shell=True)
78 procutil.runbgcommand(script, fullenv, shell=True)
79
80 def uisetup(ui):
81
82 class logtoprocessui(ui.__class__):
83 def __init__(self, src=None):
84 super(logtoprocessui, self).__init__(src)
85 if src and r'_ltplogger' in src.__dict__:
86 self._ltplogger = src._ltplogger
87
88 # trick to initialize logger after configuration is loaded, which
89 # can be replaced later with processlogger(ui) in uisetup(), where
90 # both user and repo configurations should be available.
91 @util.propertycache
92 def _ltplogger(self):
93 return processlogger(self)
94
95 def log(self, event, *msg, **opts):
96 self._ltplogger.log(self, event, msg, opts)
73 return super(logtoprocessui, self).log(event, *msg, **opts)
97 return super(logtoprocessui, self).log(event, *msg, **opts)
74
98
75 # Replace the class for this instance and all clones created from it:
99 # Replace the class for this instance and all clones created from it:
76 ui.__class__ = logtoprocessui
100 ui.__class__ = logtoprocessui
General Comments 0
You need to be logged in to leave comments. Login now