1
# Copyright (C) 2005-2010 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
106
106
This tells the library how to display things to the user. Through this
107
107
layer different applications can choose the style of UI.
109
:ivar suppressed_warnings: Identifiers for user warnings that should
113
_user_warning_templates = dict(
114
cross_format_fetch=("Doing on-the-fly conversion from "
115
"%(from_format)s to %(to_format)s.\n"
116
"This may take some time. Upgrade the repositories to the "
117
"same format for better performance."
121
110
def __init__(self):
122
111
self._task_stack = []
123
self.suppressed_warnings = set()
126
def be_quiet(self, state):
127
"""Tell the UI to be more quiet, or not.
129
Typically this suppresses progress bars; the application may also look
130
at ui_factory.is_quiet().
134
113
def get_password(self, prompt='', **kwargs):
135
114
"""Prompt the user for a password.
195
171
if not self._task_stack:
196
172
warnings.warn("%r finished but nothing is active"
198
if task in self._task_stack:
199
self._task_stack.remove(task)
174
elif task != self._task_stack[-1]:
175
warnings.warn("%r is not the active task %r"
176
% (task, self._task_stack[-1]))
201
warnings.warn("%r is not in active stack %r"
202
% (task, self._task_stack))
178
del self._task_stack[-1]
203
179
if not self._task_stack:
204
180
self._progress_all_finished()
225
def format_user_warning(self, warning_id, message_args):
227
template = self._user_warning_templates[warning_id]
229
fail = "failed to format warning %r, %r" % (warning_id, message_args)
230
warnings.warn(fail) # so tests will fail etc
233
return template % message_args
234
except ValueError, e:
235
fail = "failed to format warning %r, %r: %s" % (
236
warning_id, message_args, e)
237
warnings.warn(fail) # so tests will fail etc
240
201
def get_boolean(self, prompt):
241
202
"""Get a boolean question answered from the user.
267
228
def recommend_upgrade(self,
268
229
current_format_name,
270
# XXX: this should perhaps be in the TextUIFactory and the default can do
231
# this should perhaps be in the TextUIFactory and the default can do
273
# XXX: Change to show_user_warning - that will accomplish the previous
274
# xxx. -- mbp 2010-02-25
275
233
trace.warning("%s is deprecated "
276
234
"and a better format is available.\n"
277
235
"It is recommended that you upgrade by "
291
def log_transport_activity(self, display=False):
292
"""Write out whatever transport activity has been measured.
294
Implementations are allowed to do nothing, but it is useful if they can
295
write a line to the log file.
297
:param display: If False, only log to disk, if True also try to display
298
a message to the user.
301
# Default implementation just does nothing
304
def show_user_warning(self, warning_id, **message_args):
305
"""Show a warning to the user.
307
This is specifically for things that are under the user's control (eg
308
outdated formats), not for internal program warnings like deprecated
311
This can be overridden by UIFactory subclasses to show it in some
312
appropriate way; the default UIFactory is noninteractive and does
313
nothing. format_user_warning maps it to a string, though other
314
presentations can be used for particular UIs.
316
:param warning_id: An identifier like 'cross_format_fetch' used to
317
check if the message is suppressed and to look up the string.
318
:param message_args: Arguments to be interpolated into the message.
322
249
def show_error(self, msg):
323
250
"""Show an error message (not an exception) to the user.
325
252
The message should not have an error prefix or trailing newline. That
326
will be added by the factory if appropriate.
253
will be added by the factory if appropriate.
328
255
raise NotImplementedError(self.show_error)
335
262
"""Show a warning to the user."""
336
263
raise NotImplementedError(self.show_warning)
338
def warn_cross_format_fetch(self, from_format, to_format):
339
"""Warn about a potentially slow cross-format transfer.
341
This is deprecated in favor of show_user_warning, but retained for api
342
compatibility in 2.0 and 2.1.
344
self.show_user_warning('cross_format_fetch', from_format=from_format,
347
def warn_experimental_format_fetch(self, inter):
348
"""Warn about fetching into experimental repository formats."""
349
if inter.target._format.experimental:
350
trace.warning("Fetching into experimental format %s.\n"
351
"This format may be unreliable or change in the future "
352
"without an upgrade path.\n" % (inter.target._format,))
356
267
class SilentUIFactory(UIFactory):
372
283
def get_username(self, prompt, **kwargs):
375
def _make_output_stream_explicit(self, encoding, encoding_type):
376
return NullOutputStream(encoding)
378
286
def show_error(self, msg):
438
346
def show_transport_activity(self, transport, direction, byte_count):
441
def log_transport_activity(self, display=False):
445
class NullOutputStream(object):
446
"""Acts like a file, but discard all output."""
448
def __init__(self, encoding):
449
self.encoding = encoding
451
def write(self, data):
454
def writelines(self, data):