bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
3948.2.2
by Martin Pool
 Corrections to finishing progress bars  | 
1  | 
# Copyright (C) 2005, 2008, 2009 Canonical Ltd
 | 
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
2  | 
#
 | 
| 
1185.49.21
by John Arbash Meinel
 Refactored bzrlib/ui.py into a module with the possibility for multiple ui forms.  | 
3  | 
# 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 by
 | 
|
5  | 
# the Free Software Foundation; either version 2 of the License, or
 | 
|
6  | 
# (at your option) any later version.
 | 
|
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
7  | 
#
 | 
| 
1185.49.21
by John Arbash Meinel
 Refactored bzrlib/ui.py into a module with the possibility for multiple ui forms.  | 
8  | 
# This program is distributed in the hope that it will be useful,
 | 
9  | 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|
10  | 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|
11  | 
# GNU General Public License for more details.
 | 
|
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
12  | 
#
 | 
| 
1185.49.21
by John Arbash Meinel
 Refactored bzrlib/ui.py into a module with the possibility for multiple ui forms.  | 
13  | 
# You should have received a copy of the GNU General Public License
 | 
14  | 
# along with this program; if not, write to the Free Software
 | 
|
| 
4183.7.1
by Sabin Iacob
 update FSF mailing address  | 
15  | 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
| 
1185.49.21
by John Arbash Meinel
 Refactored bzrlib/ui.py into a module with the possibility for multiple ui forms.  | 
16  | 
|
17  | 
||
18  | 
||
19  | 
"""Text UI, write output to the console.
 | 
|
20  | 
"""
 | 
|
21  | 
||
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
22  | 
import sys  | 
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
23  | 
import time  | 
| 
3948.2.2
by Martin Pool
 Corrections to finishing progress bars  | 
24  | 
import warnings  | 
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
25  | 
|
26  | 
from bzrlib.lazy_import import lazy_import  | 
|
27  | 
lazy_import(globals(), """  | 
|
28  | 
from bzrlib import (
 | 
|
29  | 
    progress,
 | 
|
| 
2294.4.1
by Vincent Ladeuil
 Add a UIFactory.get_login method, fix tests.  | 
30  | 
    osutils,
 | 
| 
3882.8.8
by Martin Pool
 Progress and UI test cleanups  | 
31  | 
    symbol_versioning,
 | 
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
32  | 
    )
 | 
| 
3882.8.8
by Martin Pool
 Progress and UI test cleanups  | 
33  | 
|
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
34  | 
""")  | 
35  | 
||
| 
1687.1.4
by Robert Collins
 Add bzrlib.ui.ui_factory.get_boolean().  | 
36  | 
from bzrlib.ui import CLIUIFactory  | 
37  | 
||
38  | 
||
39  | 
class TextUIFactory(CLIUIFactory):  | 
|
| 
1681.1.2
by Robert Collins
 * bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which  | 
40  | 
"""A UI factory for Text user interefaces."""  | 
41  | 
||
| 
1692.3.3
by Robert Collins
 Get run_bzr in tests to always assign a new, clean ui factory.  | 
42  | 
def __init__(self,  | 
43  | 
bar_type=None,  | 
|
| 
3882.8.11
by Martin Pool
 Choose the UIFactory class depending on the terminal capabilities  | 
44  | 
stdin=None,  | 
| 
1692.3.3
by Robert Collins
 Get run_bzr in tests to always assign a new, clean ui factory.  | 
45  | 
stdout=None,  | 
46  | 
stderr=None):  | 
|
| 
1681.1.2
by Robert Collins
 * bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which  | 
47  | 
"""Create a TextUIFactory.  | 
48  | 
||
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
49  | 
        :param bar_type: The type of progress bar to create. It defaults to
 | 
| 
1681.1.2
by Robert Collins
 * bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which  | 
50  | 
                         letting the bzrlib.progress.ProgressBar factory auto
 | 
| 
3882.8.3
by Martin Pool
 Move display of transport throughput into TextProgressView  | 
51  | 
                         select.   Deprecated.
 | 
| 
1681.1.2
by Robert Collins
 * bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which  | 
52  | 
        """
 | 
| 
3882.8.11
by Martin Pool
 Choose the UIFactory class depending on the terminal capabilities  | 
