51
52
"""Create a TextUIFactory.
53
:param bar_type: The type of progress bar to create. Deprecated
54
and ignored; a TextProgressView is always used.
56
54
super(TextUIFactory, self).__init__()
57
55
# TODO: there's no good reason not to pass all three streams, maybe we
85
83
# end-of-file; possibly should raise an error here instead
86
def get_integer(self, prompt):
89
line = self.stdin.readline()
88
95
def get_non_echoed_password(self):
89
96
isatty = getattr(self.stdin, 'isatty', None)
90
97
if isatty is not None and isatty():
150
157
return NullProgressView()
159
def _make_output_stream_explicit(self, encoding, encoding_type):
160
if encoding_type == 'exact':
161
# force sys.stdout to be binary stream on win32;
162
# NB: this leaves the file set in that mode; may cause problems if
163
# one process tries to do binary and then text output
164
if sys.platform == 'win32':
165
fileno = getattr(self.stdout, 'fileno', None)
168
msvcrt.setmode(fileno(), os.O_BINARY)
169
return TextUIOutputStream(self, self.stdout)
171
encoded_stdout = codecs.getwriter(encoding)(self.stdout,
172
errors=encoding_type)
173
# For whatever reason codecs.getwriter() does not advertise its encoding
174
# it just returns the encoding of the wrapped file, which is completely
175
# bogus. So set the attribute, so we can find the correct encoding later.
176
encoded_stdout.encoding = encoding
177
return TextUIOutputStream(self, encoded_stdout)
152
179
def note(self, msg):
153
180
"""Write an already-formatted message, clearing the progress bar if necessary."""
154
181
self.clear_term()
176
203
self._progress_view.show_transport_activity(transport,
177
204
direction, byte_count)
206
def show_error(self, msg):
208
self.stderr.write("bzr: error: %s\n" % msg)
210
def show_message(self, msg):
213
def show_warning(self, msg):
215
self.stderr.write("bzr: warning: %s\n" % msg)
179
217
def _progress_updated(self, task):
180
218
"""A task has been updated and wants to be displayed.
210
248
self._term_file = term_file
211
249
# true when there's output on the screen we may need to clear
212
250
self._have_output = False
213
# XXX: We could listen for SIGWINCH and update the terminal width...
214
# https://launchpad.net/bugs/316357
215
self._width = osutils.terminal_width()
216
251
self._last_transport_msg = ''
217
252
self._spin_pos = 0
218
253
# time we last repainted the screen
223
258
self._total_byte_count = 0
224
259
self._bytes_since_update = 0
225
260
self._fraction = 0
261
# force the progress bar to be off, as at the moment it doesn't
262
# correspond reliably to overall command progress
263
self.enable_bar = False
227
265
def _show_line(self, s):
228
266
# sys.stderr.write("progress %r\n" % s)
230
self._term_file.write('\r%-*.*s\r' % (n, n, s))
267
width = osutils.terminal_width()
268
if width is not None:
269
# we need one extra space for terminals that wrap on last char
271
s = '%-*.*s' % (width, width, s)
272
self._term_file.write('\r' + s + '\r')
233
275
if self._have_output:
237
279
def _render_bar(self):
238
280
# return a string for the progress bar itself
239
if (self._last_task is None) or self._last_task.show_bar:
281
if self.enable_bar and (
282
(self._last_task is None) or self._last_task.show_bar):
240
283
# If there's no task object, we show space for the bar anyhow.
241
284
# That's because most invocations of bzr will end showing progress
242
285
# at some point, though perhaps only after doing some initial IO.
357
400
self._bytes_since_update = 0
358
401
self._last_transport_msg = msg
405
class TextUIOutputStream(object):
406
"""Decorates an output stream so that the terminal is cleared before writing.
408
This is supposed to ensure that the progress bar does not conflict with bulk
411
# XXX: this does not handle the case of writing part of a line, then doing
412
# progress bar output: the progress bar will probably write over it.
413
# one option is just to buffer that text until we have a full line;
414
# another is to save and restore it
416
# XXX: might need to wrap more methods
418
def __init__(self, ui_factory, wrapped_stream):
419
self.ui_factory = ui_factory
420
self.wrapped_stream = wrapped_stream
421
# this does no transcoding, but it must expose the underlying encoding
422
# because some callers need to know what can be written - see for
423
# example unescape_for_display.
424
self.encoding = getattr(wrapped_stream, 'encoding', None)
427
self.ui_factory.clear_term()
428
self.wrapped_stream.flush()
430
def write(self, to_write):
431
self.ui_factory.clear_term()
432
self.wrapped_stream.write(to_write)
434
def writelines(self, lines):
435
self.ui_factory.clear_term()
436
self.wrapped_stream.writelines(lines)