Merge lp:~mbp/bzr/remove-logging into lp:bzr

Proposed by Martin Pool
Status: Superseded
Proposed branch: lp:~mbp/bzr/remove-logging
Merge into: lp:bzr
Diff against target: 903 lines (+196/-208)
21 files modified
NEWS (+17/-0)
bzr (+8/-3)
bzrlib/cleanup.py (+1/-1)
bzrlib/osutils.py (+1/-1)
bzrlib/status.py (+4/-6)
bzrlib/tests/TestUtil.py (+1/-20)
bzrlib/tests/__init__.py (+1/-2)
bzrlib/tests/blackbox/test_exceptions.py (+1/-18)
bzrlib/tests/blackbox/test_reconcile.py (+4/-4)
bzrlib/tests/blackbox/test_reconfigure.py (+6/-6)
bzrlib/tests/blackbox/test_tags.py (+1/-9)
bzrlib/tests/blackbox/test_upgrade.py (+11/-10)
bzrlib/tests/blackbox/test_whoami.py (+5/-4)
bzrlib/tests/per_branch/test_check.py (+3/-1)
bzrlib/tests/test_plugins.py (+10/-25)
bzrlib/trace.py (+39/-86)
bzrlib/transport/ssh.py (+1/-1)
bzrlib/ui/__init__.py (+4/-0)
bzrlib/ui/text.py (+15/-11)
doc/developers/index.txt (+1/-0)
doc/developers/user-interaction.txt (+62/-0)
To merge this branch: bzr merge lp:~mbp/bzr/remove-logging
Reviewer Review Type Date Requested Status
John A Meinel Needs Information
Michael Hudson-Doyle Pending
Review via email: mp+14942@code.launchpad.net

This proposal has been superseded by a proposal from 2009-11-27.

To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote :

This removes bzr's use of the Python logging module. Now all output either goes through bzrlib.trace to the log file (for developer-oriented information) or through Command.outf or UIFactory to the user (for regular interaction.)

This may slightly improve startup time (or enable improving it); more importantly it reduces the proliferation of different methods so that they're easier to debug and test. (Exhibit A, the diff to test_plugins, removing about 20 lines of overhead.)

This deprecates some APIs, but shouldn't break callers unless they're relying on bzrlib writing to logging. (Launchpad might?) But since we never did that very consistently, they're probably better off changing.

* Add some developer documentation about how things are meant to work - previously discussed on the list on "[rfc] developer documentation on user interaction"

* As a side-effect this causes more notice-type messages to go to stderr.

* Remove some unused test support related to logging.

* There were multiple names for equivalent methods in trace.py - some are now deprecated.

* trace.py sends user-oriented messages to the UIFactory.

Also some drive-by fixes while testing this:

* Delete test that was redundant with UpgradeRecommendedTests.

* Update some old tests from before tags were supported by default.

lp:~mbp/bzr/remove-logging updated
4804. By Canonical.com Patch Queue Manager <email address hidden>

(mbp, trivial) further consistency of sphinx in Japanese

4805. By Canonical.com Patch Queue Manager <email address hidden>

(mbp) really fix Japanese sphinx

Revision history for this message
John A Meinel (jameinel) wrote :
Download full text (3.5 KiB)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Martin Pool wrote:
> Martin Pool has proposed merging lp:~mbp/bzr/remove-logging into lp:bzr.
>
> Requested reviews:
> Michael Hudson (mwhudson):
> bzr-core (bzr-core)
>
>
> This removes bzr's use of the Python logging module. Now all output either goes through bzrlib.trace to the log file (for developer-oriented information) or through Command.outf or UIFactory to the user (for regular interaction.)
>
> This may slightly improve startup time (or enable improving it); more importantly it reduces the proliferation of different methods so that they're easier to debug and test. (Exhibit A, the diff to test_plugins, removing about 20 lines of overhead.)
>
> This deprecates some APIs, but shouldn't break callers unless they're relying on bzrlib writing to logging. (Launchpad might?) But since we never did that very consistently, they're probably better off changing.
>
> * Add some developer documentation about how things are meant to work - previously discussed on the list on "[rfc] developer documentation on user interaction"
>
> * As a side-effect this causes more notice-type messages to go to stderr.
>
> * Remove some unused test support related to logging.
>
> * There were multiple names for equivalent methods in trace.py - some are now deprecated.
>
> * trace.py sends user-oriented messages to the UIFactory.
>
> Also some drive-by fixes while testing this:
>
> * Delete test that was redundant with UpgradeRecommendedTests.
>
> * Update some old tests from before tags were supported by default.
>

=== modified file 'Makefile'
- --- Makefile 2009-11-16 19:21:51 +0000
+++ Makefile 2009-11-17 08:05:40 +0000
@@ -39,7 +39,7 @@
 check: docs check-nodocs

 check-nodocs: extensions
- - $(PYTHON) -Werror -O ./bzr selftest -1v $(tests)
+ $(PYTHON) -Werror -O ./bzr selftest -1 --subunit $(tests)

^- This wasn't mentioned. Are we officially switching back? Doesn't the
pipeline need to be updated since "selftest --subunit" will no longer
return a non-0 return code? (At least from my understanding of the
conversation, Robert said you need the failure to be determined from the
later processing stages.)

Also, if we are switching to --subunit, I think it is reasonable to get
rid of -1. As you can easily parse the subunit output to just get the
failures, which means in 1 round trip you can fix everything that failed.

...

=== modified file 'NEWS'
- --- NEWS 2009-11-17 04:03:45 +0000
+++ NEWS 2009-11-17 08:05:40 +0000
@@ -418,6 +418,9 @@
 * PreviewTree behaves correctly when get_file_mtime is invoked on an