53  | 
super(TextUIFactory, self).__init__(stdin=stdin,  | 
54  | 
stdout=stdout, stderr=stderr)  | 
|
| 
3882.8.6
by Martin Pool
 TextUIFactory ignores and deprecates the bar_type parameter  | 
55  | 
if bar_type:  | 
56  | 
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 11, 0))  | 
|
57  | 
% "bar_type parameter")  | 
|
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
58  | 
        # paints progress, network activity, etc
 | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
59  | 
self._progress_view = TextProgressView(self.stderr)  | 
| 
1594.1.1
by Robert Collins
 Introduce new bzr progress bar api. ui_factory.nested_progress_bar.  | 
60  | 
|
| 
1558.8.1
by Aaron Bentley
 Fix overall progress bar's interaction with 'note' and 'warning'  | 
61  | 
def clear_term(self):  | 
62  | 
"""Prepare the terminal for output.  | 
|
63  | 
||
64  | 
        This will, clear any progress bars, and leave the cursor at the
 | 
|
65  | 
        leftmost position."""
 | 
|
| 
3882.7.6
by Martin Pool
 Preliminary support for drawing network io into the progress bar  | 
66  | 
        # XXX: If this is preparing to write to stdout, but that's for example
 | 
67  | 
        # directed into a file rather than to the terminal, and the progress
 | 
|
68  | 
        # bar _is_ going to the terminal, we shouldn't need
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
69  | 
        # to clear it.  We might need to separately check for the case of
 | 
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
70  | 
self._progress_view.clear()  | 
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
71  | 
|
| 
3882.8.4
by Martin Pool
 All UI factories should support note()  | 
72  | 
def note(self, msg):  | 
73  | 
"""Write an already-formatted message, clearing the progress bar if necessary."""  | 
|
74  | 
self.clear_term()  | 
|
75  | 
self.stdout.write(msg + '\n')  | 
|
76  | 
||
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
77  | 
def report_transport_activity(self, transport, byte_count, direction):  | 
78  | 
"""Called by transports as they do IO.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
79  | 
|
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
80  | 
        This may update a progress bar, spinner, or similar display.
 | 
81  | 
        By default it does nothing.
 | 
|
82  | 
        """
 | 
|
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
83  | 
self._progress_view._show_transport_activity(transport,  | 
84  | 
direction, byte_count)  | 
|
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
85  | 
|
| 
3948.2.3
by Martin Pool
 Make the interface from ProgressTask to ui more private  | 
86  | 
def _progress_updated(self, task):  | 
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
87  | 
"""A task has been updated and wants to be displayed.  | 
88  | 
        """
 | 
|
| 
4070.1.1
by Martin Pool
 Be more robust about pb updates when none are active  | 
89  | 
if not self._task_stack:  | 
90  | 
warnings.warn("%r updated but no tasks are active" %  | 
|
91  | 
(task,))  | 
|
92  | 
elif task != self._task_stack[-1]:  | 
|
| 
3948.2.2
by Martin Pool
 Corrections to finishing progress bars  | 
93  | 
warnings.warn("%r is not the top progress task %r" %  | 
94  | 
(task, self._task_stack[-1]))  | 
|
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
95  | 
self._progress_view.show_progress(task)  | 
96  | 
||
| 
3948.2.5
by Martin Pool
 rename to _progress_all_finished  | 
97  | 
def _progress_all_finished(self):  | 
| 
3948.2.3
by Martin Pool
 Make the interface from ProgressTask to ui more private  | 
98  | 
self._progress_view.clear()  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
99  | 
|
100  | 
||
101  | 
class TextProgressView(object):  | 
|
102  | 
"""Display of progress bar and other information on a tty.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
103  | 
|
104  | 
    This shows one line of text, including possibly a network indicator, spinner,
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
105  | 
    progress bar, message, etc.
 | 
106  | 
||
107  | 
    One instance of this is created and held by the UI, and fed updates when a
 | 
|
108  | 
    task wants to be painted.
 | 
|
109  | 
||
110  | 
    Transports feed data to this through the ui_factory object.
 | 
|
| 
3948.2.2
by Martin Pool
 Corrections to finishing progress bars  | 
111  | 
|
112  | 
    The Progress views can comprise a tree with _parent_task pointers, but
 | 
|
113  | 
    this only prints the stack from the nominated current task up to the root.
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
114  | 
    """
 | 
