/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/ui/__init__.py

  • Committer: Martin Pool
  • Date: 2010-10-08 04:38:25 UTC
  • mfrom: (5462 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5478.
  • Revision ID: mbp@sourcefrog.net-20101008043825-b181r8bo5r3qwb6j
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
100
100
    return val
101
101
 
102
102
 
 
103
class ConfirmationUserInterfacePolicy(object):
 
104
    """Wrapper for a UIFactory that allows or denies all confirmed actions."""
 
105
 
 
106
    def __init__(self, wrapped_ui, default_answer, specific_answers):
 
107
        """Generate a proxy UI that does no confirmations.
 
108
 
 
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
 
112
            denied.
 
113
        :param specific_answers: Map from confirmation_id to bool answer.
 
114
        """
 
115
        self.wrapped_ui = wrapped_ui
 
116
        self.default_answer = default_answer
 
117
        self.specific_answers = specific_answers
 
118
 
 
119
    def __getattr__(self, name):
 
120
        return getattr(self.wrapped_ui, name)
 
121
 
 
122
    def __repr__(self):
 
123
        return '%s(%r, %r, %r)' % (
 
124
            self.__class__.__name__,
 
125
            self.wrapped_ui,
 
126
            self.default_answer, 
 
127
            self.specific_answers)
 
128
 
 
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
 
134
        else:
 
135
            return self.wrapped_ui.confirm_action(
 
136
                prompt, confirmation_id, prompt_kwargs)
 
137
 
 
138
 
103
139
class UIFactory(object):
104
140
    """UI abstraction.
105
141
 
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.
 
144
 
 
145
    UI Factories are also context managers, for some syntactic sugar some users
 
146
    need.
 
147
 
 
148
    :ivar suppressed_warnings: Identifiers for user warnings that should 
 
149
        no be emitted.
108
150
    """
109
151
 
 
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."
 
157
            )
 
158
        )
 
159
 
110
160
    def __init__(self):
111
161
        self._task_stack = []
 
162
        self.suppressed_warnings = set()
 
163
        self._quiet = False
 
164
 
 
165
    def __enter__(self):
 
166
        """Context manager entry support.
 
167
 
 
168
        Override in a concrete factory class if initialisation before use is
 
169
        needed.
 
170
        """
 
171
        return self # This is bound to the 'as' clause in a with statement.
 
172
 
 
173
    def __exit__(self, exc_type, exc_val, exc_tb):
 
174
        """Context manager exit support.
 
175
 
 
176
        Override in a concrete factory class if more cleanup than a simple
 
177
        self.clear_term() is needed when the UIFactory is finished with.
 
178
        """
 
179
        self.clear_term()
 
180
        return False # propogate exceptions.
 
181
 
 
182
    def be_quiet(self, state):
 
183
        """Tell the UI to be more quiet, or not.
 
184
 
 
185
        Typically this suppresses progress bars; the application may also look
 
186
        at ui_factory.is_quiet().
 
187
        """
 
188
        self._quiet = state
 
189
 
 
190
    def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
 
191
        """Seek user confirmation for an action.
 
192
 
 
193
        If the UI is noninteractive, or the user does not want to be asked
 
194
        about this action, True is returned, indicating bzr should just
 
195
        proceed.
 
196
 
 
197
        The confirmation id allows the user to configure certain actions to
 
198
        always be confirmed or always denied, and for UIs to specialize the
 
199
        display of particular confirmations.
 
200
 
 
201
        :param prompt: Suggested text to display to the user.
 
202
        :param prompt_kwargs: A dictionary of arguments that can be
 
203
            string-interpolated into the prompt.
 
204
        :param confirmation_id: Unique string identifier for the confirmation.
 
205
        """
 
206
        return self.get_boolean(prompt % prompt_kwargs)
112
207
 
113
208
    def get_password(self, prompt='', **kwargs):
114
209
        """Prompt the user for a password.
125
220
        """
126
221
        raise NotImplementedError(self.get_password)