unmodified
   file. (Aaron Bentley, #251532)

+* PreviewTree behaves correctly when get_file_mtime is invoked on an
unmodified
+ file. (Aaron Bentley, #251532)
+
 * Registry objects should not use iteritems() when asked to use items().
   (Vincent Ladeuil, #430510)

^- Something doesn't look right here...

In general, all the NEWS items seem a bit confused. Are they just going
into the wrong section? (Unfortunately NEWS means you can't really use
'daggy' fixes, because then the merge into NEWS is always wrong, as it
has to be done with the "latest" version.)

Looking further, the...

Read more...

review: Needs Information
Revision history for this message
Robert Collins (lifeless) wrote :

On Tue, 2009-11-17 at 15:27 +0000, John A Meinel wrote:
>
> check-nodocs: extensions
> - $(PYTHON) -Werror -O ./bzr selftest -1v $(tests)
> + $(PYTHON) -Werror -O ./bzr selftest -1 --subunit $(tests)

I'd do
    $(PYTHON) -Werror -O ./bzr selftest --subunit $(tests) | tee
tests.log && subunit-stats < tests.log || false

This should be robust, deal with bzr failing to start altogether as well
as individual test errors.

> ^- This wasn't mentioned. Are we officially switching back? Doesn't
> the
> pipeline need to be updated since "selftest --subunit" will no longer
> return a non-0 return code? (At least from my understanding of the
> conversation, Robert said you need the failure to be determined from
> the
> later processing stages.)
>
> Also, if we are switching to --subunit, I think it is reasonable to
> get
> rid of -1. As you can easily parse the subunit output to just get the
> failures, which means in 1 round trip you can fix everything that
> failed.

Yup. /me likes.

-Rob

lp:~mbp/bzr/remove-logging updated
4806. By Canonical.com Patch Queue Manager <email address hidden>

(jam, Martin gz) More win32 fixes.

Revision history for this message
Martin Pool (mbp) wrote :

I think I have some kind of merge problem with this submission, or
perhaps I committed more than I intended to.

lp:~mbp/bzr/remove-logging updated
4807. By Canonical.com Patch Queue Manager <email address hidden>

(mbp, trivial) additional doc building fix

4808. By Canonical.com Patch Queue Manager <email address hidden>

(vila) pycurl can't always connect direct to 'localhost' because of
 IPv4/v6 changes.

4809. By Canonical.com Patch Queue Manager <email address hidden>

(Martin <gzlist>) Allow specifying path in 'BZR_SSH' rather than just
 vendors.

4810. By Canonical.com Patch Queue Manager <email address hidden>

(jam) Last few tweaks to get the win32 test suite to pass.

4811. By Canonical.com Patch Queue Manager <email address hidden>

(Andrew Bennetts) Add 'Bazaar Contribution in Five Minutes'
 introduction to developer docs.

4812. By Canonical.com Patch Queue Manager <email address hidden>

(Alexander Sack) Add --commit-time option to 'bzr commit'. (#459276)

4813. By Canonical.com Patch Queue Manager <email address hidden>

(jam) Remove a @needs_read_lock decorator from something that doesn't
 really need it.

4814. By Canonical.com Patch Queue Manager <email address hidden>

(jam) Release the gil during some of the core groupcompress code
 paths.

4815. By Canonical.com Patch Queue Manager <email address hidden>

(jam) Fix CommitBuilder.inv_sha1 when using record_iter_changes.

4816. By Canonical.com Patch Queue Manager <email address hidden>

(igc) Explain that .bzrignore is implicitly added (Patrick Regan,
 #59608)

4817. By Canonical.com Patch Queue Manager <email address hidden>

(igc) Trivial formatting fix to merge help

4818. By Canonical.com Patch Queue Manager <email address hidden>

(jam) Add a developer doc describing dependencies for win32 builds

4819. By Canonical.com Patch Queue Manager <email address hidden>

(jam) Fix bug #485771,
 only change slashes on arguments that are being globbed.

4820. By Canonical.com Patch Queue Manager <email address hidden>

(igc) better explanation of diff -c (#475451)

4821. By Canonical.com Patch Queue Manager <email address hidden>

(vila) Further clarifications on building releases

4822. By Canonical.com Patch Queue Manager <email address hidden>

* TestCaseWithMemoryTransport no longer sets $HOME and $BZR_HOME to
 unicode strings. (Michael Hudson, #464174)

4823. By Canonical.com Patch Queue Manager <email address hidden>

(robertc) Fix parallel selftest with subprocesses - needed for win32.
 (Gordon Tyler)

4824. By Canonical.com Patch Queue Manager <email address hidden>

(robertc) Be more clear in the help for bzr serve about the
 --allow-writes option. (Robert Collins)

4825. By Canonical.com Patch Queue Manager <email address hidden>

(andrew) Terminate ssh subprocesses when no references to them
 remain. (#426662)

4826. By Canonical.com Patch Queue Manager <email address hidden>

(robertc) Documentation fixes. (Neil Martinsen-Burrell, bugs 249919,
 358821, 486892).

4827. By Canonical.com Patch Queue Manager <email address hidden>

(robertc) Fix handling of -Derror for ValueError. (Benoit PIERRE)

4828. By Canonical.com Patch Queue Manager <email address hidden>

(mbp) remove bzrlib.textui

4829. By Canonical.com Patch Queue Manager <email address hidden>

(robertc) Doc improvements for bzr help urlspec. (Neil
 Martinsen-Burrell)

4830. By Canonical.com Patch Queue Manager <email address hidden>

bzrlib.urlutils.local_path_from_url now accepts file://localhost/ as
 well as file:/// URLs on POSIX. (Michael Hudson)

4831. By Canonical.com Patch Queue Manager <email address hidden>

(bialix) Shelve command refuse to run if there is no real terminal

4832. By Martin Pool

Add user interaction architecture doc

4833. By Martin Pool

Tags can be tested in the default format now

4834. By Martin Pool

Document bzrlib.tests.TestUIFactory

4835. By Martin Pool

Remove use of python logging, and show errors through UIFactory instead.

As a side effect, this sends some error-type messages to stderr instead of
stdout.

Remove obsolete bzrlib.tests.TestUtil.LogCollector and makeCollectingLogger.

4836. By Martin Pool

Cope when sys.exitfunc doesn't exist

4837. By Martin Pool

Remove redundant 'warning' prefix from some messages

4838. By Martin Pool

Correction to error handling test that depended on python logging behaviour

Unmerged revisions

4838. By Martin Pool

Correction to error handling test that depended on python logging behaviour

4837. By Martin Pool

Remove redundant 'warning' prefix from some messages

4836. By Martin Pool

Cope when sys.exitfunc doesn't exist

4835. By Martin Pool

Remove use of python logging, and show errors through UIFactory instead.

As a side effect, this sends some error-type messages to stderr instead of
stdout.

Remove obsolete bzrlib.tests.TestUtil.LogCollector and makeCollectingLogger.

4834. By Martin Pool

Document bzrlib.tests.TestUIFactory

4833. By Martin Pool

Tags can be tested in the default format now

4832. By Martin Pool

Add user interaction architecture doc

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2009-11-26 17:23:54 +0000
+++ NEWS 2009-11-27 05:14:10 +0000
@@ -14,6 +14,10 @@
14Compatibility Breaks14Compatibility Breaks
15********************15********************
1616
17* Some messages that were previously sent to stdout now go to stderr, as
18 part of making handling of such things more consistent across bzr.
19 (Martin Pool)
20
17* The BZR_SSH environmental variable may now be set to the path of a secure21* The BZR_SSH environmental variable may now be set to the path of a secure
18 shell client. If currently set to the value ``ssh`` it will now guess the22 shell client. If currently set to the value ``ssh`` it will now guess the
19 vendor of the program with that name, to restore the old behaviour that23 vendor of the program with that name, to restore the old behaviour that
@@ -40,6 +44,9 @@
40* ``bzr serve`` is more clear about the risk of supplying --allow-writes.44* ``bzr serve`` is more clear about the risk of supplying --allow-writes.
41 (Robert Collins, #84659)45 (Robert Collins, #84659)
4246
47* Cope if sys.exitfunc doesn't exist because no exitfuncs have been
48 registered. (Martin Pool)
49
43* Lots of bugfixes for the test suite on Windows. We should once again50* Lots of bugfixes for the test suite on Windows. We should once again
44 have a test suite with no failures on Windows. (John Arbash Meinel)51 have a test suite with no failures on Windows. (John Arbash Meinel)
4552
@@ -64,6 +71,9 @@
64API Changes71API Changes
65***********72***********
6673
74* bzrlib no longer uses ``logging`` for messages, just its own UIFactory.
75 (Martin Pool)
76
67* ``bzrlib.textui`` (vestigial module) removed. (Martin Pool)77* ``bzrlib.textui`` (vestigial module) removed. (Martin Pool)
6878
69Internals79Internals
@@ -513,6 +523,13 @@
513 ``diff.get_trees_and_branches_to_diff``. It is now a public API, and it 523 ``diff.get_trees_and_branches_to_diff``. It is now a public API, and it
514 returns the old and new branches. (Gary van der Merwe)524 returns the old and new branches. (Gary van der Merwe)
515525
526* ``bzrlib.tests.TestUtil.LogCollector`` and ``makeCollectingLogger``
527 have been deleted. bzrlib no longer uses ``logging`` so tests should
528 examine output using a UIFactory or ``run_bzr``. (Martin Pool)
529
530* ``TextUIFactory`` constructor parameters providing file handles are now
531 mandatory. (Martin Pool)
532
516* ``bzrlib.trace.log_error``, ``error`` and ``info`` have been deprecated.533* ``bzrlib.trace.log_error``, ``error`` and ``info`` have been deprecated.
517 (Martin Pool)534 (Martin Pool)
518535
519536
=== modified file 'bzr'
--- bzr 2009-10-30 16:13:05 +0000
+++ bzr 2009-11-27 05:14:10 +0000
@@ -144,9 +144,14 @@
144 if profiling:144 if profiling:
145 profile_imports.log_stack_info(sys.stderr)145 profile_imports.log_stack_info(sys.stderr)
146146
147 # run anything registered by atexit, because it won't be run in the normal147 # Run anything registered by atexit, because it won't be run in the normal
148 # way148 # way; note that this interface is deprecated and only going to be present
149 sys.exitfunc()149 # if somebody has already registered something. We could alternatively
150 # use atexit._run_exitfuncs but that's undocumented and requires loading
151 # another module. -- mbp 200911127
152 exitfunc = getattr(sys, 'exitfunc', None)
153 if exitfunc:
154 exitfunc()
150155
151 # By this point we really have completed everything we want to do, and156 # By this point we really have completed everything we want to do, and
152 # there's no point doing any additional cleanup. Abruptly exiting here157 # there's no point doing any additional cleanup. Abruptly exiting here
153158
=== modified file 'bzrlib/cleanup.py'
--- bzrlib/cleanup.py 2009-10-26 06:23:14 +0000
+++ bzrlib/cleanup.py 2009-11-27 05:14:10 +0000
@@ -53,7 +53,7 @@
53 trace.mutter('Cleanup failed:')53 trace.mutter('Cleanup failed:')
54 trace.log_exception_quietly()54 trace.log_exception_quietly()
55 if 'cleanup' in debug.debug_flags:55 if 'cleanup' in debug.debug_flags:
56 trace.warning('bzr: warning: Cleanup failed: %s', exc)56 trace.warning('Cleanup failed: %s', exc)
5757
5858
59def _run_cleanup(func, *args, **kwargs):59def _run_cleanup(func, *args, **kwargs):
6060
=== modified file 'bzrlib/osutils.py'
--- bzrlib/osutils.py 2009-11-10 07:01:56 +0000
+++ bzrlib/osutils.py 2009-11-27 05:14:10 +0000
@@ -929,7 +929,7 @@
929 # the warnings framework should by default show this only once929 # the warnings framework should by default show this only once
930 from bzrlib.trace import warning930 from bzrlib.trace import warning
931 warning(931 warning(
932 "bzr: warning: some compiled extensions could not be loaded; "932 "some compiled extensions could not be loaded; "
933 "see <https://answers.launchpad.net/bzr/+faq/703>")933 "see <https://answers.launchpad.net/bzr/+faq/703>")
934 # we no longer show the specific missing extensions here, because it makes934 # we no longer show the specific missing extensions here, because it makes
935 # the message too long and scary - see935 # the message too long and scary - see
936936
=== modified file 'bzrlib/status.py'
--- bzrlib/status.py 2009-08-06 05:07:12 +0000
+++ bzrlib/status.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005, 2006, 2007 Canonical Ltd1# Copyright (C) 2005, 2006, 2007, 2009 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
20 delta as _mod_delta,20 delta as _mod_delta,
21 log,21 log,
22 osutils,22 osutils,
23 trace,
23 tree,24 tree,
24 tsort,25 tsort,
25 revision as _mod_revision,26 revision as _mod_revision,
@@ -28,10 +29,7 @@
28from bzrlib.osutils import is_inside_any29from bzrlib.osutils import is_inside_any
29from bzrlib.symbol_versioning import (deprecated_function,30from bzrlib.symbol_versioning import (deprecated_function,
30 )31 )
31from bzrlib.trace import mutter, warning32from bzrlib.trace import mutter
32
33# TODO: when showing single-line logs, truncate to the width of the terminal
34# if known, but only if really going to the terminal (not into a file)
3533
3634
37def show_tree_status(wt, show_unchanged=None,35def show_tree_status(wt, show_unchanged=None,
@@ -84,7 +82,7 @@
84 new_is_working_tree = True82 new_is_working_tree = True
85 if revision is None:83 if revision is None:
86 if wt.last_revision() != wt.branch.last_revision():84 if wt.last_revision() != wt.branch.last_revision():
87 warning("working tree is out of date, run 'bzr update'")85 trace.note("working tree is out of date, run 'bzr update'")
88 new = wt86 new = wt
89 old = new.basis_tree()87 old = new.basis_tree()
90 elif len(revision) > 0:88 elif len(revision) > 0:
9189
=== modified file 'bzrlib/tests/TestUtil.py'
--- bzrlib/tests/TestUtil.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/TestUtil.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2004, 2005, 2006 Canonical Ltd1# Copyright (C) 2004, 2005, 2006, 2009 Canonical Ltd
2# Author: Robert Collins <robert.collins@canonical.com>2# Author: Robert Collins <robert.collins@canonical.com>
3#3#
4# This program is free software; you can redistribute it and/or modify4# This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,6 @@
17#17#
1818
19import sys19import sys
20import logging
21import unittest20import unittest
2221
23# Mark this python module as being part of the implementation22# Mark this python module as being part of the implementation
@@ -26,24 +25,6 @@
26__unittest = 125__unittest = 1
2726
2827
29class LogCollector(logging.Handler):
30 def __init__(self):
31 logging.Handler.__init__(self)
32 self.records=[]
33 def emit(self, record):
34 self.records.append(record.getMessage())
35
36
37def makeCollectingLogger():
38 """I make a logger instance that collects its logs for programmatic analysis
39 -> (logger, collector)"""
40 logger=logging.Logger("collector")
41 handler=LogCollector()
42 handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
43 logger.addHandler(handler)
44 return logger, handler
45
46
47def visitTests(suite, visitor):28def visitTests(suite, visitor):
48 """A foreign method for visiting the tests in a test suite."""29 """A foreign method for visiting the tests in a test suite."""
49 for test in suite._tests:30 for test in suite._tests:
5031
=== modified file 'bzrlib/tests/__init__.py'
--- bzrlib/tests/__init__.py 2009-11-24 08:28:41 +0000
+++ bzrlib/tests/__init__.py 2009-11-27 05:14:10 +0000
@@ -1880,8 +1880,7 @@
1880 overall behavior of the bzr application (rather than a unit test1880 overall behavior of the bzr application (rather than a unit test
1881 or a functional test of the library.)1881 or a functional test of the library.)
18821882
1883 This sends the stdout/stderr results into the test's log,1883 :returns: (out, err) tuple of strings of output.
1884 where it may be useful for debugging. See also run_captured.
18851884
1886 :keyword stdin: A string to be used as stdin for the command.1885 :keyword stdin: A string to be used as stdin for the command.
1887 :keyword retcode: The status code the command should return;1886 :keyword retcode: The status code the command should return;
18881887
=== modified file 'bzrlib/tests/blackbox/test_exceptions.py'
--- bzrlib/tests/blackbox/test_exceptions.py 2009-08-20 06:25:02 +0000
+++ bzrlib/tests/blackbox/test_exceptions.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006, 2007 Canonical Ltd1# Copyright (C) 2006, 2007, 2009 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -43,20 +43,3 @@
43 self.assertContainsRe(err,43 self.assertContainsRe(err,
44 r'exceptions\.AssertionError: always fails\n')44 r'exceptions\.AssertionError: always fails\n')
45 self.assertContainsRe(err, r'Bazaar has encountered an internal error')45 self.assertContainsRe(err, r'Bazaar has encountered an internal error')
46
47
48class TestDeprecationWarning(TestCaseInTempDir):
49
50 def test_repository_deprecation_warning(self):
51 """Old formats give a warning"""
52 # the warning's normally off for testing but we reenable it
53 repository._deprecation_warning_done = False
54 try:
55 os.mkdir('foo')
56 bzrdir.BzrDirFormat5().initialize('foo')
57 out, err = self.run_bzr("status foo")
58 self.assertContainsRe(self._get_log(keep_log_file=True),
59 "bzr upgrade")
60 finally:
61 repository._deprecation_warning_done = True
62
6346
=== modified file 'bzrlib/tests/blackbox/test_reconcile.py'
--- bzrlib/tests/blackbox/test_reconcile.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/blackbox/test_reconcile.py 2009-11-27 05:14:10 +0000
@@ -46,7 +46,7 @@
46 does_backup_text = "Inventory ok.\n"46 does_backup_text = "Inventory ok.\n"
47 else:47 else:
48 does_backup_text = ""48 does_backup_text = ""
49 self.assertEqualDiff(out, "Reconciling branch %s\n"49 self.assertEqualDiff(err, "Reconciling branch %s\n"
50 "revision_history ok.\n"50 "revision_history ok.\n"
51 "Reconciling repository %s\n"51 "Reconciling repository %s\n"
52 "%s"52 "%s"
@@ -54,7 +54,7 @@
54 (t.branch.base,54 (t.branch.base,
55 t.bzrdir.root_transport.base,55 t.bzrdir.root_transport.base,
56 does_backup_text))56 does_backup_text))
57 self.assertEqualDiff(err, "")57 self.assertEqualDiff(out, "")
5858
59 def test_does_something_reconcile(self):59 def test_does_something_reconcile(self):
60 t = bzrdir.BzrDir.create_standalone_workingtree('.')60 t = bzrdir.BzrDir.create_standalone_workingtree('.')
@@ -82,5 +82,5 @@
82 (t.branch.base,82 (t.branch.base,
83 t.bzrdir.root_transport.base,83 t.bzrdir.root_transport.base,
84 does_backup_text))84 does_backup_text))
85 self.assertEqualDiff(expected, out)85 self.assertEqualDiff(expected, err)
86 self.assertEqualDiff(err, "")86 self.assertEqualDiff("", out)
8787
=== modified file 'bzrlib/tests/blackbox/test_reconfigure.py'
--- bzrlib/tests/blackbox/test_reconfigure.py 2009-07-10 08:18:28 +0000
+++ bzrlib/tests/blackbox/test_reconfigure.py 2009-11-27 05:14:10 +0000
@@ -211,16 +211,16 @@
211 branch_2 = tree_2.branch211 branch_2 = tree_2.branch
212 # now reconfigure to be stacked212 # now reconfigure to be stacked
213 out, err = self.run_bzr('reconfigure --stacked-on b1 b2')213 out, err = self.run_bzr('reconfigure --stacked-on b1 b2')
214 self.assertContainsRe(out,214 self.assertContainsRe(err,
215 '^.*/b2/ is now stacked on ../b1\n$')215 '^.*/b2/ is now stacked on ../b1\n$')
216 self.assertEquals('', err)216 self.assertEquals('', out)
217 # can also give the absolute URL of the branch, and it gets stored 217 # can also give the absolute URL of the branch, and it gets stored
218 # as a relative path if possible218 # as a relative path if possible
219 out, err = self.run_bzr('reconfigure --stacked-on %s b2'219 out, err = self.run_bzr('reconfigure --stacked-on %s b2'
220 % (self.get_url('b1'),))220 % (self.get_url('b1'),))
221 self.assertContainsRe(out,221 self.assertContainsRe(err,
222 '^.*/b2/ is now stacked on ../b1\n$')222 '^.*/b2/ is now stacked on ../b1\n$')
223 self.assertEquals('', err)223 self.assertEquals('', out)
224 # It should be given a relative URL to the destination, if possible,224 # It should be given a relative URL to the destination, if possible,
225 # because that's most likely to work across different transports225 # because that's most likely to work across different transports
226 self.assertEquals(branch_2.get_stacked_on_url(),226 self.assertEquals(branch_2.get_stacked_on_url(),
@@ -230,9 +230,9 @@
230 tree_2.commit('update foo')230 tree_2.commit('update foo')
231 # Now turn it off again231 # Now turn it off again
232 out, err = self.run_bzr('reconfigure --unstacked b2')232 out, err = self.run_bzr('reconfigure --unstacked b2')
233 self.assertContainsRe(out,233 self.assertContainsRe(err,
234 '^.*/b2/ is now not stacked\n$')234 '^.*/b2/ is now not stacked\n$')
235 self.assertEquals('', err)235 self.assertEquals('', out)
236 self.assertRaises(errors.NotStacked,236 self.assertRaises(errors.NotStacked,
237 branch_2.get_stacked_on_url)237 branch_2.get_stacked_on_url)
238238
239239
=== modified file 'bzrlib/tests/blackbox/test_tags.py'
--- bzrlib/tests/blackbox/test_tags.py 2009-08-20 04:09:58 +0000
+++ bzrlib/tests/blackbox/test_tags.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2007 Canonical Ltd1# Copyright (C) 2007, 2009 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -30,14 +30,6 @@
3030
31class TestTagging(TestCaseWithTransport):31class TestTagging(TestCaseWithTransport):
3232
33 # as of 0.14, the default format doesn't do tags so we need to use a
34 # specific format
35
36 def make_branch_and_tree(self, relpath):
37 format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
38 return TestCaseWithTransport.make_branch_and_tree(self, relpath,
39 format=format)
40
41 def test_tag_command_help(self):33 def test_tag_command_help(self):
42 out, err = self.run_bzr('help tag')34 out, err = self.run_bzr('help tag')
43 self.assertContainsRe(out, 'Create, remove or modify a tag')35 self.assertContainsRe(out, 'Create, remove or modify a tag')
4436
=== modified file 'bzrlib/tests/blackbox/test_upgrade.py'
--- bzrlib/tests/blackbox/test_upgrade.py 2009-08-21 02:10:06 +0000
+++ bzrlib/tests/blackbox/test_upgrade.py 2009-11-27 05:14:10 +0000
@@ -86,11 +86,12 @@
86 (out, err) = self.run_bzr('upgrade current_format_checkout', retcode=3)86 (out, err) = self.run_bzr('upgrade current_format_checkout', retcode=3)
87 self.assertEqual("This is a checkout. The branch (%s) needs to be "87 self.assertEqual("This is a checkout. The branch (%s) needs to be "
88 "upgraded separately.\n"88 "upgraded separately.\n"
89 "bzr: ERROR: The branch format Meta "
90 "directory format 1 is already at the most "
91 "recent format.\n"
89 % get_transport(self.get_url('current_format_branch')).base,92 % get_transport(self.get_url('current_format_branch')).base,
90 out)93 err)
91 self.assertEqualDiff("bzr: ERROR: The branch format Meta "94 self.assertEqualDiff('', out)
92 "directory format 1 is already at the most "
93 "recent format.\n", err)
9495
95 def test_upgrade_checkout(self):96 def test_upgrade_checkout(self):
96 # upgrading a checkout should work97 # upgrading a checkout should work
@@ -121,8 +122,8 @@
121adding prefixes to revision-store122adding prefixes to revision-store
122starting upgrade from format 6 to metadir123starting upgrade from format 6 to metadir
123finished124finished
124""" % (url, url, url), out)125""" % (url, url, url), err)
125 self.assertEqualDiff("", err)126 self.assertEqualDiff("", out)
126 self.assertTrue(isinstance(127 self.assertTrue(isinstance(
127 bzrdir.BzrDir.open(self.get_url('format_5_branch'))._format,128 bzrdir.BzrDir.open(self.get_url('format_5_branch'))._format,
128 bzrdir.BzrDirMetaFormat1))129 bzrdir.BzrDirMetaFormat1))
@@ -142,8 +143,8 @@
142starting repository conversion143starting repository conversion
143repository converted144repository converted
144finished145finished
145""" % (url, url, url), out)146""" % (url, url, url), err)
146 self.assertEqualDiff("", err)147 self.assertEqualDiff("", out)
147 converted_dir = bzrdir.BzrDir.open(self.get_url('metadir_weave_branch'))148 converted_dir = bzrdir.BzrDir.open(self.get_url('metadir_weave_branch'))
148 self.assertTrue(isinstance(converted_dir._format,149 self.assertTrue(isinstance(converted_dir._format,
149 bzrdir.BzrDirMetaFormat1))150 bzrdir.BzrDirMetaFormat1))
@@ -180,8 +181,8 @@
180starting repository conversion181starting repository conversion
181repository converted182repository converted
182finished183finished
183""" % (url, url, url), out)184""" % (url, url, url), err)
184 self.assertEqual('', err)185 self.assertEqual('', out)
185186
186187
187class UpgradeRecommendedTests(TestCaseWithTransport):188class UpgradeRecommendedTests(TestCaseWithTransport):
188189
=== modified file 'bzrlib/tests/blackbox/test_whoami.py'
--- bzrlib/tests/blackbox/test_whoami.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/blackbox/test_whoami.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2006 Canonical Ltd1# Copyright (C) 2006, 2009 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -108,6 +108,7 @@
108 """verify that a warning is displayed if no email is given."""108 """verify that a warning is displayed if no email is given."""
109 self.make_branch_and_tree('.')109 self.make_branch_and_tree('.')
110 display = self.run_bzr(['whoami', 'Branch Identity'])[1]110 display = self.run_bzr(['whoami', 'Branch Identity'])[1]
111 self.assertEquals('"Branch Identity" does not seem to contain an '111 self.assertEquals('bzr: warning: '
112 'email address. This is allowed, but not '112 '"Branch Identity" does not seem to contain an '
113 'recommended.\n', display)113 'email address. This is allowed, but not '
114 'recommended.\n', display)
114115
=== modified file 'bzrlib/tests/per_branch/test_check.py'
--- bzrlib/tests/per_branch/test_check.py 2009-08-04 04:36:34 +0000
+++ bzrlib/tests/per_branch/test_check.py 2009-11-27 05:14:10 +0000
@@ -60,7 +60,9 @@
60 self.addCleanup(tree.unlock)60 self.addCleanup(tree.unlock)
61 refs = self.make_refs(tree.branch)61 refs = self.make_refs(tree.branch)
62 result = tree.branch.check(refs)62 result = tree.branch.check(refs)
63 ui.ui_factory = tests.TestUIFactory(stdout=StringIO())63 ui.ui_factory = tests.TestUIFactory(stdin='',
64 stdout=StringIO(),
65 stderr=StringIO())
64 result.report_results(True)66 result.report_results(True)
65 self.assertContainsRe('revno does not match len',67 self.assertContainsRe('revno does not match len',
66 ui.ui_factory.stdout.getvalue())68 ui.ui_factory.stdout.getvalue())
6769
=== modified file 'bzrlib/tests/test_plugins.py'
--- bzrlib/tests/test_plugins.py 2009-09-18 14:53:37 +0000
+++ bzrlib/tests/test_plugins.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005, 2007 Canonical Ltd1# Copyright (C) 2005, 2007, 2009 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -16,11 +16,6 @@
1616
17"""Tests for plugins"""17"""Tests for plugins"""
1818
19# XXX: There are no plugin tests at the moment because the plugin module
20# affects the global state of the process. See bzrlib/plugins.py for more
21# comments.
22
23import logging
24import os19import os
25from StringIO import StringIO20from StringIO import StringIO
26import sys21import sys
@@ -30,6 +25,7 @@
30 osutils,25 osutils,
31 plugin,26 plugin,
32 tests,27 tests,
28 ui,
33 )29 )
34import bzrlib.plugin30import bzrlib.plugin
35import bzrlib.plugins31import bzrlib.plugins
@@ -202,28 +198,17 @@
202 :param name: The name of the plugin.198 :param name: The name of the plugin.
203 :return: A string with the log from the plugin loading call.199 :return: A string with the log from the plugin loading call.
204 """200 """
205 # Capture output
206 stream = StringIO()201 stream = StringIO()
202 ui.ui_factory = tests.TestUIFactory(stdout=stream, stderr=stream,
203 stdin=None)
207 try:204 try:
208 handler = logging.StreamHandler(stream)205 bzrlib.plugin.load_from_path(['.'])
209 log = logging.getLogger('bzr')
210 log.addHandler(handler)
211 try:
212 try:
213 bzrlib.plugin.load_from_path(['.'])
214 finally:
215 if 'bzrlib.plugins.%s' % name in sys.modules:
216 del sys.modules['bzrlib.plugins.%s' % name]
217 if getattr(bzrlib.plugins, name, None):
218 delattr(bzrlib.plugins, name)
219 finally:
220 # Stop capturing output
221 handler.flush()
222 handler.close()
223 log.removeHandler(handler)
224 return stream.getvalue()
225 finally:206 finally:
226 stream.close()207 if 'bzrlib.plugins.%s' % name in sys.modules:
208 del sys.modules['bzrlib.plugins.%s' % name]
209 if getattr(bzrlib.plugins, name, None):
210 delattr(bzrlib.plugins, name)
211 return stream.getvalue()
227212
228 def test_plugin_with_bad_api_version_reports(self):213 def test_plugin_with_bad_api_version_reports(self):
229 # This plugin asks for bzrlib api version 1.0.0, which is not supported214 # This plugin asks for bzrlib api version 1.0.0, which is not supported
230215
=== modified file 'bzrlib/trace.py'
--- bzrlib/trace.py 2009-11-19 20:47:51 +0000
+++ bzrlib/trace.py 2009-11-27 05:14:10 +0000
@@ -1,4 +1,4 @@
1# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd1# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2#2#
3# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -16,16 +16,17 @@
1616
17"""Messages and logging for bazaar-ng.17"""Messages and logging for bazaar-ng.
1818
19The current general approach is that information for the user in normal
20operation should go through the UIFactory, and trace should mostly be used for
21debug and internal error information. However, this is not fully implemented.
22
19Messages are supplied by callers as a string-formatting template, plus values23Messages are supplied by callers as a string-formatting template, plus values
20to be inserted into it. The actual %-formatting is deferred to the log24to be inserted into it. The actual %-formatting is deferred to the log
21library so that it doesn't need to be done for messages that won't be emitted.25library so that it doesn't need to be done for messages that won't be emitted.
2226
23Messages are classified by severity levels: critical, error, warning, info,27They can be sent to two places: to stderr (via the UIFactory), and to
24and debug.28~/.bzr.log. For purposes such as running the test suite, they can also be
2529redirected away from both of those two places to another location.
26They can be sent to two places: to stderr, and to ~/.bzr.log. For purposes
27such as running the test suite, they can also be redirected away from both of
28those two places to another location.
2930
30~/.bzr.log gets all messages, and full tracebacks for uncaught exceptions.31~/.bzr.log gets all messages, and full tracebacks for uncaught exceptions.
31This trace file is always in UTF-8, regardless of the user's default encoding,32This trace file is always in UTF-8, regardless of the user's default encoding,
@@ -46,17 +47,7 @@
46form.47form.
47"""48"""
4849
49# FIXME: Unfortunately it turns out that python's logging module
50# is quite expensive, even when the message is not printed by any handlers.
51# We should perhaps change back to just simply doing it here.
52#
53# On the other hand, as of 1.2 we generally only call the mutter() statement
54# if (according to debug_flags) we actually intend to write it. So the
55# increased cost of logging.py is not so bad, and we could standardize on
56# that.
57
58import codecs50import codecs
59import logging
60import os51import os
61import sys52import sys
62import time53import time
@@ -83,6 +74,8 @@
83 osutils,74 osutils,
84 plugin,75 plugin,
85 symbol_versioning,76 symbol_versioning,
77 trace,
78 ui,
86 )79 )
87""")80""")
8881
@@ -106,43 +99,47 @@
106_bzr_log_start_time = bzrlib._start_time99_bzr_log_start_time = bzrlib._start_time
107100
108101
109# held in a global for quick reference102def _fmt_msg(args, kwargs):
110_bzr_logger = logging.getLogger('bzr')103 # common compatibility code for functions that take dual format string
111104 # arguments; normally we don't want to do this from now on
105 if len(args) > 1:
106 if kwargs:
107 raise ValueError("can't use both args and kwargs: %r, %r"
108 % (args, kwargs))
109 msg = args[0]
110 return msg % args[1:]
111 elif kwargs:
112 return args[0] % kwargs
113 else:
114 # for compatibility we also accept passing objects that are then cast
115 # down
116 return unicode(args[0])
117
112118
113def note(*args, **kwargs):119def note(*args, **kwargs):
114 # FIXME note always emits utf-8, regardless of the terminal encoding120 ui.ui_factory.show_message(_fmt_msg(args, kwargs))
115 #
116 # FIXME: clearing the ui and then going through the abstract logging
117 # framework is whack; we should probably have a logging Handler that
118 # deals with terminal output if needed.
119 import bzrlib.ui
120 bzrlib.ui.ui_factory.clear_term()
121 _bzr_logger.info(*args, **kwargs)
122121
123122
124def warning(*args, **kwargs):123def warning(*args, **kwargs):
125 import bzrlib.ui124 ui.ui_factory.show_warning(_fmt_msg(args, kwargs))
126 bzrlib.ui.ui_factory.clear_term()
127 _bzr_logger.warning(*args, **kwargs)
128125
129126
130@deprecated_function(deprecated_in((2, 1, 0)))127@deprecated_function(deprecated_in((2, 1, 0)))
131def info(*args, **kwargs):128def info(*args, **kwargs):
132 """Deprecated: use trace.note instead."""129 """Deprecated: use trace.note instead."""
133 note(*args, **kwargs)130 ui.ui_factory.show_message(_fmt_msg(args, kwargs))
134131
135132
136@deprecated_function(deprecated_in((2, 1, 0)))133@deprecated_function(deprecated_in((2, 1, 0)))
137def log_error(*args, **kwargs):134def log_error(*args, **kwargs):
138 """Deprecated: use bzrlib.trace.show_error instead"""135 """Deprecated: use bzrlib.trace.show_error instead"""
139 _bzr_logger.error(*args, **kwargs)136 ui.ui_factory.show_error(_fmt_msg(args, kwargs))
140137
141138
142@deprecated_function(deprecated_in((2, 1, 0)))139@deprecated_function(deprecated_in((2, 1, 0)))
143def error(*args, **kwargs):140def error(*args, **kwargs):
144 """Deprecated: use bzrlib.trace.show_error instead"""141 """Deprecated: use bzrlib.trace.show_error instead"""
145 _bzr_logger.error(*args, **kwargs)142 ui.ui_factory.show_error(_fmt_msg(args, kwargs))
146143
147144
148def show_error(msg):145def show_error(msg):
@@ -150,7 +147,7 @@
150147
151 Don't use this for exceptions, use report_exception instead.148 Don't use this for exceptions, use report_exception instead.
152 """149 """
153 _bzr_logger.error(*args, **kwargs)150 ui.ui_factory.show_error(msg)
154151
155152
156_last_mutter_flush_time = None153_last_mutter_flush_time = None
@@ -273,10 +270,7 @@
273 This should only be called once per process.270 This should only be called once per process.
274271
275 Non-command-line programs embedding bzrlib do not need to call this. They272 Non-command-line programs embedding bzrlib do not need to call this. They
276 can instead either pass a file to _push_log_file, or act directly on273 can instead pass a file to _push_log_file.
277 logging.getLogger("bzr").
278
279 Output can be redirected away by calling _push_log_file.
280 """274 """
281 # Do this before we open the log file, so we prevent275 # Do this before we open the log file, so we prevent
282 # get_terminal_encoding() from mutter()ing multiple times276 # get_terminal_encoding() from mutter()ing multiple times
@@ -290,13 +284,6 @@
290 push_log_file(bzr_log_file,284 push_log_file(bzr_log_file,
291 r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s',285 r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s',
292 r'%Y-%m-%d %H:%M:%S')286 r'%Y-%m-%d %H:%M:%S')
293 # after hooking output into bzr_log, we also need to attach a stderr
294 # handler, writing only at level info and with encoding
295 writer_factory = codecs.getwriter(term_encoding)
296 encoded_stderr = writer_factory(sys.stderr, errors='replace')
297 stderr_handler = logging.StreamHandler(encoded_stderr)
298 stderr_handler.setLevel(logging.INFO)
299 logging.getLogger('bzr').addHandler(stderr_handler)
300287
301288
302def push_log_file(to_file, log_format=None, date_format=None):289def push_log_file(to_file, log_format=None, date_format=None):
@@ -305,37 +292,18 @@
305 :param to_file: A file-like object to which messages will be sent.292 :param to_file: A file-like object to which messages will be sent.
306293
307 :returns: A memento that should be passed to _pop_log_file to restore the294 :returns: A memento that should be passed to _pop_log_file to restore the
308 previously active logging.295 previously active logging.
309 """296 """
310 global _trace_file297 global _trace_file
311 # make a new handler
312 new_handler = logging.StreamHandler(to_file)
313 new_handler.setLevel(logging.DEBUG)
314 if log_format is None:
315 log_format = '%(levelname)8s %(message)s'
316 new_handler.setFormatter(logging.Formatter(log_format, date_format))
317 # save and remove any existing log handlers
318 bzr_logger = logging.getLogger('bzr')
319 old_handlers = bzr_logger.handlers[:]
320 del bzr_logger.handlers[:]
321 # set that as the default logger
322 bzr_logger.addHandler(new_handler)
323 bzr_logger.setLevel(logging.DEBUG)
324 # TODO: check if any changes are needed to the root logger
325 #
326 # TODO: also probably need to save and restore the level on bzr_logger.
327 # but maybe we can avoid setting the logger level altogether, and just set
328 # the level on the handler?
329 #
330 # save the old trace file298 # save the old trace file
331 old_trace_file = _trace_file299 old_trace_file = _trace_file
332 # send traces to the new one300 # send traces to the new one
333 _trace_file = to_file301 _trace_file = to_file
334 result = new_handler, _trace_file302 result = _trace_file
335 return ('log_memento', old_handlers, new_handler, old_trace_file, to_file)303 return ('log_memento', old_trace_file, to_file)
336304
337305
338def pop_log_file((magic, old_handlers, new_handler, old_trace_file, new_trace_file)):306def pop_log_file((magic, old_trace_file, new_trace_file)):
339 """Undo changes to logging/tracing done by _push_log_file.307 """Undo changes to logging/tracing done by _push_log_file.
340308
341 This flushes, but does not close the trace file.309 This flushes, but does not close the trace file.
@@ -343,12 +311,6 @@
343 Takes the memento returned from _push_log_file."""311 Takes the memento returned from _push_log_file."""
344 global _trace_file312 global _trace_file
345 _trace_file = old_trace_file313 _trace_file = old_trace_file
346 bzr_logger = logging.getLogger('bzr')
347 bzr_logger.removeHandler(new_handler)
348 # must be closed, otherwise logging will try to close it atexit, and the
349 # file will likely already be closed underneath.
350 new_handler.close()
351 bzr_logger.handlers = old_handlers
352 new_trace_file.flush()314 new_trace_file.flush()
353315
354316
@@ -369,7 +331,6 @@
369 """331 """
370 global _verbosity_level332 global _verbosity_level
371 _verbosity_level = level333 _verbosity_level = level
372 _update_logging_level(level < 0)
373334
374335
375def get_verbosity_level():336def get_verbosity_level():
@@ -388,14 +349,6 @@
388 set_verbosity_level(0)349 set_verbosity_level(0)
389350
390351
391def _update_logging_level(quiet=True):
392 """Hide INFO messages if quiet."""
393 if quiet:
394 _bzr_logger.setLevel(logging.WARNING)
395 else:
396 _bzr_logger.setLevel(logging.INFO)
397
398
399def is_quiet():352def is_quiet():
400 """Is the verbosity level negative?"""353 """Is the verbosity level negative?"""
401 return _verbosity_level < 0354 return _verbosity_level < 0
402355
=== modified file 'bzrlib/transport/ssh.py'
--- bzrlib/transport/ssh.py 2009-11-25 07:27:43 +0000
+++ bzrlib/transport/ssh.py 2009-11-27 05:14:10 +0000
@@ -19,7 +19,6 @@
1919
20import errno20import errno
21import getpass21import getpass
22import logging
23import os22import os
24import socket23import socket
25import subprocess24import subprocess
@@ -500,6 +499,7 @@
500 # auth_none check to see if it is even supported.499 # auth_none check to see if it is even supported.
501 supported_auth_types = []500 supported_auth_types = []
502 try:501 try:
502 import logging
503 # Note that with paramiko <1.7.5 this logs an INFO message:503 # Note that with paramiko <1.7.5 this logs an INFO message:
504 # Authentication type (none) not permitted.504 # Authentication type (none) not permitted.
505 # So we explicitly disable the logging level for this action505 # So we explicitly disable the logging level for this action
506506
=== modified file 'bzrlib/ui/__init__.py'
--- bzrlib/ui/__init__.py 2009-10-15 20:04:37 +0000
+++ bzrlib/ui/__init__.py 2009-11-27 05:14:10 +0000
@@ -39,6 +39,10 @@
39 depending on the detected capabilities of the terminal.39 depending on the detected capabilities of the terminal.
40 GUIs may choose to subclass this so that unimplemented methods fall40 GUIs may choose to subclass this so that unimplemented methods fall
41 back to working through the terminal.41 back to working through the terminal.
42
43bzrlib.tests.TestUIFactory
44 Similar to TextUIFactory, but with no progress bars and some facilities
45 for automated testing.
42"""46"""
4347
4448
4549
=== modified file 'bzrlib/ui/text.py'
--- bzrlib/ui/text.py 2009-09-23 06:29:46 +0000
+++ bzrlib/ui/text.py 2009-11-27 05:14:10 +0000
@@ -18,6 +18,7 @@
18"""Text UI, write output to the console.18"""Text UI, write output to the console.
19"""19"""
2020
21import codecs
21import getpass22import getpass
22import os23import os
23import sys24import sys
@@ -44,18 +45,18 @@
44class TextUIFactory(UIFactory):45class TextUIFactory(UIFactory):
45 """A UI factory for Text user interefaces."""46 """A UI factory for Text user interefaces."""
4647
47 def __init__(self,48 def __init__(self, stdin, stdout, stderr):
48 stdin=None,
49 stdout=None,
50 stderr=None):
51 """Create a TextUIFactory.49 """Create a TextUIFactory.
52 """50 """
53 super(TextUIFactory, self).__init__()51 super(TextUIFactory, self).__init__()
54 # TODO: there's no good reason not to pass all three streams, maybe we
55 # should deprecate the default values...
56 self.stdin = stdin52 self.stdin = stdin
57 self.stdout = stdout53 self.stdout = stdout
58 self.stderr = stderr54 self.stderr = stderr
55 # encoding_stderr is used for data put into the terminal encoding with
56 # unrepresentable messages replaced; it should be used for non-bulk
57 # messages
58 self.message_stream = codecs.getwriter(osutils.get_terminal_encoding())(
59 self.stderr, errors='replace')
59 # paints progress, network activity, etc60 # paints progress, network activity, etc
60 self._progress_view = self.make_progress_view()61 self._progress_view = self.make_progress_view()
61 62
@@ -149,7 +150,9 @@
149 def note(self, msg):150 def note(self, msg):
150 """Write an already-formatted message, clearing the progress bar if necessary."""151 """Write an already-formatted message, clearing the progress bar if necessary."""
151 self.clear_term()152 self.clear_term()
152 self.stdout.write(msg + '\n')153 self.message_stream.write(unicode(msg) + '\n')
154 # XXX: At the moment this accepts string-able objects, but we should
155 # deprecate that and make the caller pass unicode.
153156
154 def prompt(self, prompt, **kwargs):157 def prompt(self, prompt, **kwargs):
155 """Emit prompt on the CLI.158 """Emit prompt on the CLI.
@@ -162,7 +165,7 @@
162 prompt = prompt % kwargs165 prompt = prompt % kwargs
163 prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace')166 prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace')
164 self.clear_term()167 self.clear_term()
165 self.stderr.write(prompt)168 self.message_stream.write(prompt)
166169
167 def report_transport_activity(self, transport, byte_count, direction):170 def report_transport_activity(self, transport, byte_count, direction):
168 """Called by transports as they do IO.171 """Called by transports as they do IO.
@@ -175,14 +178,15 @@
175178
176 def show_error(self, msg):179 def show_error(self, msg):
177 self.clear_term()180 self.clear_term()
178 self.stderr.write("bzr: error: %s\n" % msg)181 self.message_stream.write("bzr: error: %s\n" % msg)
179182
180 def show_message(self, msg):183 def show_message(self, msg):
181 self.note(msg)184 self.clear_term()
185 self.message_stream.write(unicode(msg) + '\n')
182186
183 def show_warning(self, msg):187 def show_warning(self, msg):
184 self.clear_term()188 self.clear_term()
185 self.stderr.write("bzr: warning: %s\n" % msg)189 self.message_stream.write("bzr: warning: %s\n" % msg)
186190
187 def _progress_updated(self, task):191 def _progress_updated(self, task):
188 """A task has been updated and wants to be displayed.192 """A task has been updated and wants to be displayed.
189193
=== modified file 'doc/developers/index.txt'
--- doc/developers/index.txt 2009-11-18 02:09:01 +0000
+++ doc/developers/index.txt 2009-11-27 05:14:10 +0000
@@ -33,6 +33,7 @@
3333
34 overview34 overview
35 integration35 integration
36 user-interaction
3637
37* `Writing plugins for Bazaar <http://bazaar-vcs.org/WritingPlugins>`_ (web link) 38* `Writing plugins for Bazaar <http://bazaar-vcs.org/WritingPlugins>`_ (web link)
3839
3940
=== added file 'doc/developers/user-interaction.txt'
--- doc/developers/user-interaction.txt 1970-01-01 00:00:00 +0000
+++ doc/developers/user-interaction.txt 2009-11-27 05:14:10 +0000
@@ -0,0 +1,62 @@
1************************************
2Bazaar User Interaction Architecture
3************************************
4
5Bazaar aims to provide a library that can be mated to various text and
6graphical user interfaces, and that can be used when there is no user to
7interact with. This document describes some patterns and standards to
8abstract this. It's a work in progress and not all code follows this
9standard yet.
10
11Most interaction with the user goes through a ``UIFactory`` subclass bound
12to the global variable ``bzrlib.ui.ui_factory``. Through this you can
13display messages and ask for input. Data between the UIFactory and the
14rest of the library should generally be Unicode, with the UIFactory
15responsible for any encoding.
16
17Some UIFactories support only a subset of operations: for example
18non-interactive UIs may refuse to ask for input.
19
20Plugin UIFactories might choose to subclass ``TextUIFactory`` rather than
21the base UIFactory. Then if they don't have an implementation for a
22particular method, it'll be done through text interaction in their
23terminal window (if any) rather than giving an error.
24
25In general we want to add more semantic methods to the UIFactory so that
26non-text user interfaces can do more than just present the text that would
27have been shown in the console. For instance, rather than just presenting
28the string that a branch is locked, we'd prefer to have a specific method
29advising of inability to lock, so that a GUI could offer different options
30or a specific presentation.
31
32We're moving towards a complete API separation between developer-oriented
33debug messages, recorded using ``mutter``, and user-oriented messages.
34The former can still be recorded even in graphical or non-interactive
35programs.
36
37Core library code has the option to synchronously show messages to the
38user or to ask for input through eg ``get_boolean`` or ``show_message``,
39but it should do this with care. In a GUI the user should be driving the
40interaction, not the application.
41
42Some core library code, such as upgrade or checkout, does some work that
43should be reported to the user in a text-mode application, but that might
44be shown very differently or not at all in other cases. Rather than
45repeatedly showing messages.
46
47A particular case of this is the ProgressTask api, where a model/view
48separation is fairly complete. Core code obtains a ``ProgressTask`` from
49``ui.ui_factory.nested_progress_bar``, and then feeds it events to tell
50how the task is progressing, with no concern for whether or how this is
51displayed to the user.
52
53In tests, mutter output is collected onto the test log, so that it can be
54shown when there's a failure or inspected by code that wants to check what
55was logged. However, this should no longer be used for inspecting user
56output: do that by providing a custom UIFactory or using run_bzr_captured.
57
58stdout and stderr
59*****************
60
61We normally reserve stdout for bulk output data, such as diffs, logs, or
62bundles, and put all UIFactory output onto stderr.