bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
4988.10.3
by John Arbash Meinel
 Merge bzr.dev 5007, resolve conflict, update NEWS  | 
1  | 
# Copyright (C) 2005-2010 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  | 
"""Text UI, write output to the console.
 | 
|
19  | 
"""
 | 
|
20  | 
||
| 
4792.8.2
by Martin Pool
 New method ui_factory.make_output_stream  | 
21  | 
import codecs  | 
| 
4566.1.1
by John Arbash Meinel
 Fix a fairly critical bug where TextUIFactory.get_non_echoed_password was failing.  | 
22  | 
import getpass  | 
| 
4449.2.1
by Martin Pool
 TextUIFactory now respects BZR_PROGRESS_BAR again  | 
23  | 
import os  | 
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
24  | 
import sys  | 
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
25  | 
import time  | 
| 
3948.2.2
by Martin Pool
 Corrections to finishing progress bars  | 
26  | 
import warnings  | 
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
27  | 
|
28  | 
from bzrlib.lazy_import import lazy_import  | 
|
29  | 
lazy_import(globals(), """  | 
|
30  | 
from bzrlib import (
 | 
|
| 
4332.3.18
by Robert Collins
 Add -Dprogress to assist in debugging progress bar jumping.  | 
31  | 
    debug,
 | 
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
32  | 
    progress,
 | 
| 
2294.4.1
by Vincent Ladeuil
 Add a UIFactory.get_login method, fix tests.  | 
33  | 
    osutils,
 | 
| 
3882.8.8
by Martin Pool
 Progress and UI test cleanups  | 
34  | 
    symbol_versioning,
 | 
| 
4906.1.1
by John Arbash Meinel
 Basic implementation of logging bytes transferred when bzr exits.  | 
35  | 
    trace,
 | 
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
36  | 
    )
 | 
| 
3882.8.8
by Martin Pool
 Progress and UI test cleanups  | 
37  | 
|
| 
1996.3.27
by John Arbash Meinel
 lazy import getpass in bzrlib.ui.text  | 
38  | 
""")  | 
39  | 
||
| 
4449.3.15
by Martin Pool
 Move NullProgressView and make_progress_view up to UIFactory base class  | 
40  | 
from bzrlib.ui import (  | 
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
41  | 
UIFactory,  | 
| 
4449.3.15
by Martin Pool
 Move NullProgressView and make_progress_view up to UIFactory base class  | 
42  | 
NullProgressView,  | 
43  | 
    )
 | 
|
| 
1687.1.4
by Robert Collins
 Add bzrlib.ui.ui_factory.get_boolean().  | 
44  | 
|
45  | 
||
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
46  | 
class TextUIFactory(UIFactory):  | 
| 
1681.1.2
by Robert Collins
 * bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which  | 
47  | 
"""A UI factory for Text user interefaces."""  | 
48  | 
||
| 
1692.3.3
by Robert Collins
 Get run_bzr in tests to always assign a new, clean ui factory.  | 
49  | 
def __init__(self,  | 
| 
3882.8.11
by Martin Pool
 Choose the UIFactory class depending on the terminal capabilities  | 
50  | 
stdin=None,  | 
| 
1692.3.3
by Robert Collins
 Get run_bzr in tests to always assign a new, clean ui factory.  | 
51  | 
stdout=None,  | 
52  | 
stderr=None):  | 
|
| 
1681.1.2
by Robert Collins
 * bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which  | 
53  | 
"""Create a TextUIFactory.  | 
54  | 
        """
 | 
|
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
55  | 
super(TextUIFactory, self).__init__()  | 
| 
4449.3.28
by Martin Pool
 todo  | 
56  | 
        # TODO: there's no good reason not to pass all three streams, maybe we
 | 
57  | 
        # should deprecate the default values...
 | 
|
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
58  | 
self.stdin = stdin  | 
59  | 
self.stdout = stdout  | 
|
60  | 
self.stderr = stderr  | 
|
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
61  | 
        # paints progress, network activity, etc
 | 
| 
4449.3.15
by Martin Pool
 Move NullProgressView and make_progress_view up to UIFactory base class  | 
62  | 
self._progress_view = self.make_progress_view()  | 
| 
4449.2.1
by Martin Pool
 TextUIFactory now respects BZR_PROGRESS_BAR again  | 
63  | 
|
| 
4961.1.2
by Martin Pool
 quietness-state is now tracked on UIFactory  | 
64  | 
def be_quiet(self, state):  | 
65  | 
if state and not self._quiet:  | 
|
66  | 
self.clear_term()  | 
|
67  | 
UIFactory.be_quiet(self, state)  | 
|
| 
4961.1.3
by Martin Pool
 trace quietness now controls whether the progress bar appears  | 
