Merge lp:~abentley/bzr/fix-terminal-spew into lp:bzr

Proposed by Aaron Bentley
Status: Merged
Merged at revision: 5310
Proposed branch: lp:~abentley/bzr/fix-terminal-spew
Merge into: lp:bzr
Diff against target: 80 lines (+21/-7)
4 files modified
NEWS (+2/-0)
bzr (+6/-3)
bzrlib/__init__.py (+7/-4)
bzrlib/ui/text.py (+6/-0)
To merge this branch: bzr merge lp:~abentley/bzr/fix-terminal-spew
Reviewer Review Type Date Requested Status
Robert Collins (community) Needs Fixing
Andrew Bennetts Needs Fixing
Review via email: mp+25233@code.launchpad.net

Commit message

Clean up progress output on exit.

Description of the change

Hi all,

This branch introduces automatic cleanup for progress output when exiting.

It accomplishes this by introducing bzrlib.clean_up, which indirectly calls
clear_term.

TextUIFactory is converted into a Context Manager, and bzrlib.clean_up will
invoke __exit__ on the ui factory, if it provides it.

Why a Context Manager, since Python 2.4 doesn't support the with statement?
Because this is a common idiom in the Python world for managing resources which
may perform actions when acquired and released, and because some bzrlib clients
are using more recent Pythons.

It turned out we were setting up a bunch of atexit entries in
bzrlib.initialize, but these are actually meant to run when bzrlib is no longer
being used, so they were moved to bzrlib.clean_up.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

Seems nice to me.

Revision history for this message
Andrew Bennetts (spiv) wrote :

Looks reasonable to me.

The only problem I see is that bzrlib.clean_up now assumes that bzrlib.ui.ui_factory has a __exit__ method. I expect that's generally true for /usr/bin/bzr, but it might not be true for other existing clients of bzrlib (including loggerhead, perhaps?). So I think you should 1) document this new requirement of UIFactory objects in NEWS as an API Change, and 2) add empty implementations to the UIFactory base class.

(I'm voting "Needs Fixing" in the bb:tweak sense.)

review: Needs Fixing
Revision history for this message
Alexander Belchenko (bialix) wrote :

IIRC, ContextManager is for Python 2.5 and later?

Revision history for this message
Andrew Bennetts (spiv) wrote :

Alexander Belchenko wrote:
> IIRC, ContextManager is for Python 2.5 and later?

The 'with' statement is for Python 2.5 or later. There's nothing that
prevents us from creating objects with __enter__ and __exit__ methods in
Python 2.4. Obviously Python 2.4 can't use those objects in 'with'
statements, but it can call the methods directly as Aaron does in this
patch.

Revision history for this message
Martin Packman (gz) wrote :

The _flush_stdout_stderr and _flush_trace functions in bzrlib.trace both have comments at the top stating they'll be run from atexit, should be changed if it's going to no longer be the case.

This change effectively moves the ui teardown to an earlier point, will that cause issues with messages being printed on object destruction?

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

Martin[gz] - side note, if you find something that should be changed, please do vote 'needs fixing' rather than a simple comment - the votes are usually instructive when looking at a proposal.

I actually have a deeper question - rather than having a library 'clean up' function, what about having bzrlib.initialize return something that can be used to clean up ? This would solve a bug in this proposal - calling cleanup() when initialize hasn't been called, or initialize then cleanup twice will fail because ui_factory will be None, so getting to the exit function is impossible :)

e.g.
if __name__ == '__main__':
- bzrlib.initialize()
+ clean_up = bzrlib.initialize()
- exit_val = bzrlib.commands.main()
+ try:
+ exit_val = bzrlib.commands.main()

- if profiling:
- profile_imports.log_stack_info(sys.stderr)
+ if profiling:
+ profile_imports.log_stack_info(sys.stderr)
+ finally:
+ clean_up()

I agree with the things that Martin[gz] noted too, so marking Needs Fixing. Aaron - totally up to you if you want to change it to be something returned from initialize: I think that might be better in the long run - taking us away from globals, but its up to you.

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

I'm polishing - see my fix-terminal-spew branch.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-05-11 17:22:12 +0000
3+++ NEWS 2010-05-13 13:30:47 +0000
4@@ -97,6 +97,8 @@
5 history is being copied.
6 (Parth Malwankar, #538868)
7
8+* Progress output is cleaned up when exiting. (Aaron Bentley)
9+
10 * Reduce peak memory by one copy of compressed text.
11 (John Arbash Meinel, #566940)
12
13
14=== modified file 'bzr'
15--- bzr 2010-04-23 08:51:52 +0000
16+++ bzr 2010-05-13 13:30:47 +0000
17@@ -136,10 +136,13 @@
18
19 if __name__ == '__main__':
20 bzrlib.initialize()
21- exit_val = bzrlib.commands.main()
22+ try:
23+ exit_val = bzrlib.commands.main()
24
25- if profiling:
26- profile_imports.log_stack_info(sys.stderr)
27+ if profiling:
28+ profile_imports.log_stack_info(sys.stderr)
29+ finally:
30+ bzrlib.clean_up()
31
32 # By this point we really have completed everything we want to do, and
33 # there's no point doing any additional cleanup. Abruptly exiting here
34
35=== modified file 'bzrlib/__init__.py'
36--- bzrlib/__init__.py 2010-04-22 10:20:40 +0000
37+++ bzrlib/__init__.py 2010-05-13 13:30:47 +0000
38@@ -142,12 +142,9 @@
39 # in-process run_bzr calls. If it's broken, we expect that
40 # TestRunBzrSubprocess may fail.
41
42- import atexit
43 import bzrlib.trace
44
45 bzrlib.trace.enable_default_logging()
46- atexit.register(bzrlib.trace._flush_stdout_stderr)
47- atexit.register(bzrlib.trace._flush_trace)
48
49 import bzrlib.ui
50 if stdin is None:
51@@ -165,5 +162,11 @@
52 from bzrlib.symbol_versioning import suppress_deprecation_warnings
53 suppress_deprecation_warnings(override=True)
54
55+def clean_up():
56+ import bzrlib.ui
57+ bzrlib.trace._flush_stdout_stderr()
58+ bzrlib.trace._flush_trace()
59 import bzrlib.osutils
60- atexit.register(osutils.report_extension_load_failures)
61+ bzrlib.osutils.report_extension_load_failures()
62+ bzrlib.ui.ui_factory.__exit__(None, None, None)
63+ bzrlib.ui.ui_factory = None
64
65=== modified file 'bzrlib/ui/text.py'
66--- bzrlib/ui/text.py 2010-04-22 16:04:16 +0000
67+++ bzrlib/ui/text.py 2010-05-13 13:30:47 +0000
68@@ -65,6 +65,12 @@
69 # hook up the signals to watch for terminal size changes
70 watch_sigwinch()
71
72+ def __enter__(self):
73+ pass
74+
75+ def __exit__(self, exc_type, exc_val, exc_tb):
76+ self.clear_term()
77+
78 def be_quiet(self, state):
79 if state and not self._quiet:
80 self.clear_term()