115  | 
||
116  | 
def __init__(self, term_file):  | 
|
117  | 
self._term_file = term_file  | 
|
118  | 
        # true when there's output on the screen we may need to clear
 | 
|
119  | 
self._have_output = False  | 
|
120  | 
        # XXX: We could listen for SIGWINCH and update the terminal width...
 | 
|
121  | 
self._width = osutils.terminal_width()  | 
|
122  | 
self._last_transport_msg = ''  | 
|
123  | 
self._spin_pos = 0  | 
|
124  | 
        # time we last repainted the screen
 | 
|
125  | 
self._last_repaint = 0  | 
|
126  | 
        # time we last got information about transport activity
 | 
|
127  | 
self._transport_update_time = 0  | 
|
128  | 
self._last_task = None  | 
|
129  | 
self._total_byte_count = 0  | 
|
130  | 
self._bytes_since_update = 0  | 
|
131  | 
||
132  | 
def _show_line(self, s):  | 
|
133  | 
n = self._width - 1  | 
|
134  | 
self._term_file.write('\r%-*.*s\r' % (n, n, s))  | 
|
135  | 
||
136  | 
def clear(self):  | 
|
137  | 
if self._have_output:  | 
|
138  | 
self._show_line('')  | 
|
139  | 
self._have_output = False  | 
|
140  | 
||
141  | 
def _render_bar(self):  | 
|
142  | 
        # return a string for the progress bar itself
 | 
|
| 
4103.3.3
by Martin Pool
 Show the progress bar part when showing activity by default  | 
143  | 
if (self._last_task is None) or self._last_task.show_bar:  | 
144  | 
            # If there's no task object, we show space for the bar anyhow.
 | 
|
145  | 
            # That's because most invocations of bzr will end showing progress
 | 
|
146  | 
            # at some point, though perhaps only after doing some initial IO.
 | 
|
147  | 
            # It looks better to draw the progress bar initially rather than
 | 
|
148  | 
            # to have what looks like an incomplete progress bar.
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
149  | 
spin_str = r'/-\|'[self._spin_pos % 4]  | 
150  | 
self._spin_pos += 1  | 
|
151  | 
cols = 20  | 
|
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
152  | 
if self._last_task is None:  | 
153  | 
completion_fraction = 0  | 
|
154  | 
else:  | 
|
155  | 
completion_fraction = \  | 
|
156  | 
self._last_task._overall_completion_fraction() or 0  | 
|
| 
4110.2.15
by Martin Pool
 Fix bug in showing task progress and add a test  | 
157  | 
markers = int(round(float(cols) * completion_fraction)) - 1  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
158  | 
bar_str = '[' + ('#' * markers + spin_str).ljust(cols) + '] '  | 
159  | 
return bar_str  | 
|
| 
4103.3.3
by Martin Pool
 Show the progress bar part when showing activity by default  | 
160  | 
elif self._last_task.show_spinner:  | 
161  | 
            # The last task wanted just a spinner, no bar
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
162  | 
spin_str = r'/-\|'[self._spin_pos % 4]  | 
163  | 
self._spin_pos += 1  | 
|
164  | 
return spin_str + ' '  | 
|
165  | 
else:  | 
|
166  | 
return ''  | 
|
167  | 
||
168  | 
def _format_task(self, task):  | 
|
169  | 
if not task.show_count:  | 
|
170  | 
s = ''  | 
|
| 
4017.1.1
by John Arbash Meinel
 Get a pb.tick() to work after calling pb.update()  | 
171  | 
elif task.current_cnt is not None and task.total_cnt is not None:  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
172  | 
s = ' %d/%d' % (task.current_cnt, task.total_cnt)  | 
173  | 
elif task.current_cnt is not None:  | 
|
174  | 
s = ' %d' % (task.current_cnt)  | 
|
175  | 
else:  | 
|
176  | 
s = ''  | 
|
177  | 
        # compose all the parent messages
 | 
|
178  | 
t = task  | 
|
179  | 
m = task.msg  | 
|
180  | 
while t._parent_task:  | 
|
181  | 
t = t._parent_task  | 
|
182  | 
if t.msg:  | 
|
183  | 
m = t.msg + ':' + m  | 
|
184  | 
return m + s  | 
|
185  | 
||
| 
4110.2.16
by Martin Pool
 Refactor TextProgressView a bit and add another test  | 