127
222
 
 
223
    def is_quiet(self):
 
224
        return self._quiet
 
225
 
128
226
    def make_output_stream(self, encoding=None, encoding_type=None):
129
227
        """Get a stream for sending out bulk text data.
130
228
 
134
232
        version of stdout, but in a GUI it might be appropriate to send it to a 
135
233
        window displaying the text.
136
234
     
137
 
        :param encoding: Unicode encoding for output; default is the 
138
 
            terminal encoding, which may be different from the user encoding.
 
235
        :param encoding: Unicode encoding for output; if not specified 
 
236
            uses the configured 'output_encoding' if any; otherwise the 
 
237
            terminal encoding. 
139
238
            (See get_terminal_encoding.)
140
239
 
141
240
        :param encoding_type: How to handle encoding errors:
143
242
        """
144
243
        # XXX: is the caller supposed to close the resulting object?
145
244
        if encoding is None:
146
 
            encoding = osutils.get_terminal_encoding()
 
245
            from bzrlib import config
 
246
            encoding = config.GlobalConfig().get_user_option(
 
247
                'output_encoding')
 
248
        if encoding is None:
 
249
            encoding = osutils.get_terminal_encoding(trace=True)
147
250
        if encoding_type is None:
148
251
            encoding_type = 'replace'
149
252
        out_stream = self._make_output_stream_explicit(encoding, encoding_type)
171
274
        if not self._task_stack:
172
275
            warnings.warn("%r finished but nothing is active"
173
276
                % (task,))
174
 
        elif task != self._task_stack[-1]:
175
 
            warnings.warn("%r is not the active task %r"
176
 
                % (task, self._task_stack[-1]))
 
277
        if task in self._task_stack:
 
278
            self._task_stack.remove(task)
177
279
        else:
178
 
            del self._task_stack[-1]
 
280
            warnings.warn("%r is not in active stack %r"
 
281
                % (task, self._task_stack))
179
282
        if not self._task_stack:
180
283
            self._progress_all_finished()
181
284
 
198
301
        """
199
302
        pass
200
303
 
 
304
    def format_user_warning(self, warning_id, message_args):
 
305
        try:
 
306
            template = self._user_warning_templates[warning_id]
 
307
        except KeyError:
 
308
            fail = "failed to format warning %r, %r" % (warning_id, message_args)
 
309
            warnings.warn(fail)   # so tests will fail etc
 
310
            return fail
 
311
        try:
 
312
            return template % message_args
 
313
        except ValueError, e:
 
314
            fail = "failed to format warning %r, %r: %s" % (
 
315
                warning_id, message_args, e)
 
316
            warnings.warn(fail)   # so tests will fail etc
 
317
            return fail
 
318
 
201
319
    def get_boolean(self, prompt):
202
320
        """Get a boolean question answered from the user.
203
321
 
228
346
    def recommend_upgrade(self,
229
347
        current_format_name,
230
348
        basedir):
231
 
        # this should perhaps be in the TextUIFactory and the default can do
 
349
        # XXX: this should perhaps be in the TextUIFactory and the default can do
232
350
        # nothing
 
351
        #
 
352
        # XXX: Change to show_user_warning - that will accomplish the previous
 
353
        # xxx. -- mbp 2010-02-25
233
354
        trace.warning("%s is deprecated "
234
355
            "and a better format is available.\n"
235
356
            "It is recommended that you upgrade by "
246
367
        """
247
368
        pass
248
369
 
 
370
    def log_transport_activity(self, display=False):
 
371
        """Write out whatever transport activity has been measured.
 
372
 
 
373
        Implementations are allowed to do nothing, but it is useful if they can
 
374
        write a line to the log file.
 
375
 
 
376
        :param display: If False, only log to disk, if True also try to display
 
377
            a message to the user.
 
378
        :return: None
 
379
        """
 
380
        # Default implementation just does nothing
 
381
        pass
 
382
 
 
383
    def show_user_warning(self, warning_id, **message_args):
 
384
        """Show a warning to the user.
 
385
 
 
386
        This is specifically for things that are under the user's control (eg
 
387
        outdated formats), not for internal program warnings like deprecated
 
