~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/ui/__init__.py

  • Committer: Martin
  • Date: 2010-05-03 20:57:39 UTC
  • mto: This revision was merged to the branch mainline in revision 5204.
  • Revision ID: gzlist@googlemail.com-20100503205739-n326zdvevv0rmruh
Retain original stack and error message when translating to ValueError in bencode

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
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
41
41
    back to working through the terminal.
42
42
"""
43
43
 
44
 
from __future__ import absolute_import
45
44
 
 
45
import os
 
46
import sys
46
47
import warnings
47
48
 
48
49
from bzrlib.lazy_import import lazy_import
49
50
lazy_import(globals(), """
 
51
import getpass
 
52
 
50
53
from bzrlib import (
51
 
    config,
 
54
    errors,
52
55
    osutils,
53
56
    progress,
54
57
    trace,
55
58
    )
56
59
""")
 
60
from bzrlib.symbol_versioning import (
 
61
    deprecated_function,
 
62
    deprecated_in,
 
63
    deprecated_method,
 
64
    )
57
65
 
58
66
 
59
67
_valid_boolean_strings = dict(yes=True, no=False,
92
100
    return val
93
101
 
94
102
 
95
 
class ConfirmationUserInterfacePolicy(object):
96
 
    """Wrapper for a UIFactory that allows or denies all confirmed actions."""
97
 
 
98
 
    def __init__(self, wrapped_ui, default_answer, specific_answers):
99
 
        """Generate a proxy UI that does no confirmations.
100
 
 
101
 
        :param wrapped_ui: Underlying UIFactory.
102
 
        :param default_answer: Bool for whether requests for
103
 
            confirmation from the user should be noninteractively accepted or
104
 
            denied.
105
 
        :param specific_answers: Map from confirmation_id to bool answer.
106
 
        """
107
 
        self.wrapped_ui = wrapped_ui
108
 
        self.default_answer = default_answer
109
 
        self.specific_answers = specific_answers
110
 
 
111
 
    def __getattr__(self, name):
112
 
        return getattr(self.wrapped_ui, name)
113
 
 
114
 
    def __repr__(self):
115
 
        return '%s(%r, %r, %r)' % (
116
 
            self.__class__.__name__,
117
 
            self.wrapped_ui,
118
 
            self.default_answer, 
119
 
            self.specific_answers)
120
 
 
121
 
    def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
122
 
        if confirmation_id in self.specific_answers:
123
 
            return self.specific_answers[confirmation_id]
124
 
        elif self.default_answer is not None:
125
 
            return self.default_answer
126
 
        else:
127
 
            return self.wrapped_ui.confirm_action(
128
 
                prompt, confirmation_id, prompt_kwargs)
129
 
 
130
 
 
131
103
class UIFactory(object):
132
104
    """UI abstraction.
133
105
 
134
106
    This tells the library how to display things to the user.  Through this
135
107
    layer different applications can choose the style of UI.
136
108
 
137
 
    UI Factories are also context managers, for some syntactic sugar some users
138
 
    need.
139
 
 
140
109
    :ivar suppressed_warnings: Identifiers for user warnings that should 
141
110
        no be emitted.
142
111
    """
146
115
            "%(from_format)s to %(to_format)s.\n"
147
116
            "This may take some time. Upgrade the repositories to the "
148
117
            "same format for better performance."
149
 
            ),
150
 
        experimental_format_fetch=("Fetching into experimental format "
151
 
            "%(to_format)s.\n"
152
 
            "This format may be unreliable or change in the future "
153
 
            "without an upgrade path.\n"),
154
 
        deprecated_command=(
155
 
            "The command 'bzr %(deprecated_name)s' "
156
 
            "has been deprecated in bzr %(deprecated_in_version)s. "
157
 
            "Please use 'bzr %(recommended_name)s' instead."),
158
 
        deprecated_command_option=(
159
 
            "The option '%(deprecated_name)s' to 'bzr %(command)s' "
160
 
            "has been deprecated in bzr %(deprecated_in_version)s. "
161
 
            "Please use '%(recommended_name)s' instead."),
162
 
        recommend_upgrade=("%(current_format_name)s is deprecated "
163
 
            "and a better format is available.\n"
164
 
            "It is recommended that you upgrade by "
165
 
            "running the command\n"
166
 
            "  bzr upgrade %(basedir)s"),
167
 
        locks_steal_dead=(
168
 
            u"Stole dead lock %(lock_url)s %(other_holder_info)s."),
169
 
        not_checking_ssl_cert=(
170
 
            u"Not checking SSL certificate for %(host)s."),
 
118
            )
171
119
        )
172
120
 
173
121
    def __init__(self):
175
123
        self.suppressed_warnings = set()
176
124
        self._quiet = False
177
125
 
178
 
    def __enter__(self):
179
 
        """Context manager entry support.
