Merge lp:~mbp/bzr/remove-logging into lp:bzr
- remove-logging
- Merge into bzr.dev
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 |
Related bugs: |
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.
Commit message
Description of the change
Martin Pool (mbp) wrote : | # |
John A Meinel (jameinel) wrote : | # |
-----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 UpgradeRecommen
>
> * 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...
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
- 4806. By Canonical.com Patch Queue Manager <email address hidden>
-
(jam, Martin gz) More win32 fixes.
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.
- 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>
-
* TestCaseWithMem
oryTransport 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.TestUIFac tory - 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 makeCollectingL ogger. - 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 makeCollectingL ogger. - 4834. By Martin Pool
-
Document bzrlib.
tests.TestUIFac tory - 4833. By Martin Pool
-
Tags can be tested in the default format now
- 4832. By Martin Pool
-
Add user interaction architecture doc
Preview Diff
1 | === modified file 'NEWS' | |||
2 | --- NEWS 2009-11-26 17:23:54 +0000 | |||
3 | +++ NEWS 2009-11-27 05:14:10 +0000 | |||
4 | @@ -14,6 +14,10 @@ | |||
5 | 14 | Compatibility Breaks | 14 | Compatibility Breaks |
6 | 15 | ******************** | 15 | ******************** |
7 | 16 | 16 | ||
8 | 17 | * Some messages that were previously sent to stdout now go to stderr, as | ||
9 | 18 | part of making handling of such things more consistent across bzr. | ||
10 | 19 | (Martin Pool) | ||
11 | 20 | |||
12 | 17 | * The BZR_SSH environmental variable may now be set to the path of a secure | 21 | * The BZR_SSH environmental variable may now be set to the path of a secure |
13 | 18 | shell client. If currently set to the value ``ssh`` it will now guess the | 22 | shell client. If currently set to the value ``ssh`` it will now guess the |
14 | 19 | vendor of the program with that name, to restore the old behaviour that | 23 | vendor of the program with that name, to restore the old behaviour that |
15 | @@ -40,6 +44,9 @@ | |||
16 | 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. |
17 | 41 | (Robert Collins, #84659) | 45 | (Robert Collins, #84659) |
18 | 42 | 46 | ||
19 | 47 | * Cope if sys.exitfunc doesn't exist because no exitfuncs have been | ||
20 | 48 | registered. (Martin Pool) | ||
21 | 49 | |||
22 | 43 | * Lots of bugfixes for the test suite on Windows. We should once again | 50 | * Lots of bugfixes for the test suite on Windows. We should once again |
23 | 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) |
24 | 45 | 52 | ||
25 | @@ -64,6 +71,9 @@ | |||
26 | 64 | API Changes | 71 | API Changes |
27 | 65 | *********** | 72 | *********** |
28 | 66 | 73 | ||
29 | 74 | * bzrlib no longer uses ``logging`` for messages, just its own UIFactory. | ||
30 | 75 | (Martin Pool) | ||
31 | 76 | |||
32 | 67 | * ``bzrlib.textui`` (vestigial module) removed. (Martin Pool) | 77 | * ``bzrlib.textui`` (vestigial module) removed. (Martin Pool) |
33 | 68 | 78 | ||
34 | 69 | Internals | 79 | Internals |
35 | @@ -513,6 +523,13 @@ | |||
36 | 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 |
37 | 514 | returns the old and new branches. (Gary van der Merwe) | 524 | returns the old and new branches. (Gary van der Merwe) |
38 | 515 | 525 | ||
39 | 526 | * ``bzrlib.tests.TestUtil.LogCollector`` and ``makeCollectingLogger`` | ||
40 | 527 | have been deleted. bzrlib no longer uses ``logging`` so tests should | ||
41 | 528 | examine output using a UIFactory or ``run_bzr``. (Martin Pool) | ||
42 | 529 | |||
43 | 530 | * ``TextUIFactory`` constructor parameters providing file handles are now | ||
44 | 531 | mandatory. (Martin Pool) | ||
45 | 532 | |||
46 | 516 | * ``bzrlib.trace.log_error``, ``error`` and ``info`` have been deprecated. | 533 | * ``bzrlib.trace.log_error``, ``error`` and ``info`` have been deprecated. |
47 | 517 | (Martin Pool) | 534 | (Martin Pool) |
48 | 518 | 535 | ||
49 | 519 | 536 | ||
50 | === modified file 'bzr' | |||
51 | --- bzr 2009-10-30 16:13:05 +0000 | |||
52 | +++ bzr 2009-11-27 05:14:10 +0000 | |||
53 | @@ -144,9 +144,14 @@ | |||
54 | 144 | if profiling: | 144 | if profiling: |
55 | 145 | profile_imports.log_stack_info(sys.stderr) | 145 | profile_imports.log_stack_info(sys.stderr) |
56 | 146 | 146 | ||
60 | 147 | # run anything registered by atexit, because it won't be run in the normal | 147 | # Run anything registered by atexit, because it won't be run in the normal |
61 | 148 | # way | 148 | # way; note that this interface is deprecated and only going to be present |
62 | 149 | sys.exitfunc() | 149 | # if somebody has already registered something. We could alternatively |
63 | 150 | # use atexit._run_exitfuncs but that's undocumented and requires loading | ||
64 | 151 | # another module. -- mbp 200911127 | ||
65 | 152 | exitfunc = getattr(sys, 'exitfunc', None) | ||
66 | 153 | if exitfunc: | ||
67 | 154 | exitfunc() | ||
68 | 150 | 155 | ||
69 | 151 | # By this point we really have completed everything we want to do, and | 156 | # By this point we really have completed everything we want to do, and |
70 | 152 | # there's no point doing any additional cleanup. Abruptly exiting here | 157 | # there's no point doing any additional cleanup. Abruptly exiting here |
71 | 153 | 158 | ||
72 | === modified file 'bzrlib/cleanup.py' | |||
73 | --- bzrlib/cleanup.py 2009-10-26 06:23:14 +0000 | |||
74 | +++ bzrlib/cleanup.py 2009-11-27 05:14:10 +0000 | |||
75 | @@ -53,7 +53,7 @@ | |||
76 | 53 | trace.mutter('Cleanup failed:') | 53 | trace.mutter('Cleanup failed:') |
77 | 54 | trace.log_exception_quietly() | 54 | trace.log_exception_quietly() |
78 | 55 | if 'cleanup' in debug.debug_flags: | 55 | if 'cleanup' in debug.debug_flags: |
80 | 56 | trace.warning('bzr: warning: Cleanup failed: %s', exc) | 56 | trace.warning('Cleanup failed: %s', exc) |
81 | 57 | 57 | ||
82 | 58 | 58 | ||
83 | 59 | def _run_cleanup(func, *args, **kwargs): | 59 | def _run_cleanup(func, *args, **kwargs): |
84 | 60 | 60 | ||
85 | === modified file 'bzrlib/osutils.py' | |||
86 | --- bzrlib/osutils.py 2009-11-10 07:01:56 +0000 | |||
87 | +++ bzrlib/osutils.py 2009-11-27 05:14:10 +0000 | |||
88 | @@ -929,7 +929,7 @@ | |||
89 | 929 | # the warnings framework should by default show this only once | 929 | # the warnings framework should by default show this only once |
90 | 930 | from bzrlib.trace import warning | 930 | from bzrlib.trace import warning |
91 | 931 | warning( | 931 | warning( |
93 | 932 | "bzr: warning: some compiled extensions could not be loaded; " | 932 | "some compiled extensions could not be loaded; " |
94 | 933 | "see <https://answers.launchpad.net/bzr/+faq/703>") | 933 | "see <https://answers.launchpad.net/bzr/+faq/703>") |
95 | 934 | # we no longer show the specific missing extensions here, because it makes | 934 | # we no longer show the specific missing extensions here, because it makes |
96 | 935 | # the message too long and scary - see | 935 | # the message too long and scary - see |
97 | 936 | 936 | ||
98 | === modified file 'bzrlib/status.py' | |||
99 | --- bzrlib/status.py 2009-08-06 05:07:12 +0000 | |||
100 | +++ bzrlib/status.py 2009-11-27 05:14:10 +0000 | |||
101 | @@ -1,4 +1,4 @@ | |||
103 | 1 | # Copyright (C) 2005, 2006, 2007 Canonical Ltd | 1 | # Copyright (C) 2005, 2006, 2007, 2009 Canonical Ltd |
104 | 2 | # | 2 | # |
105 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
106 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
107 | @@ -20,6 +20,7 @@ | |||
108 | 20 | delta as _mod_delta, | 20 | delta as _mod_delta, |
109 | 21 | log, | 21 | log, |
110 | 22 | osutils, | 22 | osutils, |
111 | 23 | trace, | ||
112 | 23 | tree, | 24 | tree, |
113 | 24 | tsort, | 25 | tsort, |
114 | 25 | revision as _mod_revision, | 26 | revision as _mod_revision, |
115 | @@ -28,10 +29,7 @@ | |||
116 | 28 | from bzrlib.osutils import is_inside_any | 29 | from bzrlib.osutils import is_inside_any |
117 | 29 | from bzrlib.symbol_versioning import (deprecated_function, | 30 | from bzrlib.symbol_versioning import (deprecated_function, |
118 | 30 | ) | 31 | ) |
123 | 31 | from bzrlib.trace import mutter, warning | 32 | from bzrlib.trace import mutter |
120 | 32 | |||
121 | 33 | # TODO: when showing single-line logs, truncate to the width of the terminal | ||
122 | 34 | # if known, but only if really going to the terminal (not into a file) | ||
124 | 35 | 33 | ||
125 | 36 | 34 | ||
126 | 37 | def show_tree_status(wt, show_unchanged=None, | 35 | def show_tree_status(wt, show_unchanged=None, |
127 | @@ -84,7 +82,7 @@ | |||
128 | 84 | new_is_working_tree = True | 82 | new_is_working_tree = True |
129 | 85 | if revision is None: | 83 | if revision is None: |
130 | 86 | if wt.last_revision() != wt.branch.last_revision(): | 84 | if wt.last_revision() != wt.branch.last_revision(): |
132 | 87 | warning("working tree is out of date, run 'bzr update'") | 85 | trace.note("working tree is out of date, run 'bzr update'") |
133 | 88 | new = wt | 86 | new = wt |
134 | 89 | old = new.basis_tree() | 87 | old = new.basis_tree() |
135 | 90 | elif len(revision) > 0: | 88 | elif len(revision) > 0: |
136 | 91 | 89 | ||
137 | === modified file 'bzrlib/tests/TestUtil.py' | |||
138 | --- bzrlib/tests/TestUtil.py 2009-03-23 14:59:43 +0000 | |||
139 | +++ bzrlib/tests/TestUtil.py 2009-11-27 05:14:10 +0000 | |||
140 | @@ -1,4 +1,4 @@ | |||
142 | 1 | # Copyright (C) 2004, 2005, 2006 Canonical Ltd | 1 | # Copyright (C) 2004, 2005, 2006, 2009 Canonical Ltd |
143 | 2 | # Author: Robert Collins <robert.collins@canonical.com> | 2 | # Author: Robert Collins <robert.collins@canonical.com> |
144 | 3 | # | 3 | # |
145 | 4 | # This program is free software; you can redistribute it and/or modify | 4 | # This program is free software; you can redistribute it and/or modify |
146 | @@ -17,7 +17,6 @@ | |||
147 | 17 | # | 17 | # |
148 | 18 | 18 | ||
149 | 19 | import sys | 19 | import sys |
150 | 20 | import logging | ||
151 | 21 | import unittest | 20 | import unittest |
152 | 22 | 21 | ||
153 | 23 | # Mark this python module as being part of the implementation | 22 | # Mark this python module as being part of the implementation |
154 | @@ -26,24 +25,6 @@ | |||
155 | 26 | __unittest = 1 | 25 | __unittest = 1 |
156 | 27 | 26 | ||
157 | 28 | 27 | ||
158 | 29 | class LogCollector(logging.Handler): | ||
159 | 30 | def __init__(self): | ||
160 | 31 | logging.Handler.__init__(self) | ||
161 | 32 | self.records=[] | ||
162 | 33 | def emit(self, record): | ||
163 | 34 | self.records.append(record.getMessage()) | ||
164 | 35 | |||
165 | 36 | |||
166 | 37 | def makeCollectingLogger(): | ||
167 | 38 | """I make a logger instance that collects its logs for programmatic analysis | ||
168 | 39 | -> (logger, collector)""" | ||
169 | 40 | logger=logging.Logger("collector") | ||
170 | 41 | handler=LogCollector() | ||
171 | 42 | handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) | ||
172 | 43 | logger.addHandler(handler) | ||
173 | 44 | return logger, handler | ||
174 | 45 | |||
175 | 46 | |||
176 | 47 | def visitTests(suite, visitor): | 28 | def visitTests(suite, visitor): |
177 | 48 | """A foreign method for visiting the tests in a test suite.""" | 29 | """A foreign method for visiting the tests in a test suite.""" |
178 | 49 | for test in suite._tests: | 30 | for test in suite._tests: |
179 | 50 | 31 | ||
180 | === modified file 'bzrlib/tests/__init__.py' | |||
181 | --- bzrlib/tests/__init__.py 2009-11-24 08:28:41 +0000 | |||
182 | +++ bzrlib/tests/__init__.py 2009-11-27 05:14:10 +0000 | |||
183 | @@ -1880,8 +1880,7 @@ | |||
184 | 1880 | overall behavior of the bzr application (rather than a unit test | 1880 | overall behavior of the bzr application (rather than a unit test |
185 | 1881 | or a functional test of the library.) | 1881 | or a functional test of the library.) |
186 | 1882 | 1882 | ||
189 | 1883 | This sends the stdout/stderr results into the test's log, | 1883 | :returns: (out, err) tuple of strings of output. |
188 | 1884 | where it may be useful for debugging. See also run_captured. | ||
190 | 1885 | 1884 | ||
191 | 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. |
192 | 1887 | :keyword retcode: The status code the command should return; | 1886 | :keyword retcode: The status code the command should return; |
193 | 1888 | 1887 | ||
194 | === modified file 'bzrlib/tests/blackbox/test_exceptions.py' | |||
195 | --- bzrlib/tests/blackbox/test_exceptions.py 2009-08-20 06:25:02 +0000 | |||
196 | +++ bzrlib/tests/blackbox/test_exceptions.py 2009-11-27 05:14:10 +0000 | |||
197 | @@ -1,4 +1,4 @@ | |||
199 | 1 | # Copyright (C) 2006, 2007 Canonical Ltd | 1 | # Copyright (C) 2006, 2007, 2009 Canonical Ltd |
200 | 2 | # | 2 | # |
201 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
202 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
203 | @@ -43,20 +43,3 @@ | |||
204 | 43 | self.assertContainsRe(err, | 43 | self.assertContainsRe(err, |
205 | 44 | r'exceptions\.AssertionError: always fails\n') | 44 | r'exceptions\.AssertionError: always fails\n') |
206 | 45 | self.assertContainsRe(err, r'Bazaar has encountered an internal error') | 45 | self.assertContainsRe(err, r'Bazaar has encountered an internal error') |
207 | 46 | |||
208 | 47 | |||
209 | 48 | class TestDeprecationWarning(TestCaseInTempDir): | ||
210 | 49 | |||
211 | 50 | def test_repository_deprecation_warning(self): | ||
212 | 51 | """Old formats give a warning""" | ||
213 | 52 | # the warning's normally off for testing but we reenable it | ||
214 | 53 | repository._deprecation_warning_done = False | ||
215 | 54 | try: | ||
216 | 55 | os.mkdir('foo') | ||
217 | 56 | bzrdir.BzrDirFormat5().initialize('foo') | ||
218 | 57 | out, err = self.run_bzr("status foo") | ||
219 | 58 | self.assertContainsRe(self._get_log(keep_log_file=True), | ||
220 | 59 | "bzr upgrade") | ||
221 | 60 | finally: | ||
222 | 61 | repository._deprecation_warning_done = True | ||
223 | 62 | |||
224 | 63 | 46 | ||
225 | === modified file 'bzrlib/tests/blackbox/test_reconcile.py' | |||
226 | --- bzrlib/tests/blackbox/test_reconcile.py 2009-03-23 14:59:43 +0000 | |||
227 | +++ bzrlib/tests/blackbox/test_reconcile.py 2009-11-27 05:14:10 +0000 | |||
228 | @@ -46,7 +46,7 @@ | |||
229 | 46 | does_backup_text = "Inventory ok.\n" | 46 | does_backup_text = "Inventory ok.\n" |
230 | 47 | else: | 47 | else: |
231 | 48 | does_backup_text = "" | 48 | does_backup_text = "" |
233 | 49 | self.assertEqualDiff(out, "Reconciling branch %s\n" | 49 | self.assertEqualDiff(err, "Reconciling branch %s\n" |
234 | 50 | "revision_history ok.\n" | 50 | "revision_history ok.\n" |
235 | 51 | "Reconciling repository %s\n" | 51 | "Reconciling repository %s\n" |
236 | 52 | "%s" | 52 | "%s" |
237 | @@ -54,7 +54,7 @@ | |||
238 | 54 | (t.branch.base, | 54 | (t.branch.base, |
239 | 55 | t.bzrdir.root_transport.base, | 55 | t.bzrdir.root_transport.base, |
240 | 56 | does_backup_text)) | 56 | does_backup_text)) |
242 | 57 | self.assertEqualDiff(err, "") | 57 | self.assertEqualDiff(out, "") |
243 | 58 | 58 | ||
244 | 59 | def test_does_something_reconcile(self): | 59 | def test_does_something_reconcile(self): |
245 | 60 | t = bzrdir.BzrDir.create_standalone_workingtree('.') | 60 | t = bzrdir.BzrDir.create_standalone_workingtree('.') |
246 | @@ -82,5 +82,5 @@ | |||
247 | 82 | (t.branch.base, | 82 | (t.branch.base, |
248 | 83 | t.bzrdir.root_transport.base, | 83 | t.bzrdir.root_transport.base, |
249 | 84 | does_backup_text)) | 84 | does_backup_text)) |
252 | 85 | self.assertEqualDiff(expected, out) | 85 | self.assertEqualDiff(expected, err) |
253 | 86 | self.assertEqualDiff(err, "") | 86 | self.assertEqualDiff("", out) |
254 | 87 | 87 | ||
255 | === modified file 'bzrlib/tests/blackbox/test_reconfigure.py' | |||
256 | --- bzrlib/tests/blackbox/test_reconfigure.py 2009-07-10 08:18:28 +0000 | |||
257 | +++ bzrlib/tests/blackbox/test_reconfigure.py 2009-11-27 05:14:10 +0000 | |||
258 | @@ -211,16 +211,16 @@ | |||
259 | 211 | branch_2 = tree_2.branch | 211 | branch_2 = tree_2.branch |
260 | 212 | # now reconfigure to be stacked | 212 | # now reconfigure to be stacked |
261 | 213 | out, err = self.run_bzr('reconfigure --stacked-on b1 b2') | 213 | out, err = self.run_bzr('reconfigure --stacked-on b1 b2') |
263 | 214 | self.assertContainsRe(out, | 214 | self.assertContainsRe(err, |
264 | 215 | '^.*/b2/ is now stacked on ../b1\n$') | 215 | '^.*/b2/ is now stacked on ../b1\n$') |
266 | 216 | self.assertEquals('', err) | 216 | self.assertEquals('', out) |
267 | 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 |
268 | 218 | # as a relative path if possible | 218 | # as a relative path if possible |
269 | 219 | out, err = self.run_bzr('reconfigure --stacked-on %s b2' | 219 | out, err = self.run_bzr('reconfigure --stacked-on %s b2' |
270 | 220 | % (self.get_url('b1'),)) | 220 | % (self.get_url('b1'),)) |
272 | 221 | self.assertContainsRe(out, | 221 | self.assertContainsRe(err, |
273 | 222 | '^.*/b2/ is now stacked on ../b1\n$') | 222 | '^.*/b2/ is now stacked on ../b1\n$') |
275 | 223 | self.assertEquals('', err) | 223 | self.assertEquals('', out) |
276 | 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, |
277 | 225 | # because that's most likely to work across different transports | 225 | # because that's most likely to work across different transports |
278 | 226 | self.assertEquals(branch_2.get_stacked_on_url(), | 226 | self.assertEquals(branch_2.get_stacked_on_url(), |
279 | @@ -230,9 +230,9 @@ | |||
280 | 230 | tree_2.commit('update foo') | 230 | tree_2.commit('update foo') |
281 | 231 | # Now turn it off again | 231 | # Now turn it off again |
282 | 232 | out, err = self.run_bzr('reconfigure --unstacked b2') | 232 | out, err = self.run_bzr('reconfigure --unstacked b2') |
284 | 233 | self.assertContainsRe(out, | 233 | self.assertContainsRe(err, |
285 | 234 | '^.*/b2/ is now not stacked\n$') | 234 | '^.*/b2/ is now not stacked\n$') |
287 | 235 | self.assertEquals('', err) | 235 | self.assertEquals('', out) |
288 | 236 | self.assertRaises(errors.NotStacked, | 236 | self.assertRaises(errors.NotStacked, |
289 | 237 | branch_2.get_stacked_on_url) | 237 | branch_2.get_stacked_on_url) |
290 | 238 | 238 | ||
291 | 239 | 239 | ||
292 | === modified file 'bzrlib/tests/blackbox/test_tags.py' | |||
293 | --- bzrlib/tests/blackbox/test_tags.py 2009-08-20 04:09:58 +0000 | |||
294 | +++ bzrlib/tests/blackbox/test_tags.py 2009-11-27 05:14:10 +0000 | |||
295 | @@ -1,4 +1,4 @@ | |||
297 | 1 | # Copyright (C) 2007 Canonical Ltd | 1 | # Copyright (C) 2007, 2009 Canonical Ltd |
298 | 2 | # | 2 | # |
299 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
300 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
301 | @@ -30,14 +30,6 @@ | |||
302 | 30 | 30 | ||
303 | 31 | class TestTagging(TestCaseWithTransport): | 31 | class TestTagging(TestCaseWithTransport): |
304 | 32 | 32 | ||
305 | 33 | # as of 0.14, the default format doesn't do tags so we need to use a | ||
306 | 34 | # specific format | ||
307 | 35 | |||
308 | 36 | def make_branch_and_tree(self, relpath): | ||
309 | 37 | format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree') | ||
310 | 38 | return TestCaseWithTransport.make_branch_and_tree(self, relpath, | ||
311 | 39 | format=format) | ||
312 | 40 | |||
313 | 41 | def test_tag_command_help(self): | 33 | def test_tag_command_help(self): |
314 | 42 | out, err = self.run_bzr('help tag') | 34 | out, err = self.run_bzr('help tag') |
315 | 43 | self.assertContainsRe(out, 'Create, remove or modify a tag') | 35 | self.assertContainsRe(out, 'Create, remove or modify a tag') |
316 | 44 | 36 | ||
317 | === modified file 'bzrlib/tests/blackbox/test_upgrade.py' | |||
318 | --- bzrlib/tests/blackbox/test_upgrade.py 2009-08-21 02:10:06 +0000 | |||
319 | +++ bzrlib/tests/blackbox/test_upgrade.py 2009-11-27 05:14:10 +0000 | |||
320 | @@ -86,11 +86,12 @@ | |||
321 | 86 | (out, err) = self.run_bzr('upgrade current_format_checkout', retcode=3) | 86 | (out, err) = self.run_bzr('upgrade current_format_checkout', retcode=3) |
322 | 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 " |
323 | 88 | "upgraded separately.\n" | 88 | "upgraded separately.\n" |
324 | 89 | "bzr: ERROR: The branch format Meta " | ||
325 | 90 | "directory format 1 is already at the most " | ||
326 | 91 | "recent format.\n" | ||
327 | 89 | % get_transport(self.get_url('current_format_branch')).base, | 92 | % get_transport(self.get_url('current_format_branch')).base, |
332 | 90 | out) | 93 | err) |
333 | 91 | self.assertEqualDiff("bzr: ERROR: The branch format Meta " | 94 | self.assertEqualDiff('', out) |
330 | 92 | "directory format 1 is already at the most " | ||
331 | 93 | "recent format.\n", err) | ||
334 | 94 | 95 | ||
335 | 95 | def test_upgrade_checkout(self): | 96 | def test_upgrade_checkout(self): |
336 | 96 | # upgrading a checkout should work | 97 | # upgrading a checkout should work |
337 | @@ -121,8 +122,8 @@ | |||
338 | 121 | adding prefixes to revision-store | 122 | adding prefixes to revision-store |
339 | 122 | starting upgrade from format 6 to metadir | 123 | starting upgrade from format 6 to metadir |
340 | 123 | finished | 124 | finished |
343 | 124 | """ % (url, url, url), out) | 125 | """ % (url, url, url), err) |
344 | 125 | self.assertEqualDiff("", err) | 126 | self.assertEqualDiff("", out) |
345 | 126 | self.assertTrue(isinstance( | 127 | self.assertTrue(isinstance( |
346 | 127 | bzrdir.BzrDir.open(self.get_url('format_5_branch'))._format, | 128 | bzrdir.BzrDir.open(self.get_url('format_5_branch'))._format, |
347 | 128 | bzrdir.BzrDirMetaFormat1)) | 129 | bzrdir.BzrDirMetaFormat1)) |
348 | @@ -142,8 +143,8 @@ | |||
349 | 142 | starting repository conversion | 143 | starting repository conversion |
350 | 143 | repository converted | 144 | repository converted |
351 | 144 | finished | 145 | finished |
354 | 145 | """ % (url, url, url), out) | 146 | """ % (url, url, url), err) |
355 | 146 | self.assertEqualDiff("", err) | 147 | self.assertEqualDiff("", out) |
356 | 147 | converted_dir = bzrdir.BzrDir.open(self.get_url('metadir_weave_branch')) | 148 | converted_dir = bzrdir.BzrDir.open(self.get_url('metadir_weave_branch')) |
357 | 148 | self.assertTrue(isinstance(converted_dir._format, | 149 | self.assertTrue(isinstance(converted_dir._format, |
358 | 149 | bzrdir.BzrDirMetaFormat1)) | 150 | bzrdir.BzrDirMetaFormat1)) |
359 | @@ -180,8 +181,8 @@ | |||
360 | 180 | starting repository conversion | 181 | starting repository conversion |
361 | 181 | repository converted | 182 | repository converted |
362 | 182 | finished | 183 | finished |
365 | 183 | """ % (url, url, url), out) | 184 | """ % (url, url, url), err) |
366 | 184 | self.assertEqual('', err) | 185 | self.assertEqual('', out) |
367 | 185 | 186 | ||
368 | 186 | 187 | ||
369 | 187 | class UpgradeRecommendedTests(TestCaseWithTransport): | 188 | class UpgradeRecommendedTests(TestCaseWithTransport): |
370 | 188 | 189 | ||
371 | === modified file 'bzrlib/tests/blackbox/test_whoami.py' | |||
372 | --- bzrlib/tests/blackbox/test_whoami.py 2009-03-23 14:59:43 +0000 | |||
373 | +++ bzrlib/tests/blackbox/test_whoami.py 2009-11-27 05:14:10 +0000 | |||
374 | @@ -1,4 +1,4 @@ | |||
376 | 1 | # Copyright (C) 2006 Canonical Ltd | 1 | # Copyright (C) 2006, 2009 Canonical Ltd |
377 | 2 | # | 2 | # |
378 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
379 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
380 | @@ -108,6 +108,7 @@ | |||
381 | 108 | """verify that a warning is displayed if no email is given.""" | 108 | """verify that a warning is displayed if no email is given.""" |
382 | 109 | self.make_branch_and_tree('.') | 109 | self.make_branch_and_tree('.') |
383 | 110 | display = self.run_bzr(['whoami', 'Branch Identity'])[1] | 110 | display = self.run_bzr(['whoami', 'Branch Identity'])[1] |
387 | 111 | self.assertEquals('"Branch Identity" does not seem to contain an ' | 111 | self.assertEquals('bzr: warning: ' |
388 | 112 | 'email address. This is allowed, but not ' | 112 | '"Branch Identity" does not seem to contain an ' |
389 | 113 | 'recommended.\n', display) | 113 | 'email address. This is allowed, but not ' |
390 | 114 | 'recommended.\n', display) | ||
391 | 114 | 115 | ||
392 | === modified file 'bzrlib/tests/per_branch/test_check.py' | |||
393 | --- bzrlib/tests/per_branch/test_check.py 2009-08-04 04:36:34 +0000 | |||
394 | +++ bzrlib/tests/per_branch/test_check.py 2009-11-27 05:14:10 +0000 | |||
395 | @@ -60,7 +60,9 @@ | |||
396 | 60 | self.addCleanup(tree.unlock) | 60 | self.addCleanup(tree.unlock) |
397 | 61 | refs = self.make_refs(tree.branch) | 61 | refs = self.make_refs(tree.branch) |
398 | 62 | result = tree.branch.check(refs) | 62 | result = tree.branch.check(refs) |
400 | 63 | ui.ui_factory = tests.TestUIFactory(stdout=StringIO()) | 63 | ui.ui_factory = tests.TestUIFactory(stdin='', |
401 | 64 | stdout=StringIO(), | ||
402 | 65 | stderr=StringIO()) | ||
403 | 64 | result.report_results(True) | 66 | result.report_results(True) |
404 | 65 | self.assertContainsRe('revno does not match len', | 67 | self.assertContainsRe('revno does not match len', |
405 | 66 | ui.ui_factory.stdout.getvalue()) | 68 | ui.ui_factory.stdout.getvalue()) |
406 | 67 | 69 | ||
407 | === modified file 'bzrlib/tests/test_plugins.py' | |||
408 | --- bzrlib/tests/test_plugins.py 2009-09-18 14:53:37 +0000 | |||
409 | +++ bzrlib/tests/test_plugins.py 2009-11-27 05:14:10 +0000 | |||
410 | @@ -1,4 +1,4 @@ | |||
412 | 1 | # Copyright (C) 2005, 2007 Canonical Ltd | 1 | # Copyright (C) 2005, 2007, 2009 Canonical Ltd |
413 | 2 | # | 2 | # |
414 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
415 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
416 | @@ -16,11 +16,6 @@ | |||
417 | 16 | 16 | ||
418 | 17 | """Tests for plugins""" | 17 | """Tests for plugins""" |
419 | 18 | 18 | ||
420 | 19 | # XXX: There are no plugin tests at the moment because the plugin module | ||
421 | 20 | # affects the global state of the process. See bzrlib/plugins.py for more | ||
422 | 21 | # comments. | ||
423 | 22 | |||
424 | 23 | import logging | ||
425 | 24 | import os | 19 | import os |
426 | 25 | from StringIO import StringIO | 20 | from StringIO import StringIO |
427 | 26 | import sys | 21 | import sys |
428 | @@ -30,6 +25,7 @@ | |||
429 | 30 | osutils, | 25 | osutils, |
430 | 31 | plugin, | 26 | plugin, |
431 | 32 | tests, | 27 | tests, |
432 | 28 | ui, | ||
433 | 33 | ) | 29 | ) |
434 | 34 | import bzrlib.plugin | 30 | import bzrlib.plugin |
435 | 35 | import bzrlib.plugins | 31 | import bzrlib.plugins |
436 | @@ -202,28 +198,17 @@ | |||
437 | 202 | :param name: The name of the plugin. | 198 | :param name: The name of the plugin. |
438 | 203 | :return: A string with the log from the plugin loading call. | 199 | :return: A string with the log from the plugin loading call. |
439 | 204 | """ | 200 | """ |
440 | 205 | # Capture output | ||
441 | 206 | stream = StringIO() | 201 | stream = StringIO() |
442 | 202 | ui.ui_factory = tests.TestUIFactory(stdout=stream, stderr=stream, | ||
443 | 203 | stdin=None) | ||
444 | 207 | try: | 204 | try: |
462 | 208 | handler = logging.StreamHandler(stream) | 205 | bzrlib.plugin.load_from_path(['.']) |
446 | 209 | log = logging.getLogger('bzr') | ||
447 | 210 | log.addHandler(handler) | ||
448 | 211 | try: | ||
449 | 212 | try: | ||
450 | 213 | bzrlib.plugin.load_from_path(['.']) | ||
451 | 214 | finally: | ||
452 | 215 | if 'bzrlib.plugins.%s' % name in sys.modules: | ||
453 | 216 | del sys.modules['bzrlib.plugins.%s' % name] | ||
454 | 217 | if getattr(bzrlib.plugins, name, None): | ||
455 | 218 | delattr(bzrlib.plugins, name) | ||
456 | 219 | finally: | ||
457 | 220 | # Stop capturing output | ||
458 | 221 | handler.flush() | ||
459 | 222 | handler.close() | ||
460 | 223 | log.removeHandler(handler) | ||
461 | 224 | return stream.getvalue() | ||
463 | 225 | finally: | 206 | finally: |
465 | 226 | stream.close() | 207 | if 'bzrlib.plugins.%s' % name in sys.modules: |
466 | 208 | del sys.modules['bzrlib.plugins.%s' % name] | ||
467 | 209 | if getattr(bzrlib.plugins, name, None): | ||
468 | 210 | delattr(bzrlib.plugins, name) | ||
469 | 211 | return stream.getvalue() | ||
470 | 227 | 212 | ||
471 | 228 | def test_plugin_with_bad_api_version_reports(self): | 213 | def test_plugin_with_bad_api_version_reports(self): |
472 | 229 | # This plugin asks for bzrlib api version 1.0.0, which is not supported | 214 | # This plugin asks for bzrlib api version 1.0.0, which is not supported |
473 | 230 | 215 | ||
474 | === modified file 'bzrlib/trace.py' | |||
475 | --- bzrlib/trace.py 2009-11-19 20:47:51 +0000 | |||
476 | +++ bzrlib/trace.py 2009-11-27 05:14:10 +0000 | |||
477 | @@ -1,4 +1,4 @@ | |||
479 | 1 | # Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd | 1 | # Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd |
480 | 2 | # | 2 | # |
481 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
482 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
483 | @@ -16,16 +16,17 @@ | |||
484 | 16 | 16 | ||
485 | 17 | """Messages and logging for bazaar-ng. | 17 | """Messages and logging for bazaar-ng. |
486 | 18 | 18 | ||
487 | 19 | The current general approach is that information for the user in normal | ||
488 | 20 | operation should go through the UIFactory, and trace should mostly be used for | ||
489 | 21 | debug and internal error information. However, this is not fully implemented. | ||
490 | 22 | |||
491 | 19 | Messages are supplied by callers as a string-formatting template, plus values | 23 | Messages are supplied by callers as a string-formatting template, plus values |
492 | 20 | to be inserted into it. The actual %-formatting is deferred to the log | 24 | to be inserted into it. The actual %-formatting is deferred to the log |
493 | 21 | library so that it doesn't need to be done for messages that won't be emitted. | 25 | library so that it doesn't need to be done for messages that won't be emitted. |
494 | 22 | 26 | ||
501 | 23 | Messages are classified by severity levels: critical, error, warning, info, | 27 | They can be sent to two places: to stderr (via the UIFactory), and to |
502 | 24 | and debug. | 28 | ~/.bzr.log. For purposes such as running the test suite, they can also be |
503 | 25 | 29 | redirected away from both of those two places to another location. | |
498 | 26 | They can be sent to two places: to stderr, and to ~/.bzr.log. For purposes | ||
499 | 27 | such as running the test suite, they can also be redirected away from both of | ||
500 | 28 | those two places to another location. | ||
504 | 29 | 30 | ||
505 | 30 | ~/.bzr.log gets all messages, and full tracebacks for uncaught exceptions. | 31 | ~/.bzr.log gets all messages, and full tracebacks for uncaught exceptions. |
506 | 31 | This trace file is always in UTF-8, regardless of the user's default encoding, | 32 | This trace file is always in UTF-8, regardless of the user's default encoding, |
507 | @@ -46,17 +47,7 @@ | |||
508 | 46 | form. | 47 | form. |
509 | 47 | """ | 48 | """ |
510 | 48 | 49 | ||
511 | 49 | # FIXME: Unfortunately it turns out that python's logging module | ||
512 | 50 | # is quite expensive, even when the message is not printed by any handlers. | ||
513 | 51 | # We should perhaps change back to just simply doing it here. | ||
514 | 52 | # | ||
515 | 53 | # On the other hand, as of 1.2 we generally only call the mutter() statement | ||
516 | 54 | # if (according to debug_flags) we actually intend to write it. So the | ||
517 | 55 | # increased cost of logging.py is not so bad, and we could standardize on | ||
518 | 56 | # that. | ||
519 | 57 | |||
520 | 58 | import codecs | 50 | import codecs |
521 | 59 | import logging | ||
522 | 60 | import os | 51 | import os |
523 | 61 | import sys | 52 | import sys |
524 | 62 | import time | 53 | import time |
525 | @@ -83,6 +74,8 @@ | |||
526 | 83 | osutils, | 74 | osutils, |
527 | 84 | plugin, | 75 | plugin, |
528 | 85 | symbol_versioning, | 76 | symbol_versioning, |
529 | 77 | trace, | ||
530 | 78 | ui, | ||
531 | 86 | ) | 79 | ) |
532 | 87 | """) | 80 | """) |
533 | 88 | 81 | ||
534 | @@ -106,43 +99,47 @@ | |||
535 | 106 | _bzr_log_start_time = bzrlib._start_time | 99 | _bzr_log_start_time = bzrlib._start_time |
536 | 107 | 100 | ||
537 | 108 | 101 | ||
541 | 109 | # held in a global for quick reference | 102 | def _fmt_msg(args, kwargs): |
542 | 110 | _bzr_logger = logging.getLogger('bzr') | 103 | # common compatibility code for functions that take dual format string |
543 | 111 | 104 | # arguments; normally we don't want to do this from now on | |
544 | 105 | if len(args) > 1: | ||
545 | 106 | if kwargs: | ||
546 | 107 | raise ValueError("can't use both args and kwargs: %r, %r" | ||
547 | 108 | % (args, kwargs)) | ||
548 | 109 | msg = args[0] | ||
549 | 110 | return msg % args[1:] | ||
550 | 111 | elif kwargs: | ||
551 | 112 | return args[0] % kwargs | ||
552 | 113 | else: | ||
553 | 114 | # for compatibility we also accept passing objects that are then cast | ||
554 | 115 | # down | ||
555 | 116 | return unicode(args[0]) | ||
556 | 117 | |||
557 | 112 | 118 | ||
558 | 113 | def note(*args, **kwargs): | 119 | def note(*args, **kwargs): |
567 | 114 | # FIXME note always emits utf-8, regardless of the terminal encoding | 120 | ui.ui_factory.show_message(_fmt_msg(args, kwargs)) |
560 | 115 | # | ||
561 | 116 | # FIXME: clearing the ui and then going through the abstract logging | ||
562 | 117 | # framework is whack; we should probably have a logging Handler that | ||
563 | 118 | # deals with terminal output if needed. | ||
564 | 119 | import bzrlib.ui | ||
565 | 120 | bzrlib.ui.ui_factory.clear_term() | ||
566 | 121 | _bzr_logger.info(*args, **kwargs) | ||
568 | 122 | 121 | ||
569 | 123 | 122 | ||
570 | 124 | def warning(*args, **kwargs): | 123 | def warning(*args, **kwargs): |
574 | 125 | import bzrlib.ui | 124 | ui.ui_factory.show_warning(_fmt_msg(args, kwargs)) |
572 | 126 | bzrlib.ui.ui_factory.clear_term() | ||
573 | 127 | _bzr_logger.warning(*args, **kwargs) | ||
575 | 128 | 125 | ||
576 | 129 | 126 | ||
577 | 130 | @deprecated_function(deprecated_in((2, 1, 0))) | 127 | @deprecated_function(deprecated_in((2, 1, 0))) |
578 | 131 | def info(*args, **kwargs): | 128 | def info(*args, **kwargs): |
579 | 132 | """Deprecated: use trace.note instead.""" | 129 | """Deprecated: use trace.note instead.""" |
581 | 133 | note(*args, **kwargs) | 130 | ui.ui_factory.show_message(_fmt_msg(args, kwargs)) |
582 | 134 | 131 | ||
583 | 135 | 132 | ||
584 | 136 | @deprecated_function(deprecated_in((2, 1, 0))) | 133 | @deprecated_function(deprecated_in((2, 1, 0))) |
585 | 137 | def log_error(*args, **kwargs): | 134 | def log_error(*args, **kwargs): |
586 | 138 | """Deprecated: use bzrlib.trace.show_error instead""" | 135 | """Deprecated: use bzrlib.trace.show_error instead""" |
588 | 139 | _bzr_logger.error(*args, **kwargs) | 136 | ui.ui_factory.show_error(_fmt_msg(args, kwargs)) |
589 | 140 | 137 | ||
590 | 141 | 138 | ||
591 | 142 | @deprecated_function(deprecated_in((2, 1, 0))) | 139 | @deprecated_function(deprecated_in((2, 1, 0))) |
592 | 143 | def error(*args, **kwargs): | 140 | def error(*args, **kwargs): |
593 | 144 | """Deprecated: use bzrlib.trace.show_error instead""" | 141 | """Deprecated: use bzrlib.trace.show_error instead""" |
595 | 145 | _bzr_logger.error(*args, **kwargs) | 142 | ui.ui_factory.show_error(_fmt_msg(args, kwargs)) |
596 | 146 | 143 | ||
597 | 147 | 144 | ||
598 | 148 | def show_error(msg): | 145 | def show_error(msg): |
599 | @@ -150,7 +147,7 @@ | |||
600 | 150 | 147 | ||
601 | 151 | Don't use this for exceptions, use report_exception instead. | 148 | Don't use this for exceptions, use report_exception instead. |
602 | 152 | """ | 149 | """ |
604 | 153 | _bzr_logger.error(*args, **kwargs) | 150 | ui.ui_factory.show_error(msg) |
605 | 154 | 151 | ||
606 | 155 | 152 | ||
607 | 156 | _last_mutter_flush_time = None | 153 | _last_mutter_flush_time = None |
608 | @@ -273,10 +270,7 @@ | |||
609 | 273 | This should only be called once per process. | 270 | This should only be called once per process. |
610 | 274 | 271 | ||
611 | 275 | Non-command-line programs embedding bzrlib do not need to call this. They | 272 | Non-command-line programs embedding bzrlib do not need to call this. They |
616 | 276 | can instead either pass a file to _push_log_file, or act directly on | 273 | can instead pass a file to _push_log_file. |
613 | 277 | logging.getLogger("bzr"). | ||
614 | 278 | |||
615 | 279 | Output can be redirected away by calling _push_log_file. | ||
617 | 280 | """ | 274 | """ |
618 | 281 | # Do this before we open the log file, so we prevent | 275 | # Do this before we open the log file, so we prevent |
619 | 282 | # get_terminal_encoding() from mutter()ing multiple times | 276 | # get_terminal_encoding() from mutter()ing multiple times |
620 | @@ -290,13 +284,6 @@ | |||
621 | 290 | push_log_file(bzr_log_file, | 284 | push_log_file(bzr_log_file, |
622 | 291 | r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s', | 285 | r'[%(process)5d] %(asctime)s.%(msecs)03d %(levelname)s: %(message)s', |
623 | 292 | r'%Y-%m-%d %H:%M:%S') | 286 | r'%Y-%m-%d %H:%M:%S') |
624 | 293 | # after hooking output into bzr_log, we also need to attach a stderr | ||
625 | 294 | # handler, writing only at level info and with encoding | ||
626 | 295 | writer_factory = codecs.getwriter(term_encoding) | ||
627 | 296 | encoded_stderr = writer_factory(sys.stderr, errors='replace') | ||
628 | 297 | stderr_handler = logging.StreamHandler(encoded_stderr) | ||
629 | 298 | stderr_handler.setLevel(logging.INFO) | ||
630 | 299 | logging.getLogger('bzr').addHandler(stderr_handler) | ||
631 | 300 | 287 | ||
632 | 301 | 288 | ||
633 | 302 | def push_log_file(to_file, log_format=None, date_format=None): | 289 | def push_log_file(to_file, log_format=None, date_format=None): |
634 | @@ -305,37 +292,18 @@ | |||
635 | 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. |
636 | 306 | 293 | ||
637 | 307 | :returns: A memento that should be passed to _pop_log_file to restore the | 294 | :returns: A memento that should be passed to _pop_log_file to restore the |
639 | 308 | previously active logging. | 295 | previously active logging. |
640 | 309 | """ | 296 | """ |
641 | 310 | global _trace_file | 297 | global _trace_file |
642 | 311 | # make a new handler | ||
643 | 312 | new_handler = logging.StreamHandler(to_file) | ||
644 | 313 | new_handler.setLevel(logging.DEBUG) | ||
645 | 314 | if log_format is None: | ||
646 | 315 | log_format = '%(levelname)8s %(message)s' | ||
647 | 316 | new_handler.setFormatter(logging.Formatter(log_format, date_format)) | ||
648 | 317 | # save and remove any existing log handlers | ||
649 | 318 | bzr_logger = logging.getLogger('bzr') | ||
650 | 319 | old_handlers = bzr_logger.handlers[:] | ||
651 | 320 | del bzr_logger.handlers[:] | ||
652 | 321 | # set that as the default logger | ||
653 | 322 | bzr_logger.addHandler(new_handler) | ||
654 | 323 | bzr_logger.setLevel(logging.DEBUG) | ||
655 | 324 | # TODO: check if any changes are needed to the root logger | ||
656 | 325 | # | ||
657 | 326 | # TODO: also probably need to save and restore the level on bzr_logger. | ||
658 | 327 | # but maybe we can avoid setting the logger level altogether, and just set | ||
659 | 328 | # the level on the handler? | ||
660 | 329 | # | ||
661 | 330 | # save the old trace file | 298 | # save the old trace file |
662 | 331 | old_trace_file = _trace_file | 299 | old_trace_file = _trace_file |
663 | 332 | # send traces to the new one | 300 | # send traces to the new one |
664 | 333 | _trace_file = to_file | 301 | _trace_file = to_file |
670 | 334 | result = new_handler, _trace_file | 302 | result = _trace_file |
671 | 335 | return ('log_memento', old_handlers, new_handler, old_trace_file, to_file) | 303 | return ('log_memento', old_trace_file, to_file) |
672 | 336 | 304 | ||
673 | 337 | 305 | ||
674 | 338 | def pop_log_file((magic, old_handlers, new_handler, old_trace_file, new_trace_file)): | 306 | def pop_log_file((magic, old_trace_file, new_trace_file)): |
675 | 339 | """Undo changes to logging/tracing done by _push_log_file. | 307 | """Undo changes to logging/tracing done by _push_log_file. |
676 | 340 | 308 | ||
677 | 341 | This flushes, but does not close the trace file. | 309 | This flushes, but does not close the trace file. |
678 | @@ -343,12 +311,6 @@ | |||
679 | 343 | Takes the memento returned from _push_log_file.""" | 311 | Takes the memento returned from _push_log_file.""" |
680 | 344 | global _trace_file | 312 | global _trace_file |
681 | 345 | _trace_file = old_trace_file | 313 | _trace_file = old_trace_file |
682 | 346 | bzr_logger = logging.getLogger('bzr') | ||
683 | 347 | bzr_logger.removeHandler(new_handler) | ||
684 | 348 | # must be closed, otherwise logging will try to close it atexit, and the | ||
685 | 349 | # file will likely already be closed underneath. | ||
686 | 350 | new_handler.close() | ||
687 | 351 | bzr_logger.handlers = old_handlers | ||
688 | 352 | new_trace_file.flush() | 314 | new_trace_file.flush() |
689 | 353 | 315 | ||
690 | 354 | 316 | ||
691 | @@ -369,7 +331,6 @@ | |||
692 | 369 | """ | 331 | """ |
693 | 370 | global _verbosity_level | 332 | global _verbosity_level |
694 | 371 | _verbosity_level = level | 333 | _verbosity_level = level |
695 | 372 | _update_logging_level(level < 0) | ||
696 | 373 | 334 | ||
697 | 374 | 335 | ||
698 | 375 | def get_verbosity_level(): | 336 | def get_verbosity_level(): |
699 | @@ -388,14 +349,6 @@ | |||
700 | 388 | set_verbosity_level(0) | 349 | set_verbosity_level(0) |
701 | 389 | 350 | ||
702 | 390 | 351 | ||
703 | 391 | def _update_logging_level(quiet=True): | ||
704 | 392 | """Hide INFO messages if quiet.""" | ||
705 | 393 | if quiet: | ||
706 | 394 | _bzr_logger.setLevel(logging.WARNING) | ||
707 | 395 | else: | ||
708 | 396 | _bzr_logger.setLevel(logging.INFO) | ||
709 | 397 | |||
710 | 398 | |||
711 | 399 | def is_quiet(): | 352 | def is_quiet(): |
712 | 400 | """Is the verbosity level negative?""" | 353 | """Is the verbosity level negative?""" |
713 | 401 | return _verbosity_level < 0 | 354 | return _verbosity_level < 0 |
714 | 402 | 355 | ||
715 | === modified file 'bzrlib/transport/ssh.py' | |||
716 | --- bzrlib/transport/ssh.py 2009-11-25 07:27:43 +0000 | |||
717 | +++ bzrlib/transport/ssh.py 2009-11-27 05:14:10 +0000 | |||
718 | @@ -19,7 +19,6 @@ | |||
719 | 19 | 19 | ||
720 | 20 | import errno | 20 | import errno |
721 | 21 | import getpass | 21 | import getpass |
722 | 22 | import logging | ||
723 | 23 | import os | 22 | import os |
724 | 24 | import socket | 23 | import socket |
725 | 25 | import subprocess | 24 | import subprocess |
726 | @@ -500,6 +499,7 @@ | |||
727 | 500 | # auth_none check to see if it is even supported. | 499 | # auth_none check to see if it is even supported. |
728 | 501 | supported_auth_types = [] | 500 | supported_auth_types = [] |
729 | 502 | try: | 501 | try: |
730 | 502 | import logging | ||
731 | 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: |
732 | 504 | # Authentication type (none) not permitted. | 504 | # Authentication type (none) not permitted. |
733 | 505 | # So we explicitly disable the logging level for this action | 505 | # So we explicitly disable the logging level for this action |
734 | 506 | 506 | ||
735 | === modified file 'bzrlib/ui/__init__.py' | |||
736 | --- bzrlib/ui/__init__.py 2009-10-15 20:04:37 +0000 | |||
737 | +++ bzrlib/ui/__init__.py 2009-11-27 05:14:10 +0000 | |||
738 | @@ -39,6 +39,10 @@ | |||
739 | 39 | depending on the detected capabilities of the terminal. | 39 | depending on the detected capabilities of the terminal. |
740 | 40 | GUIs may choose to subclass this so that unimplemented methods fall | 40 | GUIs may choose to subclass this so that unimplemented methods fall |
741 | 41 | back to working through the terminal. | 41 | back to working through the terminal. |
742 | 42 | |||
743 | 43 | bzrlib.tests.TestUIFactory | ||
744 | 44 | Similar to TextUIFactory, but with no progress bars and some facilities | ||
745 | 45 | for automated testing. | ||
746 | 42 | """ | 46 | """ |
747 | 43 | 47 | ||
748 | 44 | 48 | ||
749 | 45 | 49 | ||
750 | === modified file 'bzrlib/ui/text.py' | |||
751 | --- bzrlib/ui/text.py 2009-09-23 06:29:46 +0000 | |||
752 | +++ bzrlib/ui/text.py 2009-11-27 05:14:10 +0000 | |||
753 | @@ -18,6 +18,7 @@ | |||
754 | 18 | """Text UI, write output to the console. | 18 | """Text UI, write output to the console. |
755 | 19 | """ | 19 | """ |
756 | 20 | 20 | ||
757 | 21 | import codecs | ||
758 | 21 | import getpass | 22 | import getpass |
759 | 22 | import os | 23 | import os |
760 | 23 | import sys | 24 | import sys |
761 | @@ -44,18 +45,18 @@ | |||
762 | 44 | class TextUIFactory(UIFactory): | 45 | class TextUIFactory(UIFactory): |
763 | 45 | """A UI factory for Text user interefaces.""" | 46 | """A UI factory for Text user interefaces.""" |
764 | 46 | 47 | ||
769 | 47 | def __init__(self, | 48 | def __init__(self, stdin, stdout, stderr): |
766 | 48 | stdin=None, | ||
767 | 49 | stdout=None, | ||
768 | 50 | stderr=None): | ||
770 | 51 | """Create a TextUIFactory. | 49 | """Create a TextUIFactory. |
771 | 52 | """ | 50 | """ |
772 | 53 | super(TextUIFactory, self).__init__() | 51 | super(TextUIFactory, self).__init__() |
773 | 54 | # TODO: there's no good reason not to pass all three streams, maybe we | ||
774 | 55 | # should deprecate the default values... | ||
775 | 56 | self.stdin = stdin | 52 | self.stdin = stdin |
776 | 57 | self.stdout = stdout | 53 | self.stdout = stdout |
777 | 58 | self.stderr = stderr | 54 | self.stderr = stderr |
778 | 55 | # encoding_stderr is used for data put into the terminal encoding with | ||
779 | 56 | # unrepresentable messages replaced; it should be used for non-bulk | ||
780 | 57 | # messages | ||
781 | 58 | self.message_stream = codecs.getwriter(osutils.get_terminal_encoding())( | ||
782 | 59 | self.stderr, errors='replace') | ||
783 | 59 | # paints progress, network activity, etc | 60 | # paints progress, network activity, etc |
784 | 60 | self._progress_view = self.make_progress_view() | 61 | self._progress_view = self.make_progress_view() |
785 | 61 | 62 | ||
786 | @@ -149,7 +150,9 @@ | |||
787 | 149 | def note(self, msg): | 150 | def note(self, msg): |
788 | 150 | """Write an already-formatted message, clearing the progress bar if necessary.""" | 151 | """Write an already-formatted message, clearing the progress bar if necessary.""" |
789 | 151 | self.clear_term() | 152 | self.clear_term() |
791 | 152 | self.stdout.write(msg + '\n') | 153 | self.message_stream.write(unicode(msg) + '\n') |
792 | 154 | # XXX: At the moment this accepts string-able objects, but we should | ||
793 | 155 | # deprecate that and make the caller pass unicode. | ||
794 | 153 | 156 | ||
795 | 154 | def prompt(self, prompt, **kwargs): | 157 | def prompt(self, prompt, **kwargs): |
796 | 155 | """Emit prompt on the CLI. | 158 | """Emit prompt on the CLI. |
797 | @@ -162,7 +165,7 @@ | |||
798 | 162 | prompt = prompt % kwargs | 165 | prompt = prompt % kwargs |
799 | 163 | prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace') | 166 | prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace') |
800 | 164 | self.clear_term() | 167 | self.clear_term() |
802 | 165 | self.stderr.write(prompt) | 168 | self.message_stream.write(prompt) |
803 | 166 | 169 | ||
804 | 167 | def report_transport_activity(self, transport, byte_count, direction): | 170 | def report_transport_activity(self, transport, byte_count, direction): |
805 | 168 | """Called by transports as they do IO. | 171 | """Called by transports as they do IO. |
806 | @@ -175,14 +178,15 @@ | |||
807 | 175 | 178 | ||
808 | 176 | def show_error(self, msg): | 179 | def show_error(self, msg): |
809 | 177 | self.clear_term() | 180 | self.clear_term() |
811 | 178 | self.stderr.write("bzr: error: %s\n" % msg) | 181 | self.message_stream.write("bzr: error: %s\n" % msg) |
812 | 179 | 182 | ||
813 | 180 | def show_message(self, msg): | 183 | def show_message(self, msg): |
815 | 181 | self.note(msg) | 184 | self.clear_term() |
816 | 185 | self.message_stream.write(unicode(msg) + '\n') | ||
817 | 182 | 186 | ||
818 | 183 | def show_warning(self, msg): | 187 | def show_warning(self, msg): |
819 | 184 | self.clear_term() | 188 | self.clear_term() |
821 | 185 | self.stderr.write("bzr: warning: %s\n" % msg) | 189 | self.message_stream.write("bzr: warning: %s\n" % msg) |
822 | 186 | 190 | ||
823 | 187 | def _progress_updated(self, task): | 191 | def _progress_updated(self, task): |
824 | 188 | """A task has been updated and wants to be displayed. | 192 | """A task has been updated and wants to be displayed. |
825 | 189 | 193 | ||
826 | === modified file 'doc/developers/index.txt' | |||
827 | --- doc/developers/index.txt 2009-11-18 02:09:01 +0000 | |||
828 | +++ doc/developers/index.txt 2009-11-27 05:14:10 +0000 | |||
829 | @@ -33,6 +33,7 @@ | |||
830 | 33 | 33 | ||
831 | 34 | overview | 34 | overview |
832 | 35 | integration | 35 | integration |
833 | 36 | user-interaction | ||
834 | 36 | 37 | ||
835 | 37 | * `Writing plugins for Bazaar <http://bazaar-vcs.org/WritingPlugins>`_ (web link) | 38 | * `Writing plugins for Bazaar <http://bazaar-vcs.org/WritingPlugins>`_ (web link) |
836 | 38 | 39 | ||
837 | 39 | 40 | ||
838 | === added file 'doc/developers/user-interaction.txt' | |||
839 | --- doc/developers/user-interaction.txt 1970-01-01 00:00:00 +0000 | |||
840 | +++ doc/developers/user-interaction.txt 2009-11-27 05:14:10 +0000 | |||
841 | @@ -0,0 +1,62 @@ | |||
842 | 1 | ************************************ | ||
843 | 2 | Bazaar User Interaction Architecture | ||
844 | 3 | ************************************ | ||
845 | 4 | |||
846 | 5 | Bazaar aims to provide a library that can be mated to various text and | ||
847 | 6 | graphical user interfaces, and that can be used when there is no user to | ||
848 | 7 | interact with. This document describes some patterns and standards to | ||
849 | 8 | abstract this. It's a work in progress and not all code follows this | ||
850 | 9 | standard yet. | ||
851 | 10 | |||
852 | 11 | Most interaction with the user goes through a ``UIFactory`` subclass bound | ||
853 | 12 | to the global variable ``bzrlib.ui.ui_factory``. Through this you can | ||
854 | 13 | display messages and ask for input. Data between the UIFactory and the | ||
855 | 14 | rest of the library should generally be Unicode, with the UIFactory | ||
856 | 15 | responsible for any encoding. | ||
857 | 16 | |||
858 | 17 | Some UIFactories support only a subset of operations: for example | ||
859 | 18 | non-interactive UIs may refuse to ask for input. | ||
860 | 19 | |||
861 | 20 | Plugin UIFactories might choose to subclass ``TextUIFactory`` rather than | ||
862 | 21 | the base UIFactory. Then if they don't have an implementation for a | ||
863 | 22 | particular method, it'll be done through text interaction in their | ||
864 | 23 | terminal window (if any) rather than giving an error. | ||
865 | 24 | |||
866 | 25 | In general we want to add more semantic methods to the UIFactory so that | ||
867 | 26 | non-text user interfaces can do more than just present the text that would | ||
868 | 27 | have been shown in the console. For instance, rather than just presenting | ||
869 | 28 | the string that a branch is locked, we'd prefer to have a specific method | ||
870 | 29 | advising of inability to lock, so that a GUI could offer different options | ||
871 | 30 | or a specific presentation. | ||
872 | 31 | |||
873 | 32 | We're moving towards a complete API separation between developer-oriented | ||
874 | 33 | debug messages, recorded using ``mutter``, and user-oriented messages. | ||
875 | 34 | The former can still be recorded even in graphical or non-interactive | ||
876 | 35 | programs. | ||
877 | 36 | |||
878 | 37 | Core library code has the option to synchronously show messages to the | ||
879 | 38 | user or to ask for input through eg ``get_boolean`` or ``show_message``, | ||
880 | 39 | but it should do this with care. In a GUI the user should be driving the | ||
881 | 40 | interaction, not the application. | ||
882 | 41 | |||
883 | 42 | Some core library code, such as upgrade or checkout, does some work that | ||
884 | 43 | should be reported to the user in a text-mode application, but that might | ||
885 | 44 | be shown very differently or not at all in other cases. Rather than | ||
886 | 45 | repeatedly showing messages. | ||
887 | 46 | |||
888 | 47 | A particular case of this is the ProgressTask api, where a model/view | ||
889 | 48 | separation is fairly complete. Core code obtains a ``ProgressTask`` from | ||
890 | 49 | ``ui.ui_factory.nested_progress_bar``, and then feeds it events to tell | ||
891 | 50 | how the task is progressing, with no concern for whether or how this is | ||
892 | 51 | displayed to the user. | ||
893 | 52 | |||
894 | 53 | In tests, mutter output is collected onto the test log, so that it can be | ||
895 | 54 | shown when there's a failure or inspected by code that wants to check what | ||
896 | 55 | was logged. However, this should no longer be used for inspecting user | ||
897 | 56 | output: do that by providing a custom UIFactory or using run_bzr_captured. | ||
898 | 57 | |||
899 | 58 | stdout and stderr | ||
900 | 59 | ***************** | ||
901 | 60 | |||
902 | 61 | We normally reserve stdout for bulk output data, such as diffs, logs, or | ||
903 | 62 | bundles, and put all UIFactory output onto stderr. |
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 UpgradeRecommen dedTests.
* Update some old tests from before tags were supported by default.