68  | 
self._progress_view = self.make_progress_view()  | 
| 
4961.1.2
by Martin Pool
 quietness-state is now tracked on UIFactory  | 
69  | 
|
| 
1558.8.1
by Aaron Bentley
 Fix overall progress bar's interaction with 'note' and 'warning'  | 
70  | 
def clear_term(self):  | 
71  | 
"""Prepare the terminal for output.  | 
|
72  | 
||
73  | 
        This will, clear any progress bars, and leave the cursor at the
 | 
|
74  | 
        leftmost position."""
 | 
|
| 
3882.7.6
by Martin Pool
 Preliminary support for drawing network io into the progress bar  | 
75  | 
        # XXX: If this is preparing to write to stdout, but that's for example
 | 
76  | 
        # directed into a file rather than to the terminal, and the progress
 | 
|
77  | 
        # bar _is_ going to the terminal, we shouldn't need
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
78  | 
        # 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  | 
79  | 
self._progress_view.clear()  | 
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
80  | 
|
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
81  | 
def get_boolean(self, prompt):  | 
82  | 
while True:  | 
|
83  | 
self.prompt(prompt + "? [y/n]: ")  | 
|
| 
4449.3.37
by Martin Pool
 TextUIFactory should cope with EOF when in get_boolean  | 
84  | 
line = self.stdin.readline().lower()  | 
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
85  | 
if line in ('y\n', 'yes\n'):  | 
86  | 
return True  | 
|
| 
4449.3.37
by Martin Pool
 TextUIFactory should cope with EOF when in get_boolean  | 
87  | 
elif line in ('n\n', 'no\n'):  | 
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
88  | 
return False  | 
| 
4449.3.37
by Martin Pool
 TextUIFactory should cope with EOF when in get_boolean  | 
89  | 
elif line in ('', None):  | 
90  | 
                # end-of-file; possibly should raise an error here instead
 | 
|
91  | 
return None  | 
|
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
92  | 
|
| 
4597.3.37
by Vincent Ladeuil
 Allows ui factories to query users for an integer.  | 
93  | 
def get_integer(self, prompt):  | 
94  | 
while True:  | 
|
95  | 
self.prompt(prompt)  | 
|
96  | 
line = self.stdin.readline()  | 
|
97  | 
try:  | 
|
98  | 
return int(line)  | 
|
99  | 
except ValueError:  | 
|
100  | 
                pass
 | 
|
101  | 
||
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
102  | 
def get_non_echoed_password(self):  | 
103  | 
isatty = getattr(self.stdin, 'isatty', None)  | 
|
104  | 
if isatty is not None and isatty():  | 
|
105  | 
            # getpass() ensure the password is not echoed and other
 | 
|
106  | 
            # cross-platform niceties
 | 
|
107  | 
password = getpass.getpass('')  | 
|
108  | 
else:  | 
|
109  | 
            # echo doesn't make sense without a terminal
 | 
|
110  | 
password = self.stdin.readline()  | 
|
111  | 
if not password:  | 
|
112  | 
password = None  | 
|
113  | 
elif password[-1] == '\n':  | 
|
114  | 
password = password[:-1]  | 
|
115  | 
return password  | 
|
116  | 
||
117  | 
def get_password(self, prompt='', **kwargs):  | 
|
118  | 
"""Prompt the user for a password.  | 
|
119  | 
||
120  | 
        :param prompt: The prompt to present the user
 | 
|
121  | 
        :param kwargs: Arguments which will be expanded into the prompt.
 | 
|
122  | 
                       This lets front ends display different things if
 | 
|
123  | 
                       they so choose.
 | 
|
124  | 
        :return: The password string, return None if the user
 | 
|
125  | 
                 canceled the request.
 | 
|
126  | 
        """
 | 
|
127  | 
prompt += ': '  | 
|
128  | 
self.prompt(prompt, **kwargs)  | 
|
129  | 
        # There's currently no way to say 'i decline to enter a password'
 | 
|
130  | 
        # as opposed to 'my password is empty' -- does it matter?
 | 
|
131  | 
return self.get_non_echoed_password()  | 
|
132  | 
||
133  | 
def get_username(self, prompt, **kwargs):  | 
|
134  | 
"""Prompt the user for a username.  | 
|
135  | 
||
136  | 
        :param prompt: The prompt to present the user
 | 
|
137  | 
        :param kwargs: Arguments which will be expanded into the prompt.
 | 
|
138  | 
                       This lets front ends display different things if
 | 
|
139  | 
                       they so choose.
 | 
|
140  | 
        :return: The username string, return None if the user
 | 
|
141  | 
                 canceled the request.
 | 
|
142  | 
        """
 | 
