Rev 5324: (lifeless) Make the trace module managed more cleanly by BzrLibraryState. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Mon Jun 28 05:42:09 BST 2010


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5324 [merge]
revision-id: pqm at pqm.ubuntu.com-20100628044207-67md0bfc3ojod6of
parent: pqm at pqm.ubuntu.com-20100628031248-icctusovofhlk7z9
parent: robertc at robertcollins.net-20100628032326-nwwjuav8wuby7r63
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2010-06-28 05:42:07 +0100
message:
  (lifeless) Make the trace module managed more cleanly by BzrLibraryState.
   (Robert Collins)
added:
  bzrlib/library_state.py        library_state.py-20100625053036-962zdkiik8k6m5jx-1
  bzrlib/tests/test_library_state.py test_library_state.p-20100625052815-tig59sysysgqd6wh-1
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/__init__.py             __init__.py-20050309040759-33e65acf91bbcd5d
  bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
  bzrlib/symbol_versioning.py    symbol_versioning.py-20060105104851-9ecf8af605d15a80
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/blackbox/test_commit.py test_commit.py-20060212094538-ae88fc861d969db0
  bzrlib/tests/fixtures.py       fixtures.py-20100514150609-1kpa1jqaciel01wn-1
  bzrlib/tests/test_osutils_encodings.py test_osutils_encodin-20061226013130-kkp732tpt3lm91vv-1
  bzrlib/tests/test_symbol_versioning.py test_symbol_versioning.py-20060105104851-51d7722c2018d42b
  bzrlib/tests/test_trace.py     testtrace.py-20051110225523-a21117fc7a07eeff
  bzrlib/trace.py                trace.py-20050309040759-c8ed824bdcd4748a
  bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
=== modified file 'NEWS'
--- a/NEWS	2010-06-28 03:12:48 +0000
+++ b/NEWS	2010-06-28 03:23:26 +0000
@@ -180,12 +180,22 @@
 Internals
 *********
 
+* ``bzrlib.osutils.get_terminal_encoding`` will now only mutter its
+  selection when explicitly requested; this avoids many duplicate calls
+  being logged when helpers, wrappers and older code that manually calls
+  it are executed it is now logged deliberately by the ui setup code.
+  (Robert Collins)
+
 * Improved ``bzrlib.urlutils`` to handle lp:foo/bar URLs. (Gordon Tyler)
 
 * ``bzrlib._c_static_tuple.StaticTuple`` now implements ``__sizeof__``, so
   that ``sys.getsizeof`` and other memory analysis tools will report more
   accurate results. (Andrew Bennetts)
 
+* The symbol_versioning module can now cleanup after itself -
+  ``suppress_deprecation_warnings`` now returns a cleanup function.
+  (Robert Collins)
+
 Testing
 *******
 

=== modified file 'bzrlib/__init__.py'
--- a/bzrlib/__init__.py	2010-06-21 20:03:23 +0000
+++ b/bzrlib/__init__.py	2010-06-26 02:15:26 +0000
@@ -131,12 +131,12 @@
 
 # bzr has various bits of global state that are slowly being eliminated.
 # This variable is intended to permit any new state-like things to be attached
-# to a BzrLibraryState object rather than getting new global variables that
-# need to be hunted down. Accessing the current BzrLibraryState through this
-# variable is not encouraged: it is better to pass it around as part of the
-# context of an operation than to look it up directly, but when that is too
-# hard, it is better to use this variable than to make a branch new global
-# variable.
+# to a library_state.BzrLibraryState object rather than getting new global
+# variables that need to be hunted down. Accessing the current BzrLibraryState
+# through this variable is not encouraged: it is better to pass it around as
+# part of the context of an operation than to look it up directly, but when
+# that is too hard, it is better to use this variable than to make a branch new
+# global variable.
 # If using this variable by looking it up (because it can't be easily obtained)
 # it is important to store the reference you get, rather than looking it up
 # repeatedly; that way your code will behave properly in the bzrlib test suite
@@ -144,82 +144,6 @@
 global_state = None
 
 
