Rev 3219: Clean up logging, add push/pop_log_file, trace state can now be precisely pushed and restored in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Thu Feb 7 05:25:10 GMT 2008
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 3219
revision-id:pqm at pqm.ubuntu.com-20080207052502-jz28cn21r726b737
parent: pqm at pqm.ubuntu.com-20080206163804-6zyjbbfpsm8txfdm
parent: mbp at sourcefrog.net-20080207034957-cc7tlku5xfya9wei
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2008-02-07 05:25:02 +0000
message:
Clean up logging, add push/pop_log_file, trace state can now be precisely pushed and restored
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/symbol_versioning.py symbol_versioning.py-20060105104851-9ecf8af605d15a80
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/test_trace.py testtrace.py-20051110225523-a21117fc7a07eeff
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.15
revision-id:mbp at sourcefrog.net-20080207034957-cc7tlku5xfya9wei
parent: mbp at sourcefrog.net-20080206004104-mxtn32habuhjq6b8
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Thu 2008-02-07 14:49:57 +1100
message:
Update test_push_log_file to handle there always being timestamps at the start of the trace messages
modified:
bzrlib/tests/test_trace.py testtrace.py-20051110225523-a21117fc7a07eeff
------------------------------------------------------------
revno: 3173.1.14
revision-id:mbp at sourcefrog.net-20080206004104-mxtn32habuhjq6b8
parent: mbp at sourcefrog.net-20080129070504-g8vmi3hrd3n8iirl
parent: pqm at pqm.ubuntu.com-20080205231318-dcc9hdxcxjd7hx79
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Wed 2008-02-06 11:41:04 +1100
message:
Merge trunk
removed:
bzrlib/plugins/multiparent.py mpregen-20070411063203-5x9z7i73add0d6f6-1
added:
bzrlib/tests/repository_implementations/test_has_revisions.py test_has_revisions.p-20080111035443-xaupgdsx5fw1q54b-1
doc/en/user-guide/revnos.txt revnos.txt-20080111231928-pbntxea0ynh9ww1t-1
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzr bzr.py-20050313053754-5485f144c7006fa6
bzrlib/__init__.py __init__.py-20050309040759-33e65acf91bbcd5d
bzrlib/annotate.py annotate.py-20050922133147-7c60541d2614f022
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/bzrdir.py bzrdir.py-20060131065624-156dfea39c4387cb
bzrlib/commands.py bzr.py-20050309040720-d10f4714595cf8c3
bzrlib/debug.py debug.py-20061102062349-vdhrw9qdpck8cl35-1
bzrlib/delta.py delta.py-20050729221636-54cf14ef94783d0a
bzrlib/doc/api/__init__.py __init__.py-20051224020744-7b87d590843855bc
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/fetch.py fetch.py-20050818234941-26fea6105696365d
bzrlib/graph.py graph_walker.py-20070525030359-y852guab65d4wtn0-1
bzrlib/help_topics/__init__.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
bzrlib/inventory.py inventory.py-20050309040759-6648b84ca2005b37
bzrlib/knit.py knit.py-20051212171256-f056ac8f0fbe1bd9
bzrlib/merge.py merge.py-20050513021216-953b65a438527106
bzrlib/osutils.py osutils.py-20050309040759-eeaff12fbf77ac86
bzrlib/plugin.py plugin.py-20050622060424-829b654519533d69
bzrlib/plugins/launchpad/__init__.py __init__.py-20060315182712-2d5feebd2a1032dc
bzrlib/plugins/launchpad/lp_indirect.py lp_indirect.py-20070126012204-de5rugwlt22c7u7e-1
bzrlib/plugins/launchpad/lp_registration.py lp_registration.py-20060315190948-daa617eafe3a8d48
bzrlib/plugins/launchpad/test_lp_indirect.py test_lp_indirect.py-20070126002743-oyle362tzv9cd8mi-1
bzrlib/plugins/launchpad/test_register.py test_register.py-20060315182712-40f5dda945c829a8
bzrlib/reconfigure.py reconfigure.py-20070908040425-6ykgo7escxhyrg9p-1
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/repofmt/knitrepo.py knitrepo.py-20070206081537-pyy4a00xdas0j4pf-1
bzrlib/repofmt/pack_repo.py pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
bzrlib/repofmt/weaverepo.py presplitout.py-20070125045333-wfav3tsh73oxu3zk-1
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/revisiontree.py revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
bzrlib/smart/client.py client.py-20061116014825-2k6ada6xgulslami-1
bzrlib/smart/medium.py medium.py-20061103051856-rgu2huy59fkz902q-1
bzrlib/smart/protocol.py protocol.py-20061108035435-ot0lstk2590yqhzr-1
bzrlib/smart/repository.py repository.py-20061128022038-vr5wy5bubyb8xttk-1
bzrlib/smart/request.py request.py-20061108095550-gunadhxmzkdjfeek-1
bzrlib/status.py status.py-20050505062338-431bfa63ec9b19e6
bzrlib/symbol_versioning.py symbol_versioning.py-20060105104851-9ecf8af605d15a80
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
bzrlib/tests/blackbox/test_merge.py test_merge.py-20060323225809-9bc0459c19917f41
bzrlib/tests/blackbox/test_outside_wt.py test_outside_wt.py-20060116200058-98edd33e7db8bdde
bzrlib/tests/blackbox/test_pull.py test_pull.py-20051201144907-64959364f629947f
bzrlib/tests/blackbox/test_selftest.py test_selftest.py-20060123024542-01c5f1bbcb596d78
bzrlib/tests/interrepository_implementations/test_interrepository.py test_interrepository.py-20060220061411-1ec13fa99e5e3eee
bzrlib/tests/repository_implementations/__init__.py __init__.py-20060131092037-9564957a7d4a841b
bzrlib/tests/repository_implementations/test_repository.py test_repository.py-20060131092128-ad07f494f5c9d26c
bzrlib/tests/test_annotate.py test_annotate.py-20061213215015-sttc9agsxomls7q0-1
bzrlib/tests/test_diff.py testdiff.py-20050727164403-d1a3496ebb12e339
bzrlib/tests/test_errors.py test_errors.py-20060210110251-41aba2deddf936a8
bzrlib/tests/test_graph.py test_graph_walker.py-20070525030405-enq4r60hhi9xrujc-1
bzrlib/tests/test_http.py testhttp.py-20051018020158-b2eef6e867c514d9
bzrlib/tests/test_log.py testlog.py-20050728115707-1a514809d7d49309
bzrlib/tests/test_merge.py testmerge.py-20050905070950-c1b5aa49ff911024
bzrlib/tests/test_merge_core.py test_merge_core.py-20050824132511-eb99b23a0eec641b
bzrlib/tests/test_nonascii.py testnonascii.py-20051018022645-ea1d8b6477b058a6
bzrlib/tests/test_osutils.py test_osutils.py-20051201224856-e48ee24c12182989
bzrlib/tests/test_plugins.py plugins.py-20050622075746-32002b55e5e943e9
bzrlib/tests/test_reconfigure.py test_reconfigure.py-20070908040425-6ykgo7escxhyrg9p-2
bzrlib/tests/test_remote.py test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
bzrlib/tests/test_repository.py test_repository.py-20060131075918-65c555b881612f4d
bzrlib/tests/test_selftest.py test_selftest.py-20051202044319-c110a115d8c0456a
bzrlib/tests/test_smart.py test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
bzrlib/tests/test_trace.py testtrace.py-20051110225523-a21117fc7a07eeff
bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
bzrlib/tests/test_tsort.py testtsort.py-20051025073946-27da871c394d5be4
bzrlib/tests/workingtree_implementations/test_rename_one.py test_rename_one.py-20070226161242-2d8ibdedl700jgio-1
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
bzrlib/transform.py transform.py-20060105172343-dd99e54394d91687
bzrlib/transport/__init__.py transport.py-20050711165921-4978aa7ce1285ad5
bzrlib/transport/remote.py ssh.py-20060608202016-c25gvf1ob7ypbus6-1
bzrlib/tsort.py tsort.py-20051025073946-7808f6aaf7d07208
doc/developers/HACKING.txt HACKING-20050805200004-2a5dc975d870f78c
doc/en/tutorials/using_bazaar_with_launchpad.txt using_bazaar_with_lp-20071211073140-7msh8uf9a9h4y9hb-1
doc/en/user-guide/controlling_registration.txt controlling_registra-20071121073725-0corxykv5irjal00-3
doc/en/user-guide/core_concepts.txt core_concepts.txt-20071114035000-q36a9h57ps06uvnl-2
doc/en/user-guide/index.txt index.txt-20060622101119-tgwtdci8z769bjb9-2
------------------------------------------------------------
revno: 3173.1.13
revision-id:mbp at sourcefrog.net-20080129070504-g8vmi3hrd3n8iirl
parent: mbp at sourcefrog.net-20080129060611-clv6gh4ijuawhjvy
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-29 18:05:04 +1100
message:
Describe fixes by push/pop_log_file
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
------------------------------------------------------------
revno: 3173.1.12
revision-id:mbp at sourcefrog.net-20080129060611-clv6gh4ijuawhjvy
parent: mbp at sourcefrog.net-20080129060546-ndx1go4w0dord9d1
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-29 17:06:11 +1100
message:
Add test_push_log_file
modified:
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/test_trace.py testtrace.py-20051110225523-a21117fc7a07eeff
------------------------------------------------------------
revno: 3173.1.11
revision-id:mbp at sourcefrog.net-20080129060546-ndx1go4w0dord9d1
parent: mbp at sourcefrog.net-20080129060033-7t1w0rh448m3u6kr
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-29 17:05:46 +1100
message:
Fix up renaming of push_log_file
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.10
revision-id:mbp at sourcefrog.net-20080129060033-7t1w0rh448m3u6kr
parent: mbp at sourcefrog.net-20080122080302-9mhey64swvky8m5j
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-29 17:00:33 +1100
message:
Move assertFileEqual to TestCase base class as it's generally usable
modified:
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
------------------------------------------------------------
revno: 3173.1.9
revision-id:mbp at sourcefrog.net-20080122080302-9mhey64swvky8m5j
parent: mbp at sourcefrog.net-20080122080246-w724vmev1yt4mq1r
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 19:03:02 +1100
message:
tests should now call push/pop_test_log
modified:
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
------------------------------------------------------------
revno: 3173.1.8
revision-id:mbp at sourcefrog.net-20080122080246-w724vmev1yt4mq1r
parent: mbp at sourcefrog.net-20080122074230-87ijmlmu1jrwer3a
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 19:02:46 +1100
message:
doc update
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.7
revision-id:mbp at sourcefrog.net-20080122074230-87ijmlmu1jrwer3a
parent: mbp at sourcefrog.net-20080122072845-1ct7zakuje6w34j4
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 18:42:30 +1100
message:
Rename push/pop_log_file, and deprecate enable/disable_test_log
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.6
revision-id:mbp at sourcefrog.net-20080122072845-1ct7zakuje6w34j4
parent: mbp at sourcefrog.net-20080122070957-qmmxkkv090oapj88
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 18:28:45 +1100
message:
Remove _stderr_handler global
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.5
revision-id:mbp at sourcefrog.net-20080122070957-qmmxkkv090oapj88
parent: mbp at sourcefrog.net-20080122065434-4rtkpg2asj03hxcw
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 18:09:57 +1100
message:
Remove global _bzr_log_file
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.4
revision-id:mbp at sourcefrog.net-20080122065434-4rtkpg2asj03hxcw
parent: mbp at sourcefrog.net-20080122053400-2wbr56mi9byq9mez
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 17:54:34 +1100
message:
Rearrange and clean up bzr trace/logging
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.3
revision-id:mbp at sourcefrog.net-20080122053400-2wbr56mi9byq9mez
parent: mbp at sourcefrog.net-20080122042118-w3menysoh7wrtz8n
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 16:34:00 +1100
message:
Deprecate disable_default_logging and add 1.2 deprecation marker
modified:
bzrlib/symbol_versioning.py symbol_versioning.py-20060105104851-9ecf8af605d15a80
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.2
revision-id:mbp at sourcefrog.net-20080122042118-w3menysoh7wrtz8n
parent: mbp at sourcefrog.net-20080122040252-48p03j2u4y24d0u3
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 15:21:18 +1100
message:
bzrlib.trace docs and cleanups
modified:
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
------------------------------------------------------------
revno: 3173.1.1
revision-id:mbp at sourcefrog.net-20080122040252-48p03j2u4y24d0u3
parent: pqm at pqm.ubuntu.com-20080111025153-mqrn9i5o3hqezw75
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: 124153-test-kibble
timestamp: Tue 2008-01-22 15:02:52 +1100
message:
New _push_log_file and _pop_log_file as a cleaner stack, towards a fix for #124153
modified:
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/trace.py trace.py-20050309040759-c8ed824bdcd4748a
=== modified file 'NEWS'
--- a/NEWS 2008-02-06 16:38:04 +0000
+++ b/NEWS 2008-02-07 05:25:02 +0000
@@ -82,7 +82,15 @@
* List possible values for BZR_SSH environment variable in env-variables
help topic. (Alexander Belchenko, #181842)
- * pull --quiet is now more quiet, in particular a message is no longer
+ * New methods ``push_log_file`` and ``pop_log_file`` to intercept messages:
+ popping the log redirection now precisely restores the previous state,
+ which makes it easier to use bzr log output from other programs.
+ TestCaseInTempDir no longer depends on a log redirection being established
+ by the test framework, which lets bzr tests cleanly run from a normal
+ unittest runner.
+ (#124153, #124849, Martin Pool, Jonathan Lange)
+
+ * ``pull --quiet`` is now more quiet, in particular a message is no longer
printed when the remembered pull location is used. (James Westby,
#185907)
=== modified file 'bzrlib/symbol_versioning.py'
--- a/bzrlib/symbol_versioning.py 2008-01-17 03:14:20 +0000
+++ b/bzrlib/symbol_versioning.py 2008-02-06 00:41:04 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2006, 2007 Canonical Ltd
+# Copyright (C) 2006, 2007, 2008 Canonical Ltd
# Authors: Robert Collins <robert.collins at canonical.com> and others
#
# This program is free software; you can redistribute it and/or modify
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2008-01-29 08:21:19 +0000
+++ b/bzrlib/tests/__init__.py 2008-02-06 00:41:04 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007 Canonical Ltd
+# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -797,7 +797,6 @@
def setUp(self):
unittest.TestCase.setUp(self)
self._cleanEnvironment()
- bzrlib.trace.disable_default_logging()
self._silenceUI()
self._startLogFile()
self._benchcalls = []
@@ -1041,6 +1040,32 @@
else:
self.fail('Unexpected success. Should have failed: %s' % reason)
+ def assertFileEqual(self, content, path):
+ """Fail if path does not contain 'content'."""
+ self.failUnlessExists(path)
+ f = file(path, 'rb')
+ try:
+ s = f.read()
+ finally:
+ f.close()
+ self.assertEqualDiff(content, s)
+
+ def failUnlessExists(self, path):
+ """Fail unless path or paths, which may be abs or relative, exist."""
+ if not isinstance(path, basestring):
+ for p in path:
+ self.failUnlessExists(p)
+ else:
+ self.failUnless(osutils.lexists(path),path+" does not exist")
+
+ def failIfExists(self, path):
+ """Fail if path or paths, which may be abs or relative, exist."""
+ if not isinstance(path, basestring):
+ for p in path:
+ self.failIfExists(p)
+ else:
+ self.failIf(osutils.lexists(path),path+" exists")
+
def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
"""A helper for callDeprecated and applyDeprecated.
@@ -1159,7 +1184,7 @@
"""
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
self._log_file = os.fdopen(fileno, 'w+')
- self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
+ self._log_memento = bzrlib.trace.push_log_file(self._log_file)
self._log_file_name = name
self.addCleanup(self._finishLogFile)
@@ -1170,7 +1195,7 @@
"""
if self._log_file is None:
return
- bzrlib.trace.disable_test_log(self._log_nonce)
+ bzrlib.trace.pop_log_file(self._log_memento)
self._log_file.close()
self._log_file = None
if not self._keep_log_file:
@@ -2088,32 +2113,6 @@
def build_tree_contents(self, shape):
build_tree_contents(shape)
- def assertFileEqual(self, content, path):
- """Fail if path does not contain 'content'."""
- self.failUnlessExists(path)
- f = file(path, 'rb')
- try:
- s = f.read()
- finally:
- f.close()
- self.assertEqualDiff(content, s)
-
- def failUnlessExists(self, path):
- """Fail unless path or paths, which may be abs or relative, exist."""
- if not isinstance(path, basestring):
- for p in path:
- self.failUnlessExists(p)
- else:
- self.failUnless(osutils.lexists(path),path+" does not exist")
-
- def failIfExists(self, path):
- """Fail if path or paths, which may be abs or relative, exist."""
- if not isinstance(path, basestring):
- for p in path:
- self.failIfExists(p)
- else:
- self.failIf(osutils.lexists(path),path+" exists")
-
def assertInWorkingTree(self, path, root_path='.', tree=None):
"""Assert whether path or paths are in the WorkingTree"""
if tree is None:
=== modified file 'bzrlib/tests/test_trace.py'
--- a/bzrlib/tests/test_trace.py 2008-01-22 05:00:42 +0000
+++ b/bzrlib/tests/test_trace.py 2008-02-07 03:49:57 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007 Canonical Ltd
+# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
import os
import re
import sys
+import tempfile
from bzrlib import (
errors,
@@ -31,6 +32,8 @@
from bzrlib.trace import (
mutter, mutter_callsite, report_exception,
set_verbosity_level, get_verbosity_level, is_quiet, is_verbose, be_quiet,
+ pop_log_file,
+ push_log_file,
_rollover_trace_maybe,
)
@@ -158,6 +161,39 @@
self.assertContainsRe(log, "But fails in an ascii string")
self.assertContainsRe(log, u"ascii argument: \xb5")
+ def test_push_log_file(self):
+ """Can push and pop log file, and this catches mutter messages.
+
+ This is primarily for use in the test framework.
+ """
+ tmp1 = tempfile.NamedTemporaryFile()
+ tmp2 = tempfile.NamedTemporaryFile()
+ try:
+ memento1 = push_log_file(tmp1)
+ mutter("comment to file1")
+ try:
+ memento2 = push_log_file(tmp2)
+ try:
+ mutter("comment to file2")
+ finally:
+ pop_log_file(memento2)
+ mutter("again to file1")
+ finally:
+ pop_log_file(memento1)
+ # the files were opened in binary mode, so should have exactly
+ # these bytes. and removing the file as the log target should
+ # have caused them to be flushed out. need to match using regexps
+ # as there's a timestamp at the front.
+ tmp1.seek(0)
+ self.assertContainsRe(tmp1.read(),
+ r"\d+\.\d+ comment to file1\n\d+\.\d+ again to file1\n")
+ tmp2.seek(0)
+ self.assertContainsRe(tmp2.read(),
+ r"\d+\.\d+ comment to file2\n")
+ finally:
+ tmp1.close()
+ tmp2.close()
+
class TestVerbosityLevel(TestCase):
=== modified file 'bzrlib/trace.py'
--- a/bzrlib/trace.py 2008-01-22 05:00:42 +0000
+++ b/bzrlib/trace.py 2008-02-06 00:41:04 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007 Canonical Ltd
+# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -49,6 +49,11 @@
# FIXME: Unfortunately it turns out that python's logging module
# is quite expensive, even when the message is not printed by any handlers.
# We should perhaps change back to just simply doing it here.
+#
+# On the other hand, as of 1.2 we generally only call the mutter() statement
+# if (according to debug_flags) we actually intend to write it. So the
+# increased cost of logging.py is not so bad, and we could standardize on
+# that.
import codecs
import logging
@@ -73,35 +78,54 @@
errors,
osutils,
plugin,
+ symbol_versioning,
)
""")
-_file_handler = None
-_stderr_handler = None
+
+# global verbosity for bzrlib; controls the log level for stderr; 0=normal; <0
+# is quiet; >0 is verbose.
_verbosity_level = 0
+
+# File-like object where mutter/debug output is currently sent. Can be
+# changed by _push_log_file etc. This is directly manipulated by some
+# external code; maybe there should be functions to do that more precisely
+# than push/pop_log_file.
_trace_file = None
-_trace_depth = 0
-_bzr_log_file = None
+
+# Absolute path for ~/.bzr.log. Not changed even if the log/trace output is
+# redirected elsewhere. Used to show the location in --version.
_bzr_log_filename = None
-_start_time = bzrlib._start_time
-
-
-# configure convenient aliases for output routines
-
+
+# The time the first message was written to the trace file, so that we can
+# show relative times since startup.
+_bzr_log_start_time = bzrlib._start_time
+
+
+# held in a global for quick reference
_bzr_logger = logging.getLogger('bzr')
def note(*args, **kwargs):
# FIXME note always emits utf-8, regardless of the terminal encoding
+ #
+ # FIXME: clearing the ui and then going through the abstract logging
+ # framework is whack; we should probably have a logging Handler that
+ # deals with terminal output if needed.
import bzrlib.ui
bzrlib.ui.ui_factory.clear_term()
_bzr_logger.info(*args, **kwargs)
+
def warning(*args, **kwargs):
import bzrlib.ui
bzrlib.ui.ui_factory.clear_term()
_bzr_logger.warning(*args, **kwargs)
+
+# configure convenient aliases for output routines
+#
+# TODO: deprecate them, have one name for each.
info = note
log_error = _bzr_logger.error
error = _bzr_logger.error
@@ -128,11 +152,11 @@
out = fmt % tuple(real_args)
else:
out = fmt
- timestamp = '%0.3f ' % (time.time() - _start_time,)
+ timestamp = '%0.3f ' % (time.time() - _bzr_log_start_time,)
out = timestamp + out + '\n'
_trace_file.write(out)
- # TODO: jam 20051227 Consider flushing the trace file to help debugging
- #_trace_file.flush()
+ # no need to flush here, the trace file is now linebuffered when it's
+ # opened.
def mutter_callsite(stacklevel, fmt, *args):
@@ -162,44 +186,136 @@
return
-def open_tracefile(tracefilename=None):
- # Messages are always written to here, so that we have some
- # information if something goes wrong. In a future version this
- # file will be removed on successful completion.
- global _file_handler, _bzr_log_file, _bzr_log_filename
- import codecs
-
- if tracefilename is None:
- if sys.platform == 'win32':
- from bzrlib import win32utils
- home = win32utils.get_home_location()
- else:
- home = os.path.expanduser('~')
- _bzr_log_filename = os.path.join(home, '.bzr.log')
+def _get_bzr_log_filename():
+ # TODO: should this be overridden by $BZR_HOME?
+ if sys.platform == 'win32':
+ from bzrlib import win32utils
+ home = win32utils.get_home_location()
else:
- _bzr_log_filename = tracefilename
-
- _bzr_log_filename = os.path.expanduser(_bzr_log_filename)
+ home = os.path.expanduser('~')
+ return os.path.join(home, '.bzr.log')
+
+
+def _open_bzr_log():
+ """Open the .bzr.log trace file.
+
+ If the log is more than a particular length, the old file is renamed to
+ .bzr.log.old and a new file is started. Otherwise, we append to the
+ existing file.
+
+ This sets the global _bzr_log_filename.
+ """
+ global _bzr_log_filename
+ _bzr_log_filename = _get_bzr_log_filename()
_rollover_trace_maybe(_bzr_log_filename)
try:
- LINE_BUFFERED = 1
- #tf = codecs.open(trace_fname, 'at', 'utf8', buffering=LINE_BUFFERED)
- tf = open(_bzr_log_filename, 'at', LINE_BUFFERED)
- _bzr_log_file = tf
- # tf.tell() on windows always return 0 until some writing done
- tf.write('\n')
- if tf.tell() <= 2:
- tf.write("this is a debug log for diagnosing/reporting problems in bzr\n")
- tf.write("you can delete or truncate this file, or include sections in\n")
- tf.write("bug reports to https://bugs.launchpad.net/bzr/+filebug\n\n")
- _file_handler = logging.StreamHandler(tf)
- fmt = r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s'
- datefmt = r'%Y-%m-%d %H:%M:%S'
- _file_handler.setFormatter(logging.Formatter(fmt, datefmt))
- _file_handler.setLevel(logging.DEBUG)
- logging.getLogger('').addHandler(_file_handler)
+ bzr_log_file = open(_bzr_log_filename, 'at', 1) # line buffered
+ # bzr_log_file.tell() on windows always return 0 until some writing done
+ bzr_log_file.write('\n')
+ if bzr_log_file.tell() <= 2:
+ bzr_log_file.write("this is a debug log for diagnosing/reporting problems in bzr\n")
+ bzr_log_file.write("you can delete or truncate this file, or include sections in\n")
+ bzr_log_file.write("bug reports to https://bugs.launchpad.net/bzr/+filebug\n\n")
+ return bzr_log_file
except IOError, e:
warning("failed to open trace file: %s" % (e))
+ # TODO: What should happen if we fail to open the trace file? Maybe the
+ # objects should be pointed at /dev/null or the equivalent? Currently
+ # returns None which will cause failures later.
+
+
+def enable_default_logging():
+ """Configure default logging: messages to stderr and debug to .bzr.log
+
+ This should only be called once per process.
+
+ Non-command-line programs embedding bzrlib do not need to call this. They
+ can instead either pass a file to _push_log_file, or act directly on
+ logging.getLogger("bzr").
+
+ Output can be redirected away by calling _push_log_file.
+ """
+ # create encoded wrapper around stderr
+ bzr_log_file = _open_bzr_log()
+ push_log_file(bzr_log_file,
+ r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s',
+ r'%Y-%m-%d %H:%M:%S')
+ # after hooking output into bzr_log, we also need to attach a stderr
+ # handler, writing only at level info and with encoding
+ writer_factory = codecs.getwriter(osutils.get_terminal_encoding())
+ encoded_stderr = writer_factory(sys.stderr, errors='replace')
+ stderr_handler = logging.StreamHandler(encoded_stderr)
+ stderr_handler.setLevel(logging.INFO)
+ logging.getLogger('bzr').addHandler(stderr_handler)
+
+
+def push_log_file(to_file, log_format=None, date_format=None):
+ """Intercept log and trace messages and send them to a file.
+
+ :param to_file: A file-like object to which messages will be sent.
+
+ :returns: A memento that should be passed to _pop_log_file to restore the
+ previously active logging.
+ """
+ global _trace_file
+ # make a new handler
+ new_handler = logging.StreamHandler(to_file)
+ new_handler.setLevel(logging.DEBUG)
+ if log_format is None:
+ log_format = '%(levelname)8s %(message)s'
+ new_handler.setFormatter(logging.Formatter(log_format, date_format))
+ # save and remove any existing log handlers
+ bzr_logger = logging.getLogger('bzr')
+ old_handlers = bzr_logger.handlers[:]
+ del bzr_logger.handlers[:]
+ # set that as the default logger
+ bzr_logger.addHandler(new_handler)
+ bzr_logger.setLevel(logging.DEBUG)
+ # TODO: check if any changes are needed to the root logger
+ #
+ # TODO: also probably need to save and restore the level on bzr_logger.
+ # but maybe we can avoid setting the logger level altogether, and just set
+ # the level on the handler?
+ #
+ # save the old trace file
+ old_trace_file = _trace_file
+ # send traces to the new one
+ _trace_file = to_file
+ result = new_handler, _trace_file
+ return ('log_memento', old_handlers, new_handler, old_trace_file, to_file)
+
+
+def pop_log_file((magic, old_handlers, new_handler, old_trace_file, new_trace_file)):
+ """Undo changes to logging/tracing done by _push_log_file.
+
+ This flushes, but does not close the trace file.
+
+ Takes the memento returned from _push_log_file."""
+ assert magic == 'log_memento'
+ global _trace_file
+ _trace_file = old_trace_file
+ bzr_logger = logging.getLogger('bzr')
+ bzr_logger.removeHandler(new_handler)
+ # must be closed, otherwise logging will try to close it atexit, and the
+ # file will likely already be closed underneath.
+ new_handler.close()
+ bzr_logger.handlers = old_handlers
+ new_trace_file.flush()
+
+
+ at symbol_versioning.deprecated_function(symbol_versioning.one_two)
+def enable_test_log(to_file):
+ """Redirect logging to a temporary file for a test
+
+ :returns: an opaque reference that should be passed to disable_test_log
+ after the test completes.
+ """
+ return push_log_file(to_file)
+
+
+ at symbol_versioning.deprecated_function(symbol_versioning.one_two)
+def disable_test_log(memento):
+ return pop_log_file(memento)
def log_exception_quietly():
@@ -209,28 +325,9 @@
interesting to developers but not to users. For example,
errors loading plugins.
"""
- import traceback
mutter(traceback.format_exc())
-def enable_default_logging():
- """Configure default logging to stderr and .bzr.log"""
- # FIXME: if this is run twice, things get confused
- global _stderr_handler, _file_handler, _trace_file, _bzr_log_file
- # create encoded wrapper around stderr
- stderr = codecs.getwriter(osutils.get_terminal_encoding())(sys.stderr,
- errors='replace')
- _stderr_handler = logging.StreamHandler(stderr)
- logging.getLogger('').addHandler(_stderr_handler)
- _stderr_handler.setLevel(logging.INFO)
- if not _file_handler:
- open_tracefile()
- _trace_file = _bzr_log_file
- if _file_handler:
- _file_handler.setLevel(logging.DEBUG)
- _bzr_logger.setLevel(logging.DEBUG)
-
-
def set_verbosity_level(level):
"""Set the verbosity level.
@@ -260,9 +357,9 @@
def _update_logging_level(quiet=True):
"""Hide INFO messages if quiet."""
if quiet:
- _stderr_handler.setLevel(logging.WARNING)
+ _bzr_logger.setLevel(logging.WARNING)
else:
- _stderr_handler.setLevel(logging.INFO)
+ _bzr_logger.setLevel(logging.INFO)
def is_quiet():
@@ -275,49 +372,13 @@
return _verbosity_level > 0
+ at symbol_versioning.deprecated_function(symbol_versioning.one_two)
def disable_default_logging():
"""Turn off default log handlers.
- This is intended to be used by the test framework, which doesn't
- want leakage from the code-under-test into the main logs.
- """
-
- l = logging.getLogger('')
- l.removeHandler(_stderr_handler)
- if _file_handler:
- l.removeHandler(_file_handler)
- _trace_file = None
-
-
-def enable_test_log(to_file):
- """Redirect logging to a temporary file for a test
-
- returns an opaque reference that should be passed to disable_test_log
- after the test completes.
- """
- disable_default_logging()
- global _trace_file
- global _trace_depth
- hdlr = logging.StreamHandler(to_file)
- hdlr.setLevel(logging.DEBUG)
- hdlr.setFormatter(logging.Formatter('%(levelname)8s %(message)s'))
- _bzr_logger.addHandler(hdlr)
- _bzr_logger.setLevel(logging.DEBUG)
- result = hdlr, _trace_file, _trace_depth
- _trace_file = to_file
- _trace_depth += 1
- return result
-
-
-def disable_test_log((test_log_hdlr, old_trace_file, old_trace_depth)):
- _bzr_logger.removeHandler(test_log_hdlr)
- test_log_hdlr.close()
- global _trace_file
- global _trace_depth
- _trace_file = old_trace_file
- _trace_depth = old_trace_depth
- if not _trace_depth:
- enable_default_logging()
+ Don't call this method, use _push_log_file and _pop_log_file instead.
+ """
+ pass
def report_exception(exc_info, err_file):
@@ -364,7 +425,6 @@
def report_bug(exc_info, err_file):
"""Report an exception that probably indicates a bug in bzr"""
- import traceback
exc_type, exc_object, exc_tb = exc_info
err_file.write("bzr: ERROR: %s.%s: %s\n" % (
exc_type.__module__, exc_type.__name__, exc_object))
More information about the bazaar-commits
mailing list