|
143  | 
prompt += ': '  | 
|
144  | 
self.prompt(prompt, **kwargs)  | 
|
145  | 
username = self.stdin.readline()  | 
|
146  | 
if not username:  | 
|
147  | 
username = None  | 
|
148  | 
elif username[-1] == '\n':  | 
|
149  | 
username = username[:-1]  | 
|
150  | 
return username  | 
|
151  | 
||
| 
4449.3.15
by Martin Pool
 Move NullProgressView and make_progress_view up to UIFactory base class  | 
152  | 
def make_progress_view(self):  | 
153  | 
"""Construct and return a new ProgressView subclass for this UI.  | 
|
154  | 
        """
 | 
|
| 
4961.1.2
by Martin Pool
 quietness-state is now tracked on UIFactory  | 
155  | 
        # with --quiet, never any progress view
 | 
156  | 
        # <https://bugs.edge.launchpad.net/bzr/+bug/320035>.  Otherwise if the
 | 
|
157  | 
        # user specifically requests either text or no progress bars, always
 | 
|
158  | 
        # do that.  otherwise, guess based on $TERM and tty presence.
 | 
|
159  | 
if self.is_quiet():  | 
|
160  | 
return NullProgressView()  | 
|
161  | 
elif os.environ.get('BZR_PROGRESS_BAR') == 'text':  | 
|
| 
4449.3.15
by Martin Pool
 Move NullProgressView and make_progress_view up to UIFactory base class  | 
162  | 
return TextProgressView(self.stderr)  | 
163  | 
elif os.environ.get('BZR_PROGRESS_BAR') == 'none':  | 
|
164  | 
return NullProgressView()  | 
|
165  | 
elif progress._supports_progress(self.stderr):  | 
|
| 
4449.2.1
by Martin Pool
 TextUIFactory now respects BZR_PROGRESS_BAR again  | 
166  | 
return TextProgressView(self.stderr)  | 
167  | 
else:  | 
|
168  | 
return NullProgressView()  | 
|
169  | 
||
| 
4792.8.5
by Martin Pool
 Support encoding_type=exact for make_output_stream  | 
170  | 
def _make_output_stream_explicit(self, encoding, encoding_type):  | 
171  | 
if encoding_type == 'exact':  | 
|
172  | 
            # force sys.stdout to be binary stream on win32; 
 | 
|
173  | 
            # NB: this leaves the file set in that mode; may cause problems if
 | 
|
174  | 
            # one process tries to do binary and then text output
 | 
|
175  | 
if sys.platform == 'win32':  | 
|
176  | 
fileno = getattr(self.stdout, 'fileno', None)  | 
|
177  | 
if fileno:  | 
|
178  | 
import msvcrt  | 
|
179  | 
msvcrt.setmode(fileno(), os.O_BINARY)  | 
|
180  | 
return TextUIOutputStream(self, self.stdout)  | 
|
181  | 
else:  | 
|
182  | 
encoded_stdout = codecs.getwriter(encoding)(self.stdout,  | 
|
183  | 
errors=encoding_type)  | 
|
| 
4792.8.10
by Martin Pool
 Put tweaks to codecs.getwriter encoding into the place it's created  | 
184  | 
            # For whatever reason codecs.getwriter() does not advertise its encoding
 | 
185  | 
            # it just returns the encoding of the wrapped file, which is completely
 | 
|
186  | 
            # bogus. So set the attribute, so we can find the correct encoding later.
 | 
|
187  | 
encoded_stdout.encoding = encoding  | 
|
| 
4792.8.5
by Martin Pool
 Support encoding_type=exact for make_output_stream  | 
188  | 
return TextUIOutputStream(self, encoded_stdout)  | 
| 
4792.8.2
by Martin Pool
 New method ui_factory.make_output_stream  | 
189  | 
|
| 
3882.8.4
by Martin Pool
 All UI factories should support note()  | 
190  | 
def note(self, msg):  | 
191  | 
"""Write an already-formatted message, clearing the progress bar if necessary."""  | 
|
192  | 
self.clear_term()  | 
|
193  | 
self.stdout.write(msg + '\n')  | 
|
194  | 
||
| 
4449.3.18
by Martin Pool
 Fuse CLIUIFactory and TextUIFactory and deprecate the old name  | 