-class BzrLibraryState(object):
-    """The state about how bzrlib has been configured.
-    
-    :ivar saved_state: The bzrlib.global_state at the time __enter__ was
-        called.
-    :ivar cleanups: An ObjectWithCleanups which can be used for cleanups that
-        should occur when the use of bzrlib is completed. This is initialised
-        in __enter__ and executed in __exit__.
-    """
-
-    def __init__(self, setup_ui=True, stdin=None, stdout=None, stderr=None):
-        """Create library start for normal use of bzrlib.
-
-        Most applications that embed bzrlib, including bzr itself, should just
-        call bzrlib.initialize(), but it is possible to use the state class
-        directly.
-
-        More options may be added in future so callers should use named
-        arguments.
-
-        BzrLibraryState implements the Python 2.5 Context Manager protocol
-        PEP343, and can be used with the with statement. Upon __enter__ the
-        global variables in use by bzr are set, and they are cleared on
-        __exit__.
-
-        :param setup_ui: If true (default) use a terminal UI; otherwise 
-            some other ui_factory must be assigned to `bzrlib.ui.ui_factory` by
-            the caller.
-        :param stdin, stdout, stderr: If provided, use these for terminal IO;
-            otherwise use the files in `sys`.
-        """
-        self.setup_ui = setup_ui
-        self.stdin = stdin
-        self.stdout = stdout
-        self.stderr = stderr
-
-    def __enter__(self):
-        # NB: This function tweaks so much global state it's hard to test it in
-        # isolation within the same interpreter.  It's not reached on normal
-        # in-process run_bzr calls.  If it's broken, we expect that
-        # TestRunBzrSubprocess may fail.
-        if version_info[3] == 'final':
-            from bzrlib.symbol_versioning import suppress_deprecation_warnings
-            suppress_deprecation_warnings(override=True)
-
-        import bzrlib.cleanup
-        import bzrlib.trace
-        self.cleanups = bzrlib.cleanup.ObjectWithCleanups()
-        bzrlib.trace.enable_default_logging()
-
-        if self.setup_ui:
-            import bzrlib.ui
-            stdin = self.stdin or sys.stdin
-            stdout = self.stdout or sys.stdout
-            stderr = self.stderr or sys.stderr
-            bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
-                stdin, stdout, stderr)
-        global global_state
-        self.saved_state = global_state
-        global_state = self
-        return self # This is bound to the 'as' clause in a with statement.
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.cleanups.cleanup_now()
-        import bzrlib.ui
-        bzrlib.trace._flush_stdout_stderr()
-        bzrlib.trace._flush_trace()
-        import bzrlib.osutils
-        bzrlib.osutils.report_extension_load_failures()
-        bzrlib.ui.ui_factory.__exit__(None, None, None)
-        bzrlib.ui.ui_factory = None
-        global global_state
-        global_state = self.saved_state
-        return False # propogate exceptions.
-
-
 def initialize(setup_ui=True, stdin=None, stdout=None, stderr=None):
     """Set up everything needed for normal use of bzrlib.
 
@@ -239,8 +163,17 @@
         otherwise stopping use of bzrlib. Advanced callers can use
         BzrLibraryState directly.
     """
-    return BzrLibraryState(setup_ui=setup_ui, stdin=stdin,
-        stdout=stdout, stderr=stderr)
+    import bzrlib.library_state
+    if setup_ui:
+        import bzrlib.ui
+        stdin = stdin or sys.stdin
+        stdout = stdout or sys.stdout
+        stderr = stderr or sys.stderr
+        ui_factory = bzrlib.ui.make_ui_for_terminal(stdin, stdout, stderr)
+    else:
+        ui_factory = None
+    tracer = bzrlib.trace.DefaultConfig()
+    return bzrlib.library_state.BzrLibraryState(ui=ui_factory, trace=tracer)
 
 
 def test_suite():

