103
class ConfirmationUserInterfacePolicy(object):
104
"""Wrapper for a UIFactory that allows or denies all confirmed actions."""
106
def __init__(self, wrapped_ui, default_answer, specific_answers):
107
"""Generate a proxy UI that does no confirmations.
109
:param wrapped_ui: Underlying UIFactory.
110
:param default_answer: Bool for whether requests for
111
confirmation from the user should be noninteractively accepted or
113
:param specific_answers: Map from confirmation_id to bool answer.
115
self.wrapped_ui = wrapped_ui
116
self.default_answer = default_answer
117
self.specific_answers = specific_answers
119
def __getattr__(self, name):
120
return getattr(self.wrapped_ui, name)
123
return '%s(%r, %r, %r)' % (
124
self.__class__.__name__,
127
self.specific_answers)
129
def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
130
if confirmation_id in self.specific_answers:
131
return self.specific_answers[confirmation_id]
132
elif self.default_answer is not None:
133
return self.default_answer
135
return self.wrapped_ui.confirm_action(
136
prompt, confirmation_id, prompt_kwargs)
103
139
class UIFactory(object):
104
140
"""UI abstraction.
106
142
This tells the library how to display things to the user. Through this
107
143
layer different applications can choose the style of UI.
145
UI Factories are also context managers, for some syntactic sugar some users
148
:ivar suppressed_warnings: Identifiers for user warnings that should
152
_user_warning_templates = dict(
153
cross_format_fetch=("Doing on-the-fly conversion from "
154
"%(from_format)s to %(to_format)s.\n"
155
"This may take some time. Upgrade the repositories to the "
156
"same format for better performance."
158
recommend_upgrade=("%(current_format_name)s is deprecated "
159
"and a better format is available.\n"
160
"It is recommended that you upgrade by "
161
"running the command\n"
162
" bzr upgrade %(basedir)s"),
110
165
def __init__(self):
111
166
self._task_stack = []
167
self.suppressed_warnings = set()
112
168
self._quiet = False
171
"""Context manager entry support.
173
Override in a concrete factory class if initialisation before use is
176
return self # This is bound to the 'as' clause in a with statement.
178
def __exit__(self, exc_type, exc_val, exc_tb):
179
"""Context manager exit support.
181
Override in a concrete factory class if more cleanup than a simple
182
self.clear_term() is needed when the UIFactory is finished with.
185
return False # propogate exceptions.
114
187
def be_quiet(self, state):
115
188
"""Tell the UI to be more quiet, or not.
120
193
self._quiet = state
195
def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
196
"""Seek user confirmation for an action.
198
If the UI is noninteractive, or the user does not want to be asked
199
about this action, True is returned, indicating bzr should just
202
The confirmation id allows the user to configure certain actions to
203
always be confirmed or always denied, and for UIs to specialize the
204
display of particular confirmations.
206
:param prompt: Suggested text to display to the user.
207
:param prompt_kwargs: A dictionary of arguments that can be
208
string-interpolated into the prompt.
209
:param confirmation_id: Unique string identifier for the confirmation.
211
return self.get_boolean(prompt % prompt_kwargs)
122
213
def get_password(self, prompt='', **kwargs):
123
214
"""Prompt the user for a password.
146
237
version of stdout, but in a GUI it might be appropriate to send it to a
147
238
window displaying the text.
149
:param encoding: Unicode encoding for output; default is the
150
terminal encoding, which may be different from the user encoding.
240
:param encoding: Unicode encoding for output; if not specified
241
uses the configured 'output_encoding' if any; otherwise the
151
243
(See get_terminal_encoding.)
153
245
:param encoding_type: How to handle encoding errors:
156
248
# XXX: is the caller supposed to close the resulting object?
157
249
if encoding is None:
158
encoding = osutils.get_terminal_encoding()
250
from bzrlib import config
251
encoding = config.GlobalConfig().get_user_option(
254
encoding = osutils.get_terminal_encoding(trace=True)
159
255
if encoding_type is None:
160
256
encoding_type = 'replace'
161
257
out_stream = self._make_output_stream_explicit(encoding, encoding_type)
183
279
if not self._task_stack:
184
280
warnings.warn("%r finished but nothing is active"
186
elif task != self._task_stack[-1]:
187
warnings.warn("%r is not the active task %r"
188
% (task, self._task_stack[-1]))
282
if task in self._task_stack:
283
self._task_stack.remove(task)
190
del self._task_stack[-1]
285
warnings.warn("%r is not in active stack %r"
286
% (task, self._task_stack))
191
287
if not self._task_stack:
192
288
self._progress_all_finished()
309
def format_user_warning(self, warning_id, message_args):
311
template = self._user_warning_templates[warning_id]
313
fail = "failed to format warning %r, %r" % (warning_id, message_args)
314
warnings.warn(fail) # so tests will fail etc
317
return template % message_args
318
except ValueError, e:
319
fail = "failed to format warning %r, %r: %s" % (
320
warning_id, message_args, e)
321
warnings.warn(fail) # so tests will fail etc
213
324
def get_boolean(self, prompt):
214
325
"""Get a boolean question answered from the user.
238
349
return NullProgressView()
240
def recommend_upgrade(self,
243
# this should perhaps be in the TextUIFactory and the default can do
245
trace.warning("%s is deprecated "
246
"and a better format is available.\n"
247
"It is recommended that you upgrade by "
248
"running the command\n"
351
def recommend_upgrade(self, current_format_name, basedir):
352
"""Recommend the user upgrade a control directory.
354
:param current_format_name: Description of the current format
355
:param basedir: Location of the control dir
357
self.show_user_warning('recommend_upgrade',
358
current_format_name=current_format_name, basedir=basedir)
253
360
def report_transport_activity(self, transport, byte_count, direction):
254
361
"""Called by transports as they do IO.
271
378
# Default implementation just does nothing
381
def show_user_warning(self, warning_id, **message_args):
382
"""Show a warning to the user.
384
This is specifically for things that are under the user's control (eg
385
outdated formats), not for internal program warnings like deprecated
388
This can be overridden by UIFactory subclasses to show it in some
389
appropriate way; the default UIFactory is noninteractive and does
390
nothing. format_user_warning maps it to a string, though other
391
presentations can be used for particular UIs.
393
:param warning_id: An identifier like 'cross_format_fetch' used to
394
check if the message is suppressed and to look up the string.
395
:param message_args: Arguments to be interpolated into the message.
274
399
def show_error(self, msg):
275
400
"""Show an error message (not an exception) to the user.
288
413
raise NotImplementedError(self.show_warning)
290
415
def warn_cross_format_fetch(self, from_format, to_format):
291
"""Warn about a potentially slow cross-format transfer"""
292
# See <https://launchpad.net/bugs/456077> asking for a warning here
293
trace.warning("Doing on-the-fly conversion from %s to %s.\n"
294
"This may take some time. Upgrade the repositories to the "
295
"same format for better performance.\n" %
296
(from_format, to_format))
299
class SilentUIFactory(UIFactory):
416
"""Warn about a potentially slow cross-format transfer.
418
This is deprecated in favor of show_user_warning, but retained for api
419
compatibility in 2.0 and 2.1.
421
self.show_user_warning('cross_format_fetch', from_format=from_format,
424
def warn_experimental_format_fetch(self, inter):
425
"""Warn about fetching into experimental repository formats."""
426
if inter.target._format.experimental:
427
trace.warning("Fetching into experimental format %s.\n"
428
"This format may be unreliable or change in the future "
429
"without an upgrade path.\n" % (inter.target._format,))
432
class NoninteractiveUIFactory(UIFactory):
433
"""Base class for UIs with no user."""
435
def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
439
return '%s()' % (self.__class__.__name__, )
442
class SilentUIFactory(NoninteractiveUIFactory):
300
443
"""A UI Factory which never prints anything.
302
445
This is the default UI, if another one is never registered by a program