180
 
 
181
 
        Override in a concrete factory class if initialisation before use is
182
 
        needed.
183
 
        """
184
 
        return self # This is bound to the 'as' clause in a with statement.
185
 
 
186
 
    def __exit__(self, exc_type, exc_val, exc_tb):
187
 
        """Context manager exit support.
188
 
 
189
 
        Override in a concrete factory class if more cleanup than a simple
190
 
        self.clear_term() is needed when the UIFactory is finished with.
191
 
        """
192
 
        self.clear_term()
193
 
        return False # propogate exceptions.
194
 
 
195
126
    def be_quiet(self, state):
196
127
        """Tell the UI to be more quiet, or not.
197
128
 
200
131
        """
201
132
        self._quiet = state
202
133
 
203
 
    def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
204
 
        """Seek user confirmation for an action.
205
 
 
206
 
        If the UI is noninteractive, or the user does not want to be asked
207
 
        about this action, True is returned, indicating bzr should just
208
 
        proceed.
209
 
 
210
 
        The confirmation id allows the user to configure certain actions to
211
 
        always be confirmed or always denied, and for UIs to specialize the
212
 
        display of particular confirmations.
213
 
 
214
 
        :param prompt: Suggested text to display to the user.
215
 
        :param prompt_kwargs: A dictionary of arguments that can be
216
 
            string-interpolated into the prompt.
217
 
        :param confirmation_id: Unique string identifier for the confirmation.
218
 
        """
219
 
        return self.get_boolean(prompt % prompt_kwargs)
220
 
 
221
 
    def get_password(self, prompt=u'', **kwargs):
 
134
    def get_password(self, prompt='', **kwargs):
222
135
        """Prompt the user for a password.
223
136
 
224
 
        :param prompt: The prompt to present the user (must be unicode)
 
137
        :param prompt: The prompt to present the user
225
138
        :param kwargs: Arguments which will be expanded into the prompt.
226
139
                       This lets front ends display different things if
227
140
                       they so choose.
245
158
        version of stdout, but in a GUI it might be appropriate to send it to a 
246
159
        window displaying the text.
247
160
     
248
 
        :param encoding: Unicode encoding for output; if not specified 
249
 
            uses the configured 'output_encoding' if any; otherwise the 
250
 
            terminal encoding. 
 
161
        :param encoding: Unicode encoding for output; default is the 
 
162
            terminal encoding, which may be different from the user encoding.
251
163
            (See get_terminal_encoding.)
252
164
 
253
165
        :param encoding_type: How to handle encoding errors:
255
167
        """
256
168
        # XXX: is the caller supposed to close the resulting object?
257
169
        if encoding is None:
258
 
            encoding = config.GlobalStack().get('output_encoding')
259
 
        if encoding is None:
260
 
            encoding = osutils.get_terminal_encoding(trace=True)
 
170
            encoding = osutils.get_terminal_encoding()
261
171
        if encoding_type is None:
262
172
            encoding_type = 'replace'
263
173
        out_stream = self._make_output_stream_explicit(encoding, encoding_type)
316
226
        try:
317
227
            template = self._user_warning_templates[warning_id]
318
228
        except KeyError:
319
 
            fail = "bzr warning: %r, %r" % (warning_id, message_args)
320
 
            warnings.warn("no template for warning: " + fail)   # so tests will fail etc
 
229
            fail = "failed to format warning %r, %r" % (warning_id, message_args)
 
230
            warnings.warn(fail)   # so tests will fail etc
321
231
            return fail
322
232
        try:
323
233
            return template % message_args
324
234
        except ValueError, e:
325
 
            fail = "bzr unprintable warning: %r, %r, %s" % (
 
235
            fail = "failed to format warning %r, %r: %s" % (
326
236
                warning_id, message_args, e)
327
237
            warnings.warn(fail)   # so tests will fail etc
328
238
            return fail
329
239
 
330
 
    def choose(self, msg, choices, default=None):
331
 
        """Prompt the user for a list of alternatives.
332
 
 
333
 
        :param msg: message to be shown as part of the prompt.
334
 
 
335
 
        :param choices: list of choices, with the individual choices separated
336
 
            by '\n', e.g.: choose("Save changes?", "&Yes\n&No\n&Cancel"). The
337
 
            letter after the '&' is the shortcut key for that choice. Thus you