195  | 
def prompt(self, prompt, **kwargs):  | 
196  | 
"""Emit prompt on the CLI.  | 
|
197  | 
        
 | 
|
198  | 
        :param kwargs: Dictionary of arguments to insert into the prompt,
 | 
|
199  | 
            to allow UIs to reformat the prompt.
 | 
|
200  | 
        """
 | 
|
201  | 
if kwargs:  | 
|
202  | 
            # See <https://launchpad.net/bugs/365891>
 | 
|
203  | 
prompt = prompt % kwargs  | 
|
204  | 
prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace')  | 
|
205  | 
self.clear_term()  | 
|
206  | 
self.stderr.write(prompt)  | 
|
207  | 
||
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
208  | 
def report_transport_activity(self, transport, byte_count, direction):  | 
209  | 
"""Called by transports as they do IO.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
210  | 
|
| 
3882.7.5
by Martin Pool
 Further mockup of transport-based activity indicator.  | 
211  | 
        This may update a progress bar, spinner, or similar display.
 | 
212  | 
        By default it does nothing.
 | 
|
213  | 
        """
 | 
|
| 
4449.2.1
by Martin Pool
 TextUIFactory now respects BZR_PROGRESS_BAR again  | 
214  | 
self._progress_view.show_transport_activity(transport,  | 
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
215  | 
direction, byte_count)  | 
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
216  | 
|
| 
4906.1.1
by John Arbash Meinel
 Basic implementation of logging bytes transferred when bzr exits.  | 
217  | 
def log_transport_activity(self, display=False):  | 
218  | 
"""See UIFactory.log_transport_activity()"""  | 
|
219  | 
log = getattr(self._progress_view, 'log_transport_activity', None)  | 
|
220  | 
if log is not None:  | 
|
221  | 
log(display=display)  | 
|
222  | 
||
| 
4711.1.7
by Martin Pool
 Add UIFactory.show_error, show_warning, show_message  | 
223  | 
def show_error(self, msg):  | 
224  | 
self.clear_term()  | 
|
225  | 
self.stderr.write("bzr: error: %s\n" % msg)  | 
|
226  | 
||
| 
4711.1.8
by Martin Pool
 Add show_warning and show_message tests and implementations  | 
227  | 
def show_message(self, msg):  | 
228  | 
self.note(msg)  | 
|
229  | 
||
230  | 
def show_warning(self, msg):  | 
|
231  | 
self.clear_term()  | 
|
232  | 
self.stderr.write("bzr: warning: %s\n" % msg)  | 
|
233  | 
||
| 
3948.2.3
by Martin Pool
 Make the interface from ProgressTask to ui more private  | 
234  | 
def _progress_updated(self, task):  | 
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
235  | 
"""A task has been updated and wants to be displayed.  | 
236  | 
        """
 | 
|
| 
4070.1.1
by Martin Pool
 Be more robust about pb updates when none are active  | 
237  | 
if not self._task_stack:  | 
238  | 
warnings.warn("%r updated but no tasks are active" %  | 
|
239  | 
(task,))  | 
|
240  | 
elif task != self._task_stack[-1]:  | 
|
| 
4961.2.19
by Martin Pool
 Suppress un-helpful warning about progress task ordering  | 
241  | 
            # We used to check it was the top task, but it's hard to always
 | 
242  | 
            # get this right and it's not necessarily useful: any actual
 | 
|
243  | 
            # problems will be evident in use
 | 
|
244  | 
            #warnings.warn("%r is not the top progress task %r" %
 | 
|
245  | 
            #     (task, self._task_stack[-1]))
 | 
|
246  | 
            pass
 | 
|
| 
3882.7.7
by Martin Pool
 Change progress bars to a more MVC style  | 
247  | 
self._progress_view.show_progress(task)  | 
248  | 
||
| 
3948.2.5
by Martin Pool
 rename to _progress_all_finished  | 
249  | 
def _progress_all_finished(self):  | 
| 
3948.2.3
by Martin Pool
 Make the interface from ProgressTask to ui more private  | 
250  | 
self._progress_view.clear()  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
251  | 
|
252  | 
||
253  | 
class TextProgressView(object):  | 
|
254  | 
"""Display of progress bar and other information on a tty.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
255  | 
|
256  | 
    This shows one line of text, including possibly a network indicator, spinner,
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
257  | 
    progress bar, message, etc.
 | 
258  | 
||
259  | 
    One instance of this is created and held by the UI, and fed updates when a
 | 
|
260  | 
    task wants to be painted.
 | 
|
261  | 
||
262  | 
    Transports feed data to this through the ui_factory object.
 | 
|
| 
3948.2.2
by Martin Pool
 Corrections to finishing progress bars  | 
263  | 
|
264  | 
    The Progress views can comprise a tree with _parent_task pointers, but
 | 
|
265  | 
    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  | 
266  | 
    """
 | 