=== added file 'bzrlib/library_state.py'
--- a/bzrlib/library_state.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/library_state.py	2010-06-26 01:07:16 +0000
@@ -0,0 +1,103 @@
+# Copyright (C) 2010 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""The core state needed to make use of bzr is managed here."""
+
+__all__ = [
+    'BzrLibraryState',
+    ]
+
+import sys
+
+import bzrlib
+
+
+class BzrLibraryState(object):
+    """The state about how bzrlib has been configured.
+
+    This is the core state needed to make use of bzr. The current instance is
+    currently always exposed as bzrlib.global_state, but we desired to move
+    to a point where no global state is needed at all.
+    
+    :ivar saved_state: The bzrlib.global_state at the time __enter__ was
+        called.
+    :ivar cleanups: An ObjectWithCleanups which can be used for cleanups that
+        should occur when the use of bzrlib is completed. This is initialised
+        in __enter__ and executed in __exit__.
+    """
+
+    def __init__(self, ui, trace):
+        """Create library start for normal use of bzrlib.
+
+        Most applications that embed bzrlib, including bzr itself, should just
+        call bzrlib.initialize(), but it is possible to use the state class
+        directly. The initialize() function provides sensible defaults for a
+        CLI program, such as a text UI factory.
+
+        More options may be added in future so callers should use named
+        arguments.
+
+        BzrLibraryState implements the Python 2.5 Context Manager protocol
+        PEP343, and can be used with the with statement. Upon __enter__ the
+        global variables in use by bzr are set, and they are cleared on
+        __exit__.
+
+        :param ui: A bzrlib.ui.ui_factory to use.
+        :param trace: A bzrlib.trace.Config context manager to use, perhaps
+            bzrlib.trace.DefaultConfig.
+        """
+        self._ui = ui
+        self._trace = trace
+
+    def __enter__(self):
+        # NB: This function tweaks so much global state it's hard to test it in
+        # isolation within the same interpreter.  It's not reached on normal
+        # in-process run_bzr calls.  If it's broken, we expect that
+        # TestRunBzrSubprocess may fail.
+        import bzrlib
+        if bzrlib.version_info[3] == 'final':
+            from bzrlib.symbol_versioning import suppress_deprecation_warnings
+            warning_cleanup = suppress_deprecation_warnings(override=True)
+        else:
+            warning_cleanup = None
+
+        import bzrlib.cleanup
+        self.cleanups = bzrlib.cleanup.ObjectWithCleanups()
+        if warning_cleanup:
+            self.cleanups.add_cleanup(warning_cleanup)
+        self._trace.__enter__()
+
+        self._orig_ui = bzrlib.ui.ui_factory
+        bzrlib.ui.ui_factory = self._ui
+        self._ui.__enter__()
+
+        self.saved_state = bzrlib.global_state
+        bzrlib.global_state = self
+        return self # This is bound to the 'as' clause in a with statement.
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.cleanups.cleanup_now()
+        import bzrlib.ui
+        bzrlib.trace._flush_stdout_stderr()
+        bzrlib.trace._flush_trace()
+        import bzrlib.osutils
+        bzrlib.osutils.report_extension_load_failures()
+        self._ui.__exit__(None, None, None)
+        self._trace.__exit__(None, None, None)
+        bzrlib.ui.ui_factory = self._orig_ui
+        global global_state
+        global_state = self.saved_state
+        return False # propogate exceptions.

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2010-06-18 10:57:20 +0000
+++ b/bzrlib/osutils.py	2010-06-25 20:34:05 +0000
@@ -441,7 +441,7 @@
     getcwd = _mac_getcwd
 
 
-def get_terminal_encoding():
+def get_terminal_encoding(trace=False):
     """Find the best encoding for printing to the screen.
 
     This attempts to check both sys.stdout and sys.stdin to see
@@ -453,6 +453,8 @@
 
     On my standard US Windows XP, the preferred encoding is
     cp1252, but the console is cp437
+
+    :param trace: If True trace the selected encoding via mutter().
     """
     from bzrlib.trace import mutter
     output_encoding = getattr(sys.stdout, 'encoding', None)
