[PATCH] ui: add optional timestamp to output
Matthieu Laneuville
mlaneuville at gmail.com
Tue Apr 11 13:50:08 UTC 2017
# HG changeset patch
# User Matthieu Laneuville <mlaneuville at gmail.com>
# Date 1489110756 -32400
# Fri Mar 10 10:52:36 2017 +0900
# Node ID f7c69a6deb56c856f6896f4f318fb125c3c5da37
# Parent 7433b3bc55eebfa9149280339b406bd4cec64efb
ui: add optional timestamp to output
This patch adds the possibility of having a timestamp prepended to every line.
For now, the feature is controled by an experimental config flag
'debug-timestamp' and format can be changed with debug-timestamp-format (default
is %H:%M:%S.%f).
The feature is still experimental because is still needs:
* win32 support,
* buffer support,
* label for the timestamp,
* a final UI.
A possible final UI would be to trigger this when combining '--debug' with
'--time' or maybe '--debug' and '--profile'. For now we focus on the
implementation.
diff -r 7433b3bc55ee -r f7c69a6deb56 mercurial/ui.py
--- a/mercurial/ui.py Mon Mar 06 23:21:27 2017 -0800
+++ b/mercurial/ui.py Fri Mar 10 10:52:36 2017 +0900
@@ -164,6 +164,8 @@ class ui(object):
self._colormode = None
self._terminfoparams = {}
self._styles = {}
+ # keeps track of lines start in _prependtimestamp
+ self._startline = {'std':True, 'err':True}
if src:
self.fout = src.fout
@@ -788,6 +790,32 @@ class ui(object):
return "".join(self._buffers.pop())
+ def _timestampprefix(self):
+ """Checks config if timestamp prefix should be used and return
+ format.
+ """
+ if not self.configbool("experimental", "debug-timestamp"):
+ return None
+ return self.config("experimental", "debug-timestamp-format",
+ default="%H:%M:%S.f")
+
+ def _prependtimestamp(self, args, tsformat, stream):
+ """Adds timestamp at the beginning of new lines. Both stdout and stderr
+ streams are tracked separately.
+ """
+ timestamp = util.datestr(format=tsformat)
+ timestamp = self.label(timestamp, 'debug.timestamp.stdout')
+ timestamp += ' '
+ msgs = []
+ for element in args:
+ for piece in element.splitlines(True):
+ if self._startline[stream]:
+ msgs.append(timestamp)
+ msgs.append(piece)
+ self._startline[stream] = piece.endswith('\n')
+
+ return msgs
+
def write(self, *args, **opts):
'''write args to output
@@ -804,6 +832,7 @@ class ui(object):
"cmdname.type" is recommended. For example, status issues
a label of "status.modified" for modified files.
'''
+ tsformat = self._timestampprefix()
if self._buffers and not opts.get('prompt', False):
if self._bufferapplylabels:
label = opts.get('label', '')
@@ -819,6 +848,8 @@ class ui(object):
if self._colormode is not None:
label = opts.get('label', '')
msgs = [self.label(a, label) for a in args]
+ if tsformat is not None:
+ msgs = self._prependtimestamp(msgs, tsformat, 'std')
self._write(*msgs, **opts)
def _write(self, *msgs, **opts):
@@ -833,6 +864,7 @@ class ui(object):
(util.timer() - starttime) * 1000
def write_err(self, *args, **opts):
+ tsformat = self._timestampprefix()
self._progclear()
if self._bufferstates and self._bufferstates[-1][0]:
self.write(*args, **opts)
@@ -845,6 +877,8 @@ class ui(object):
if self._colormode is not None:
label = opts.get('label', '')
msgs = [self.label(a, label) for a in args]
+ if tsformat is not None:
+ msgs = self._prependtimestamp(msgs, tsformat, 'err')
self._write_err(*msgs, **opts)
def _write_err(self, *msgs, **opts):
diff -r 7433b3bc55ee -r f7c69a6deb56 tests/test-debug-timestamp.t
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-debug-timestamp.t Fri Mar 10 10:52:36 2017 +0900
@@ -0,0 +1,142 @@
+ $ hg init
+ $ touch a
+ $ touch b
+
+Checking when the feature is disabled
+
+ $ hg status --config experimental.debug-timestamp=False
+ ? a
+ ? b
+
+Now after enabling it
+
+ $ cat >> $HGRCPATH << EOF
+ > [experimental]
+ > debug-timestamp=True
+ > debug-timestamp-format=%H:%M
+ > EOF
+
+Create an extension to test all cases
+
+ $ cat > $TESTTMP/foocommand.py << EOF
+ > from mercurial import cmdutil
+ > cmdtable = {}
+ > command = cmdutil.command(cmdtable)
+ >
+ > @command('testsinglestdout', [])
+ > def testsinglestdout(ui, repo):
+ > '''One stdout'''
+ > ui.write("stdout\n")
+ >
+ > @command('testsinglestderr', [])
+ > def testsinglestderr(ui, repo):
+ > '''One stderr'''
+ > ui.write_err("stderr\n")
+ >
+ > @command('testmultiplestdout', [])
+ > def testmultiplestdout(ui, repo):
+ > '''Multiple stdout, either multiple messages or multiple calls.'''
+ > ui.write("stdout1\n")
+ > ui.write("stdout2\n")
+ > ui.write("stdout3\n", "stdout4\n")
+ >
+ > @command('testmultiplestderr', [])
+ > def testsmultiplestderr(ui, repo):
+ > '''Multiple stderr, either multiple messages or multiple calls.'''
+ > ui.write_err("stderr1\n")
+ > ui.write_err("stderr2\n")
+ > ui.write_err("stderr3\n", "stderr4\n")
+ >
+ > @command('teststdnewline', [])
+ > def teststdnewline(ui, repo):
+ > '''stdout with multiple newlines in a message.'''
+ > ui.write("stdout1\nstdout2\n")
+ >
+ > @command('testerrnewline', [])
+ > def testerrnewline(ui, repo):
+ > '''stderr with multiple newlines in a message.'''
+ > ui.write_err("stderr1\nstderr2\n")
+ >
+ > @command('testouterr', [])
+ > def testouterr(ui, repo):
+ > '''Test both flux in sequence.'''
+ > ui.write("stdout1\n")
+ > ui.write_err("stderr1\n")
+ > ui.write("stdout2\n")
+ >
+ > @command('testinterleaved', [])
+ > def testinterleaved(ui, repo):
+ > '''Test interleaved fluxes.'''
+ > ui.write("stdout1 ")
+ > ui.write_err("stderr1\n")
+ > ui.write("stdout2 ")
+ > ui.write_err("stderr2\n")
+ > ui.write("stdout3\n")
+ >
+ > @command('testnewline2', [])
+ > def testsnewline(ui, repo):
+ > '''Multiple messages with and without newlines.'''
+ > ui.write("stdout1 ", "stdout2\n", "stdout3\n")
+ >
+ > @command('testnewline3', [])
+ > def testsnewline(ui, repo):
+ > '''Multiple calls with and without newlines.'''
+ > ui.write("stdout1 ")
+ > ui.write("stdout2\n")
+ > ui.write("stdout3\n")
+ > EOF
+
+Add extension to hgrc
+
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > foocommand=$TESTTMP/foocommand.py
+ > EOF
+
+Now test all cases
+
+ $ hg testsinglestdout
+ *:* stdout (glob)
+
+ $ hg testmultiplestdout
+ *:* stdout1 (glob)
+ *:* stdout2 (glob)
+ *:* stdout3 (glob)
+ *:* stdout4 (glob)
+
+ $ hg testsinglestderr
+ *:* stderr (glob)
+
+ $ hg testmultiplestderr
+ *:* stderr1 (glob)
+ *:* stderr2 (glob)
+ *:* stderr3 (glob)
+ *:* stderr4 (glob)
+
+ $ hg teststdnewline
+ *:* stdout1 (glob)
+ *:* stdout2 (glob)
+
+ $ hg testerrnewline
+ *:* stderr1 (glob)
+ *:* stderr2 (glob)
+
+ $ hg testnewline2
+ *:* stdout1 stdout2 (glob)
+ *:* stdout3 (glob)
+
+ $ hg testnewline3
+ *:* stdout1 stdout2 (glob)
+ *:* stdout3 (glob)
+
+ $ hg testouterr
+ *:* stdout1 (glob)
+ *:* stderr1 (glob)
+ *:* stdout2 (glob)
+
+ $ hg testinterleaved 2> stderr.log
+ *:* stdout1 stdout2 stdout3 (glob)
+
+ $ cat stderr.log
+ *:* stderr1 (glob)
+ *:* stderr2 (glob)
More information about the Mercurial-devel
mailing list