267  | 
||
268  | 
def __init__(self, term_file):  | 
|
269  | 
self._term_file = term_file  | 
|
270  | 
        # true when there's output on the screen we may need to clear
 | 
|
271  | 
self._have_output = False  | 
|
272  | 
self._last_transport_msg = ''  | 
|
273  | 
self._spin_pos = 0  | 
|
274  | 
        # time we last repainted the screen
 | 
|
275  | 
self._last_repaint = 0  | 
|
276  | 
        # time we last got information about transport activity
 | 
|
277  | 
self._transport_update_time = 0  | 
|
278  | 
self._last_task = None  | 
|
279  | 
self._total_byte_count = 0  | 
|
280  | 
self._bytes_since_update = 0  | 
|
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
281  | 
self._bytes_by_direction = {'unknown': 0, 'read': 0, 'write': 0}  | 
| 
4906.1.5
by John Arbash Meinel
 Include the KiB/s for the transfer.  | 
282  | 
self._first_byte_time = None  | 
| 
4332.3.18
by Robert Collins
 Add -Dprogress to assist in debugging progress bar jumping.  | 
283  | 
self._fraction = 0  | 
| 
4880.2.1
by Martin Pool
 Text progress view is now only a spinner not a bar.  | 
284  | 
        # force the progress bar to be off, as at the moment it doesn't 
 | 
285  | 
        # correspond reliably to overall command progress
 | 
|
286  | 
self.enable_bar = False  | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
287  | 
|
288  | 
def _show_line(self, s):  | 
|
| 
4580.3.1
by Martin Pool
 ProgressTasks can specify an update latency  | 
289  | 
        # sys.stderr.write("progress %r\n" % s)
 | 
| 
4747.5.2
by Vincent Ladeuil
 Cleanup and NEWS entry.  | 
290  | 
width = osutils.terminal_width()  | 
291  | 
if width is not None:  | 
|
292  | 
            # we need one extra space for terminals that wrap on last char
 | 
|
293  | 
width = width - 1  | 
|
294  | 
s = '%-*.*s' % (width, width, s)  | 
|
| 
4747.3.6
by Vincent Ladeuil
 terminal_width can now returns None.  | 
295  | 
self._term_file.write('\r' + s + '\r')  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
296  | 
|
297  | 
def clear(self):  | 
|
298  | 
if self._have_output:  | 
|
299  | 
self._show_line('')  | 
|
300  | 
self._have_output = False  | 
|
301  | 
||
302  | 
def _render_bar(self):  | 
|
303  | 
        # return a string for the progress bar itself
 | 
|
| 
4880.2.1
by Martin Pool
 Text progress view is now only a spinner not a bar.  | 
304  | 
if self.enable_bar and (  | 
305  | 
(self._last_task is None) or self._last_task.show_bar):  | 
|
| 
4103.3.3
by Martin Pool
 Show the progress bar part when showing activity by default  | 
306  | 
            # If there's no task object, we show space for the bar anyhow.
 | 
307  | 
            # That's because most invocations of bzr will end showing progress
 | 
|
308  | 
            # at some point, though perhaps only after doing some initial IO.
 | 
|
309  | 
            # It looks better to draw the progress bar initially rather than
 | 
|
310  | 
            # to have what looks like an incomplete progress bar.
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
311  | 
spin_str = r'/-\|'[self._spin_pos % 4]  | 
312  | 
self._spin_pos += 1  | 
|
313  | 
cols = 20  | 
|
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
314  | 
if self._last_task is None:  | 
315  | 
completion_fraction = 0  | 
|
| 
4332.3.18
by Robert Collins
 Add -Dprogress to assist in debugging progress bar jumping.  | 
316  | 
self._fraction = 0  | 
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
317  | 
else:  | 
318  | 
completion_fraction = \  | 
|
319  | 
self._last_task._overall_completion_fraction() or 0  | 
|
| 
4332.3.18
by Robert Collins
 Add -Dprogress to assist in debugging progress bar jumping.  | 
320  | 
if (completion_fraction < self._fraction and 'progress' in  | 
321  | 
debug.debug_flags):  | 
|
322  | 
import pdb;pdb.set_trace()  | 
|
323  | 
self._fraction = completion_fraction  | 
|
| 
4110.2.15
by Martin Pool
 Fix bug in showing task progress and add a test  | 