186  | 
def _render_line(self):  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
187  | 
bar_string = self._render_bar()  | 
188  | 
if self._last_task:  | 
|
189  | 
task_msg = self._format_task(self._last_task)  | 
|
190  | 
else:  | 
|
191  | 
task_msg = ''  | 
|
192  | 
trans = self._last_transport_msg  | 
|
| 
4110.2.16
by Martin Pool
 Refactor TextProgressView a bit and add another test  | 
193  | 
if trans:  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
194  | 
trans += ' | '  | 
| 
4110.2.16
by Martin Pool
 Refactor TextProgressView a bit and add another test  | 
195  | 
return (bar_string + trans + task_msg)  | 
196  | 
||
197  | 
def _repaint(self):  | 
|
198  | 
s = self._render_line()  | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
199  | 
self._show_line(s)  | 
200  | 
self._have_output = True  | 
|
201  | 
||
202  | 
def show_progress(self, task):  | 
|
| 
4110.2.15
by Martin Pool
 Fix bug in showing task progress and add a test  | 
203  | 
"""Called by the task object when it has changed.  | 
204  | 
        
 | 
|
205  | 
        :param task: The top task object; its parents are also included 
 | 
|
206  | 
            by following links.
 | 
|
207  | 
        """
 | 
|
| 
4110.2.18
by Martin Pool
 Progress bars always repaint when task structure is changed  | 
208  | 
must_update = task is not self._last_task  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
209  | 
self._last_task = task  | 
210  | 
now = time.time()  | 
|
| 
4110.2.18
by Martin Pool
 Progress bars always repaint when task structure is changed  | 
211  | 
if (not must_update) and (now < self._last_repaint + 0.1):  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
212  | 
            return
 | 
| 
4110.2.15
by Martin Pool
 Fix bug in showing task progress and add a test  | 
213  | 
if now > self._transport_update_time + 10:  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
214  | 
            # no recent activity; expire it
 | 
215  | 
self._last_transport_msg = ''  | 
|
216  | 
self._last_repaint = now  | 
|
217  | 
self._repaint()  | 
|
218  | 
||
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
219  | 
def _show_transport_activity(self, transport, direction, byte_count):  | 
220  | 
"""Called by transports via the ui_factory, as they do IO.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
221  | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
222  | 
        This may update a progress bar, spinner, or similar display.
 | 
223  | 
        By default it does nothing.
 | 
|
224  | 
        """
 | 
|
225  | 
        # XXX: Probably there should be a transport activity model, and that
 | 
|
226  | 
        # too should be seen by the progress view, rather than being poked in
 | 
|
227  | 
        # here.
 | 
|
228  | 
self._total_byte_count += byte_count  | 
|
229  | 
self._bytes_since_update += byte_count  | 
|
230  | 
now = time.time()  | 
|
231  | 
if self._transport_update_time is None:  | 
|
232  | 
self._transport_update_time = now  | 
|
| 
4043.1.1
by John Arbash Meinel
 Increase the debounce time for 'transport activity' to 0.5s  | 
233  | 
elif now >= (self._transport_update_time + 0.5):  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
234  | 
            # guard against clock stepping backwards, and don't update too
 | 
235  | 
            # often
 | 
|
236  | 
rate = self._bytes_since_update / (now - self._transport_update_time)  | 
|
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
237  | 
scheme = getattr(transport, '_scheme', None) or repr(transport)  | 
238  | 
if direction == 'read':  | 
|
| 
4258.2.2
by Jelmer Vernooij
 keep the width of the progress bar the same.  | 
239  | 
dir_char = '>'  | 
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
240  | 
elif direction == 'write':  | 
| 
4258.2.2
by Jelmer Vernooij
 keep the width of the progress bar the same.  | 
241  | 
dir_char = '<'  | 
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
242  | 
else:  | 
| 
4258.2.2
by Jelmer Vernooij
 keep the width of the progress bar the same.  | 
243  | 
dir_char = ' '  | 
244  | 
msg = ("%.7s %s %6dKB %5dKB/s" %  | 
|
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
245  | 
(scheme, dir_char, self._total_byte_count>>10, int(rate)>>10,))  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
246  | 
self._transport_update_time = now  | 
247  | 
self._last_repaint = now  | 
|
248  | 
self._bytes_since_update = 0  | 
|
249  | 
self._last_transport_msg = msg  | 
|
250  | 
self._repaint()  | 
|
251  | 
||
252  |