388
        APIs.
 
389
 
 
390
        This can be overridden by UIFactory subclasses to show it in some 
 
391
        appropriate way; the default UIFactory is noninteractive and does
 
392
        nothing.  format_user_warning maps it to a string, though other
 
393
        presentations can be used for particular UIs.
 
394
 
 
395
        :param warning_id: An identifier like 'cross_format_fetch' used to 
 
396
            check if the message is suppressed and to look up the string.
 
397
        :param message_args: Arguments to be interpolated into the message.
 
398
        """
 
399
        pass
 
400
 
249
401
    def show_error(self, msg):
250
402
        """Show an error message (not an exception) to the user.
251
403
        
252
404
        The message should not have an error prefix or trailing newline.  That
253
 
        will be added by the factory if appropriate. 
 
405
        will be added by the factory if appropriate.
254
406
        """
255
407
        raise NotImplementedError(self.show_error)
256
408
 
262
414
        """Show a warning to the user."""
263
415
        raise NotImplementedError(self.show_warning)
264
416
 
265
 
 
266
 
 
267
 
class SilentUIFactory(UIFactory):
 
417
    def warn_cross_format_fetch(self, from_format, to_format):
 
418
        """Warn about a potentially slow cross-format transfer.
 
419
        
 
420
        This is deprecated in favor of show_user_warning, but retained for api
 
421
        compatibility in 2.0 and 2.1.
 
422
        """
 
423
        self.show_user_warning('cross_format_fetch', from_format=from_format,
 
424
            to_format=to_format)
 
425
 
 
426
    def warn_experimental_format_fetch(self, inter):
 
427
        """Warn about fetching into experimental repository formats."""
 
428
        if inter.target._format.experimental:
 
429
            trace.warning("Fetching into experimental format %s.\n"
 
430
                "This format may be unreliable or change in the future "
 
431
                "without an upgrade path.\n" % (inter.target._format,))
 
432
 
 
433
 
 
434
class NoninteractiveUIFactory(UIFactory):
 
435
    """Base class for UIs with no user."""
 
436
 
 
437
    def confirm_action(self, prompt, confirmation_id, prompt_kwargs):
 
438
        return True
 
439
 
 
440
    def __repr__(self):
 
441
        return '%s()' % (self.__class__.__name__, )
 
442
 
 
443
 
 
444
class SilentUIFactory(NoninteractiveUIFactory):
268
445
    """A UI Factory which never prints anything.
269
446
 
270
447
    This is the default UI, if another one is never registered by a program
283
460
    def get_username(self, prompt, **kwargs):
284
461
        return None
285
462
 
 
463
    def _make_output_stream_explicit(self, encoding, encoding_type):
 
464
        return NullOutputStream(encoding)
 
465
 
286
466
    def show_error(self, msg):
287
467
        pass
288
468
 
302
482
    def __repr__(self):
303
483
        return "%s(%r)" % (self.__class__.__name__, self.responses)
304
484
 
 
485
    def confirm_action(self, prompt, confirmation_id, args):
 
486
        return self.get_boolean(prompt % args)
 
487
 
305
488
    def get_boolean(self, prompt):
306
489
        return self.responses.pop(0)
307
490
 
345
528
 
346
529
    def show_transport_activity(self, transport, direction, byte_count):
347
530
        pass
 
531
 
 
532
    def log_transport_activity(self, display=False):
 
533
        pass
 
534
 
 
535
 
 
536
class NullOutputStream(object):
 
537
    """Acts like a file, but discard all output."""
 
538
 
 
539
    def __init__(self, encoding):
 
540
        self.encoding = encoding
 
541
 
 
542
    def write(self, data):
 
543
        pass
 
544
 
 
545
    def writelines(self, data):
 
546
        pass
 
547
 
 
548
    def close(self):
 
549
        pass