324  | 
markers = int(round(float(cols) * completion_fraction)) - 1  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
325  | 
bar_str = '[' + ('#' * markers + spin_str).ljust(cols) + '] '  | 
326  | 
return bar_str  | 
|
| 
4912.1.1
by Martin Pool
 Transport activity indicator is now shown even if there's no pb  | 
327  | 
elif (self._last_task is None) or self._last_task.show_spinner:  | 
| 
4103.3.3
by Martin Pool
 Show the progress bar part when showing activity by default  | 
328  | 
            # The last task wanted just a spinner, no bar
 | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
329  | 
spin_str = r'/-\|'[self._spin_pos % 4]  | 
330  | 
self._spin_pos += 1  | 
|
331  | 
return spin_str + ' '  | 
|
332  | 
else:  | 
|
333  | 
return ''  | 
|
334  | 
||
335  | 
def _format_task(self, task):  | 
|
336  | 
if not task.show_count:  | 
|
337  | 
s = ''  | 
|
| 
4017.1.1
by John Arbash Meinel
 Get a pb.tick() to work after calling pb.update()  | 
338  | 
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  | 
339  | 
s = ' %d/%d' % (task.current_cnt, task.total_cnt)  | 
340  | 
elif task.current_cnt is not None:  | 
|
341  | 
s = ' %d' % (task.current_cnt)  | 
|
342  | 
else:  | 
|
343  | 
s = ''  | 
|
344  | 
        # compose all the parent messages
 | 
|
345  | 
t = task  | 
|
346  | 
m = task.msg  | 
|
347  | 
while t._parent_task:  | 
|
348  | 
t = t._parent_task  | 
|
349  | 
if t.msg:  | 
|
350  | 
m = t.msg + ':' + m  | 
|
351  | 
return m + s  | 
|
352  | 
||
| 
4110.2.16
by Martin Pool
 Refactor TextProgressView a bit and add another test  | 
353  | 
def _render_line(self):  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
354  | 
bar_string = self._render_bar()  | 
355  | 
if self._last_task:  | 
|
356  | 
task_msg = self._format_task(self._last_task)  | 
|
357  | 
else:  | 
|
358  | 
task_msg = ''  | 
|
| 
4580.3.5
by Martin Pool
 selftest sets ProgressTask.show_transport_activity off  | 
359  | 
if self._last_task and not self._last_task.show_transport_activity:  | 
360  | 
trans = ''  | 
|
361  | 
else:  | 
|
362  | 
trans = self._last_transport_msg  | 
|
363  | 
if trans:  | 
|
364  | 
trans += ' | '  | 
|
| 
4110.2.16
by Martin Pool
 Refactor TextProgressView a bit and add another test  | 
365  | 
return (bar_string + trans + task_msg)  | 
366  | 
||
367  | 
def _repaint(self):  | 
|
368  | 
s = self._render_line()  | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
369  | 
self._show_line(s)  | 
370  | 
self._have_output = True  | 
|
371  | 
||
372  | 
def show_progress(self, task):  | 
|
| 
4110.2.15
by Martin Pool
 Fix bug in showing task progress and add a test  | 
373  | 
"""Called by the task object when it has changed.  | 
374  | 
        
 | 
|
375  | 
        :param task: The top task object; its parents are also included 
 | 
|
376  | 
            by following links.
 | 
|
377  | 
        """
 | 
|
| 
4110.2.18
by Martin Pool
 Progress bars always repaint when task structure is changed  | 
378  | 
must_update = task is not self._last_task  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
379  | 
self._last_task = task  | 
380  | 
now = time.time()  | 
|
| 
4580.3.1
by Martin Pool
 ProgressTasks can specify an update latency  | 
381  | 
if (not must_update) and (now < self._last_repaint + task.update_latency):  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
382  | 
            return
 | 
| 
4110.2.15
by Martin Pool
 Fix bug in showing task progress and add a test  | 
383  | 
if now > self._transport_update_time + 10:  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
384  | 
            # no recent activity; expire it
 | 
385  | 
self._last_transport_msg = ''  | 
|
386  | 
self._last_repaint = now  | 
|
387  | 
self._repaint()  | 
|
388  | 
||
| 
4449.2.1
by Martin Pool
 TextUIFactory now respects BZR_PROGRESS_BAR again  | 
389  | 
def show_transport_activity(self, transport, direction, byte_count):  | 
| 
4110.2.19
by Martin Pool
 Transport activity now shows scheme and direction  | 
390  | 
"""Called by transports via the ui_factory, as they do IO.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
391  | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
392  | 
        This may update a progress bar, spinner, or similar display.
 | 
393  | 
        By default it does nothing.
 | 
|
394  | 
        """
 | 