338
 
            can type 'c' to select "Cancel".  Shorcuts are case insensitive.
339
 
            The shortcut does not need to be the first letter. If a shorcut key
340
 
            is not provided, the first letter for the choice will be used.
341
 
 
342
 
        :param default: default choice (index), returned for example when enter
343
 
            is pressed for the console version.
344
 
 
345
 
        :return: the index fo the user choice (so '0', '1' or '2' for
346
 
            respectively yes/no/cancel in the previous example).
347
 
        """
348
 
        raise NotImplementedError(self.choose)
349
 
 
350
240
    def get_boolean(self, prompt):
351
241
        """Get a boolean question answered from the user.
352
242
 
353
243
        :param prompt: a message to prompt the user with. Should be a single
354
 
            line without terminating \\n.
 
244
        line without terminating \n.
355
245
        :return: True or False for y/yes or n/no.
356
246
        """
357
 
        choice = self.choose(prompt + '?', '&yes\n&no', default=None)
358
 
        return 0 == choice
 
247
        raise NotImplementedError(self.get_boolean)
359
248
 
360
249
    def get_integer(self, prompt):
361
250
        """Get an integer from the user.
362
251
 
363
252
        :param prompt: a message to prompt the user with. Could be a multi-line
364
 
            prompt but without a terminating \\n.
 
253
            prompt but without a terminating \n.
365
254
 
366
255
        :return: A signed integer.
367
256
        """
375
264
        """
376
265
        return NullProgressView()
377
266
 
378
 
    def recommend_upgrade(self, current_format_name, basedir):
379
 
        """Recommend the user upgrade a control directory.
380
 
 
381
 
        :param current_format_name: Description of the current format
382
 
        :param basedir: Location of the control dir
383
 
        """
384
 
        self.show_user_warning('recommend_upgrade',
385
 
            current_format_name=current_format_name, basedir=basedir)
 
267
    def recommend_upgrade(self,
 
268
        current_format_name,
 
269
        basedir):
 
270
        # XXX: this should perhaps be in the TextUIFactory and the default can do
 
271
        # nothing
 
272
        #
 
273
        # XXX: Change to show_user_warning - that will accomplish the previous
 
274
        # xxx. -- mbp 2010-02-25
 
275
        trace.warning("%s is deprecated "
 
276
            "and a better format is available.\n"
 
277
            "It is recommended that you upgrade by "
 
278
            "running the command\n"
 
279
            "  bzr upgrade %s",
 
280
            current_format_name,
 
281
            basedir)
386
282
 
387
283
    def report_transport_activity(self, transport, byte_count, direction):
388
284
        """Called by transports as they do IO.
439
335
        """Show a warning to the user."""
440
336
        raise NotImplementedError(self.show_warning)
441
337
 
442
 
 
443
 
class NoninteractiveUIFactory(UIFactory):
444
 
    """Base class for UIs with no user."""
445
 
 
446
 
    def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
447
 
        return True
448
 
 
449
 
    def __repr__(self):
450
 
        return '%s()' % (self.__class__.__name__, )
451
 
 
452
 
 
453
 
class SilentUIFactory(NoninteractiveUIFactory):
 
338
    def warn_cross_format_fetch(self, from_format, to_format):
 
339
        """Warn about a potentially slow cross-format transfer.
 
340
        
 
341
        This is deprecated in favor of show_user_warning, but retained for api
 
342
        compatibility in 2.0 and 2.1.
 
343
        """
 
344
        self.show_user_warning('cross_format_fetch', from_format=from_format,
 
345
            to_format=to_format)
 
346
 
 
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,))
 
353
 
 
354
 
 
355
 
 
356
class SilentUIFactory(UIFactory):
454
357
    """A UI Factory which never prints anything.
455
358
 
456
359
    This is the default UI, if another one is never registered by a program
491
394
    def __repr__(self):
492
395
        return "%s(%r)" % (self.__class__.__name__, self.responses)
493
396
 
494
 
    def confirm_action(self, prompt, confirmation_id, args):
495
 
        return self.get_boolean(prompt % args)
496
 
 
497
397
    def get_boolean(self, prompt):
498
398
        return self.responses.pop(0)
499
399
 
500
400
    def get_integer(self, prompt):
501
401
        return self.responses.pop(0)
502
402
 
503
 
    def get_password(self, prompt=u'', **kwargs):
 
403
    def get_password(self, prompt='', **kwargs):
504
404
        return self.responses.pop(0)
505
405
 
506
406
    def get_username(self, prompt, **kwargs):