@@ -460,17 +462,22 @@
         input_encoding = getattr(sys.stdin, 'encoding', None)
         if not input_encoding:
             output_encoding = get_user_encoding()
-            mutter('encoding stdout as osutils.get_user_encoding() %r',
+            if trace:
+                mutter('encoding stdout as osutils.get_user_encoding() %r',
                    output_encoding)
         else:
             output_encoding = input_encoding
-            mutter('encoding stdout as sys.stdin encoding %r', output_encoding)
+            if trace:
+                mutter('encoding stdout as sys.stdin encoding %r',
+                    output_encoding)
     else:
-        mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
+        if trace:
+            mutter('encoding stdout as sys.stdout encoding %r', output_encoding)
     if output_encoding == 'cp0':
         # invalid encoding (cp0 means 'no codepage' on Windows)
         output_encoding = get_user_encoding()
-        mutter('cp0 is invalid encoding.'
+        if trace:
+            mutter('cp0 is invalid encoding.'
                ' encoding stdout as osutils.get_user_encoding() %r',
                output_encoding)
     # check encoding

=== modified file 'bzrlib/symbol_versioning.py'
--- a/bzrlib/symbol_versioning.py	2009-09-15 02:28:34 +0000
+++ b/bzrlib/symbol_versioning.py	2010-06-25 06:11:21 +0000
@@ -314,6 +314,7 @@
 
     :param override: If True, always set the ignore, if False, only set the
         ignore if there isn't already a filter.
+    :return: A callable to remove the new warnings this added.
     """
     import warnings
     if not override and _check_for_filter(error_only=False):
@@ -321,6 +322,10 @@
         # then skip it.
         return
     warnings.filterwarnings('ignore', category=DeprecationWarning)
+    filter = warnings.filters[0]
+    def cleanup():
+        warnings.filters.remove(filter)
+    return cleanup
 
 
 def activate_deprecation_warnings(override=True):

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2010-06-25 01:49:49 +0000
+++ b/bzrlib/tests/__init__.py	2010-06-25 06:12:56 +0000
@@ -3733,6 +3733,7 @@
         'bzrlib.tests.test_knit',
         'bzrlib.tests.test_lazy_import',
         'bzrlib.tests.test_lazy_regex',
+        'bzrlib.tests.test_library_state',
         'bzrlib.tests.test_lock',
         'bzrlib.tests.test_lockable_files',
         'bzrlib.tests.test_lockdir',

=== modified file 'bzrlib/tests/blackbox/test_commit.py'
--- a/bzrlib/tests/blackbox/test_commit.py	2010-06-11 07:32:12 +0000
+++ b/bzrlib/tests/blackbox/test_commit.py	2010-06-28 02:41:22 +0000
@@ -129,7 +129,7 @@
         # by ui.text.show_warning
         default_get_terminal_enc = osutils.get_terminal_encoding
         try:
-            osutils.get_terminal_encoding = lambda: 'ascii'
+            osutils.get_terminal_encoding = lambda trace=None: 'ascii'
             file_name = u'foo\u1234'
             open(file_name, 'w').write('hello world')
             self.run_bzr(['add'])

=== modified file 'bzrlib/tests/fixtures.py'
--- a/bzrlib/tests/fixtures.py	2010-06-21 22:29:38 +0000
+++ b/bzrlib/tests/fixtures.py	2010-06-26 01:07:16 +0000
@@ -82,3 +82,18 @@
     else:
         e = [n for (n, u) in interesting_encodings]
     return itertools.cycle(iter(e))
+
+
+class RecordingContextManager(object):
+    """A context manager that records."""
+
+    def __init__(self):
+        self._calls = []
+
+    def __enter__(self):
+        self._calls.append('__enter__')
+        return self # This is bound to the 'as' clause in a with statement.
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self._calls.append('__exit__')
+        return False # propogate exceptions.

=== added file 'bzrlib/tests/test_library_state.py'
--- a/bzrlib/tests/test_library_state.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/test_library_state.py	2010-06-26 01:07:16 +0000
@@ -0,0 +1,52 @@
+# Copyright (C) 2010 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""Tests for BzrLibraryState."""
+
+import bzrlib
+from bzrlib import (
+    library_state,
+    tests,
+    ui as _mod_ui
+    )
+from bzrlib.tests import fixtures
+
+
+# TODO: once sufficiently cleaned up this should be able to be TestCase.
+class TestLibraryState(tests.TestCaseWithTransport):
+
+    def test_ui_is_used(self):
+        ui = _mod_ui.SilentUIFactory()
+        state = library_state.BzrLibraryState(
+            ui=ui, trace=fixtures.RecordingContextManager())
+        orig_ui = _mod_ui.ui_factory
+        state.__enter__()
+        try:
+            self.assertEqual(ui, _mod_ui.ui_factory)
+        finally:
+            state.__exit__(None, None, None)
+            self.assertEqual(orig_ui, _mod_ui.ui_factory)
+
+    def test_trace_context(self):
+        tracer = fixtures.RecordingContextManager()
+        ui = _mod_ui.SilentUIFactory()
+        state = library_state.BzrLibraryState(ui=ui, trace=tracer)
+        state.__enter__()
+        try:
+            self.assertEqual(['__enter__'], tracer._calls)
+        finally:
+            state.__exit__(None, None, None)
+            self.assertEqual(['__enter__', '__exit__'], tracer._calls)

=== modified file 'bzrlib/tests/test_osutils_encodings.py'
--- a/bzrlib/tests/test_osutils_encodings.py	2010-01-25 17:48:22 +0000
+++ b/bzrlib/tests/test_osutils_encodings.py	2010-06-25 20:34:05 +0000
@@ -114,6 +114,26 @@
         # and in the worst case, use osutils.get_user_encoding()
         self.assertEqual('user_encoding', osutils.get_terminal_encoding())
 
+    def test_get_terminal_encoding_silent(self):
+        self.make_wrapped_streams('stdout_encoding',
+                                  'stderr_encoding',
+                                  'stdin_encoding')
+        # Calling get_terminal_encoding should not mutter when silent=True is
+        # passed.
+        log = self.get_log()
+        osutils.get_terminal_encoding()
+        self.assertEqual(log, self.get_log())
+
+    def test_get_terminal_encoding_trace(self):
+        self.make_wrapped_streams('stdout_encoding',
+                                  'stderr_encoding',
+                                  'stdin_encoding')
+        # Calling get_terminal_encoding should not mutter when silent=True is
+        # passed.
+        log = self.get_log()
+        osutils.get_terminal_encoding(trace=True)
+        self.assertNotEqual(log, self.get_log())
+
     def test_terminal_cp0(self):
         # test cp0 encoding (Windows returns cp0 when there is no encoding)
         self.make_wrapped_streams('cp0',

=== modified file 'bzrlib/tests/test_symbol_versioning.py'
--- a/bzrlib/tests/test_symbol_versioning.py	2010-04-23 08:51:52 +0000
+++ b/bzrlib/tests/test_symbol_versioning.py	2010-06-25 06:11:21 +0000
@@ -241,6 +241,11 @@
         symbol_versioning.suppress_deprecation_warnings()
         self.assertFirstWarning('ignore', DeprecationWarning)
 
+    def test_set_restore_filters(self):
+        original_filters = warnings.filters[:]
+        symbol_versioning.suppress_deprecation_warnings()()
+        self.assertEqual(original_filters, warnings.filters)
+
     def test_suppress_deprecation_with_warning_filter(self):
         """don't suppress if we already have a filter"""
         warnings.filterwarnings('error', category=Warning)

=== modified file 'bzrlib/tests/test_trace.py'
--- a/bzrlib/tests/test_trace.py	2010-05-20 21:45:02 +0000
+++ b/bzrlib/tests/test_trace.py	2010-06-26 01:07:16 +0000
@@ -333,3 +333,21 @@
         _rollover_trace_maybe(temp_log_name)
         # should have been rolled over
         self.assertFalse(os.access(temp_log_name, os.R_OK))
+
+
+class TestTraceConfiguration(TestCaseInTempDir):
+
+    def test_default_config(self):
+        config = trace.DefaultConfig()
+        self.overrideAttr(trace, "_bzr_log_filename", None)
+        trace._bzr_log_filename = None
+        expected_filename = trace._get_bzr_log_filename()
+        self.assertEqual(None, trace._bzr_log_filename)
+        config.__enter__()
+        try:
+            # Should have entered and setup a default filename.
+            self.assertEqual(expected_filename, trace._bzr_log_filename)
+        finally:
+            config.__exit__(None, None, None)
+            # Should have exited and cleaned up.
+            self.assertEqual(None, trace._bzr_log_filename)

=== modified file 'bzrlib/trace.py'
--- a/bzrlib/trace.py	2010-06-21 03:15:55 +0000
+++ b/bzrlib/trace.py	2010-06-28 02:41:22 +0000
@@ -306,26 +306,27 @@
     logging.getLogger("bzr").
 
     Output can be redirected away by calling _push_log_file.
+
+    :return: A memento from push_log_file for restoring the log state.
     """
-    # Do this before we open the log file, so we prevent
-    # get_terminal_encoding() from mutter()ing multiple times
-    term_encoding = osutils.get_terminal_encoding()
     start_time = osutils.format_local_date(_bzr_log_start_time,
                                            timezone='local')
     # create encoded wrapper around stderr
     bzr_log_file = _open_bzr_log()
     if bzr_log_file is not None:
         bzr_log_file.write(start_time.encode('utf-8') + '\n')
-    push_log_file(bzr_log_file,
+    memento = 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
+    term_encoding = osutils.get_terminal_encoding()
     writer_factory = codecs.getwriter(term_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)
+    return memento
 
 
 def push_log_file(to_file, log_format=None, date_format=None):
@@ -367,7 +368,8 @@
 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.
+    This flushes, but does not close the trace file (so that anything that was
+    in it is output.
 
     Takes the memento returned from _push_log_file."""
     global _trace_file
@@ -378,7 +380,8 @@
     # file will likely already be closed underneath.
     new_handler.close()
     bzr_logger.handlers = old_handlers
-    new_trace_file.flush()
+    if new_trace_file is not None:
+        new_trace_file.flush()
 
 
 def log_exception_quietly():
@@ -557,3 +560,36 @@
     global _trace_file
     if _trace_file:
         _trace_file.flush()
+
+
+class Config(object):
+    """Configuration of message tracing in bzrlib.
+
+    This implements the context manager protocol and should manage any global
+    variables still used. The default config used is DefaultConfig, but
+    embedded uses of bzrlib may wish to use a custom manager.
+    """
+
+    def __enter__(self):
+        return self # This is bound to the 'as' clause in a with statement.
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        return False # propogate exceptions.
+
+
+class DefaultConfig(Config):
+    """A default configuration for tracing of messages in bzrlib.
+
+    This implements the context manager protocol.
+    """
+
+    def __enter__(self):
+        self._original_filename = _bzr_log_filename
+        self._original_state = enable_default_logging()
+        return self # This is bound to the 'as' clause in a with statement.
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        pop_log_file(self._original_state)
+        global _bzr_log_filename
+        _bzr_log_filename = self._original_filename
+        return False # propogate exceptions.

=== modified file 'bzrlib/ui/__init__.py'
--- a/bzrlib/ui/__init__.py	2010-06-23 08:14:21 +0000
+++ b/bzrlib/ui/__init__.py	2010-06-25 20:34:05 +0000
@@ -192,7 +192,7 @@
             encoding = config.GlobalConfig().get_user_option(
                 'output_encoding')
         if encoding is None:
-            encoding = osutils.get_terminal_encoding()
+            encoding = osutils.get_terminal_encoding(trace=True)
         if encoding_type is None:
             encoding_type = 'replace'
         out_stream = self._make_output_stream_explicit(encoding, encoding_type)




More information about the bazaar-commits mailing list