|
| 
4906.1.8
by John Arbash Meinel
 Merge bzr.dev, resolve conflicts.  | 
395  | 
        # XXX: there should be a transport activity model, and that too should
 | 
396  | 
        #      be seen by the progress view, rather than being poked in here.
 | 
|
| 
4906.1.2
by John Arbash Meinel
 Get the basic interface tested.  | 
397  | 
self._total_byte_count += byte_count  | 
398  | 
self._bytes_since_update += byte_count  | 
|
| 
4906.1.5
by John Arbash Meinel
 Include the KiB/s for the transfer.  | 
399  | 
if self._first_byte_time is None:  | 
400  | 
            # Note that this isn't great, as technically it should be the time
 | 
|
401  | 
            # when the bytes started transferring, not when they completed.
 | 
|
402  | 
            # However, we usually start with a small request anyway.
 | 
|
403  | 
self._first_byte_time = time.time()  | 
|
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
404  | 
if direction in self._bytes_by_direction:  | 
405  | 
self._bytes_by_direction[direction] += byte_count  | 
|
406  | 
else:  | 
|
407  | 
self._bytes_by_direction['unknown'] += byte_count  | 
|
| 
4912.1.4
by Martin Pool
 Rename to -Dno_activity; incidentally fixes ReST syntax error  | 
408  | 
if 'no_activity' in debug.debug_flags:  | 
| 
4912.1.1
by Martin Pool
 Transport activity indicator is now shown even if there's no pb  | 
409  | 
            # Can be used as a workaround if
 | 
410  | 
            # <https://launchpad.net/bugs/321935> reappears and transport
 | 
|
411  | 
            # activity is cluttering other output.  However, thanks to
 | 
|
412  | 
            # TextUIOutputStream this shouldn't be a problem any more.
 | 
|
| 
4480.1.1
by Martin Pool
 (mbp) only show transport activity when progress is already visible  | 
413  | 
            return
 | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
414  | 
now = time.time()  | 
| 
4912.1.3
by Martin Pool
 Revert: don't show transport activity til some data has been sent.  | 
415  | 
if self._total_byte_count < 2000:  | 
416  | 
            # a little resistance at first, so it doesn't stay stuck at 0
 | 
|
417  | 
            # while connecting...
 | 
|
418  | 
            return
 | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
419  | 
if self._transport_update_time is None:  | 
420  | 
self._transport_update_time = now  | 
|
| 
4043.1.1
by John Arbash Meinel
 Increase the debounce time for 'transport activity' to 0.5s  | 
421  | 
elif now >= (self._transport_update_time + 0.5):  | 
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
422  | 
            # guard against clock stepping backwards, and don't update too
 | 
423  | 
            # often
 | 
|
| 
4989.1.6
by Vincent Ladeuil
 Add comments and update HACKING.txt about which units should be used.  | 
424  | 
rate = (self._bytes_since_update  | 
425  | 
/ (now - self._transport_update_time))  | 
|
426  | 
            # using base-10 units (see HACKING.txt).
 | 
|
| 
4989.1.1
by Gordon Tyler
 Changed show_transport_activity and log_transport_activity to use base-10 SI units.  | 
427  | 
msg = ("%6dkB %5dkB/s" %  | 
428  | 
(self._total_byte_count / 1000, int(rate) / 1000,))  | 
|
| 
3882.8.9
by Martin Pool
 Move TextProgressView to ui.text  | 
429  | 
self._transport_update_time = now  | 
430  | 
self._last_repaint = now  | 
|
431  | 
self._bytes_since_update = 0  | 
|
432  | 
self._last_transport_msg = msg  | 
|
433  | 
self._repaint()  | 
|
| 
4792.8.1
by Martin Pool
 Add TextUIOutputStream coordinated with progress view  | 
434  | 
|
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
435  | 
def _format_bytes_by_direction(self):  | 
| 
4906.1.5
by John Arbash Meinel
 Include the KiB/s for the transfer.  | 
436  | 
if self._first_byte_time is None:  | 
437  | 
bps = 0.0  | 
|
438  | 
else:  | 
|
439  | 
transfer_time = time.time() - self._first_byte_time  | 
|
440  | 
if transfer_time < 0.001:  | 
|
441  | 
transfer_time = 0.001  | 
|
442  | 
bps = self._total_byte_count / transfer_time  | 
|
443  | 
||
| 
4989.1.6
by Vincent Ladeuil
 Add comments and update HACKING.txt about which units should be used.  | 
444  | 
        # using base-10 units (see HACKING.txt).
 | 
| 
4989.1.1
by Gordon Tyler
 Changed show_transport_activity and log_transport_activity to use base-10 SI units.  | 
445  | 
msg = ('Transferred: %.0fkB'  | 
446  | 
' (%.1fkB/s r:%.0fkB w:%.0fkB'  | 
|
447  | 
% (self._total_byte_count / 1000.,  | 
|
448  | 
bps / 1000.,  | 
|
449  | 
self._bytes_by_direction['read'] / 1000.,  | 
|
450  | 
self._bytes_by_direction['write'] / 1000.,  | 
|
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
451  | 
                 ))
 | 
452  | 
if self._bytes_by_direction['unknown'] > 0:  | 
|
| 
4989.1.1
by Gordon Tyler
 Changed show_transport_activity and log_transport_activity to use base-10 SI units.  | 
453  | 
msg += ' u:%.0fkB)' % (  | 
454  | 
self._bytes_by_direction['unknown'] / 1000.  | 
|
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
455  | 
                )
 | 
456  | 
else:  | 
|
457  | 
msg += ')'  | 
|
458  | 
return msg  | 
|
459  | 
||
| 
4906.1.1
by John Arbash Meinel
 Basic implementation of logging bytes transferred when bzr exits.  | 
460  | 
def log_transport_activity(self, display=False):  | 
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
461  | 
msg = self._format_bytes_by_direction()  | 
462  | 
trace.mutter(msg)  | 
|
| 
4906.1.7
by John Arbash Meinel
 Switch to KiB/K for each value. Don't display if there are no bytes.  | 
463  | 
if display and self._total_byte_count > 0:  | 
| 
4906.1.3
by John Arbash Meinel
 Use clear() so that we clear a progress bar, but don't introduce a newline.  | 
464  | 
self.clear()  | 
| 
4906.1.4
by John Arbash Meinel
 Play around with the ui display a bit more.  | 
465  | 
self._term_file.write(msg + '\n')  | 
| 
4906.1.1
by John Arbash Meinel
 Basic implementation of logging bytes transferred when bzr exits.  | 
466  | 
|
| 
4792.8.1
by Martin Pool
 Add TextUIOutputStream coordinated with progress view  | 
467  | 
|
468  | 
class TextUIOutputStream(object):  | 
|
469  | 
"""Decorates an output stream so that the terminal is cleared before writing.  | 
|
470  | 
||
471  | 
    This is supposed to ensure that the progress bar does not conflict with bulk
 | 
|
472  | 
    text output.
 | 
|
473  | 
    """
 | 
|
474  | 
    # XXX: this does not handle the case of writing part of a line, then doing
 | 
|
475  | 
    # progress bar output: the progress bar will probably write over it.
 | 
|
476  | 
    # one option is just to buffer that text until we have a full line;
 | 
|
477  | 
    # another is to save and restore it
 | 
|
478  | 
||
479  | 
    # XXX: might need to wrap more methods
 | 
|
480  | 
||
481  | 
def __init__(self, ui_factory, wrapped_stream):  | 
|
482  | 
self.ui_factory = ui_factory  | 
|
483  | 
self.wrapped_stream = wrapped_stream  | 
|
| 
4792.8.13
by Martin Pool
 TextUIOutputStream must have an .encoding  | 
484  | 
        # this does no transcoding, but it must expose the underlying encoding
 | 
485  | 
        # because some callers need to know what can be written - see for
 | 
|
486  | 
        # example unescape_for_display.
 | 
|
| 
4792.8.15
by Martin Pool
 TextUIOutputStream can cope if the wrapped stream doesn't have a .encoding  | 
487  | 
self.encoding = getattr(wrapped_stream, 'encoding', None)  | 
| 
4792.8.1
by Martin Pool
 Add TextUIOutputStream coordinated with progress view  | 
488  | 
|
| 
4792.8.7
by Martin Pool
 Add TextUIOutputStream.flush  | 
489  | 
def flush(self):  | 
490  | 
self.ui_factory.clear_term()  | 
|
491  | 
self.wrapped_stream.flush()  | 
|
492  | 
||
| 
4792.8.1
by Martin Pool
 Add TextUIOutputStream coordinated with progress view  | 
493  | 
def write(self, to_write):  | 
494  | 
self.ui_factory.clear_term()  | 
|
495  | 
self.wrapped_stream.write(to_write)  | 
|
| 
4792.8.3
by Martin Pool
 Add TextUIOutputStream.writelines  | 
496  | 
|
497  | 
def writelines(self, lines):  | 
|
498  | 
self.ui_factory.clear_term()  | 
|
499  | 
self.wrapped_stream.writelines(lines)  |