~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/ui/text.py

Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.

This is used to replace various ad hoc implementations of the same logic,
notably the version used in registry's _LazyObjectGetter which had a bug when
getting a module without also getting a member.  And of course, this new
function has unit tests, unlike the replaced code.

This also adds a KnownHooksRegistry subclass to provide a more natural home for
some other logic.

I'm not thrilled about the name of the new module or the new functions, but it's
hard to think of good names for such generic functionality.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
 
38
38
""")
39
39
 
40
 
from bzrlib.osutils import watch_sigwinch
41
 
 
42
40
from bzrlib.ui import (
43
41
    UIFactory,
44
42
    NullProgressView,
62
60
        self.stderr = stderr
63
61
        # paints progress, network activity, etc
64
62
        self._progress_view = self.make_progress_view()
65
 
        # hook up the signals to watch for terminal size changes
66
 
        watch_sigwinch()
67
63
 
68
64
    def be_quiet(self, state):
69
65
        if state and not self._quiet:
157
153
        """Construct and return a new ProgressView subclass for this UI.
158
154
        """
159
155
        # with --quiet, never any progress view
160
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/320035>.  Otherwise if the
 
156
        # <https://bugs.launchpad.net/bzr/+bug/320035>.  Otherwise if the
161
157
        # user specifically requests either text or no progress bars, always
162
158
        # do that.  otherwise, guess based on $TERM and tty presence.
163
159
        if self.is_quiet():
233
229
 
234
230
    def show_warning(self, msg):
235
231
        self.clear_term()
 
232
        if isinstance(msg, unicode):
 
233
            te = osutils.get_terminal_encoding()
 
234
            msg = msg.encode(te, 'replace')
236
235
        self.stderr.write("bzr: warning: %s\n" % msg)
237
236
 
238
237
    def _progress_updated(self, task):
301
300
        # correspond reliably to overall command progress
302
301
        self.enable_bar = False
303
302
 
 
303
    def _avail_width(self):
 
304
        # we need one extra space for terminals that wrap on last char
 
305
        w = osutils.terminal_width() 
 
306
        if w is None:
 
307
            return None
 
308
        else:
 
309
            return w - 1
 
310
 
304
311
    def _show_line(self, s):
305
312
        # sys.stderr.write("progress %r\n" % s)
306
 
        width = osutils.terminal_width()
 
313
        width = self._avail_width()
307
314
        if width is not None:
308
 
            # we need one extra space for terminals that wrap on last char
309
 
            width = width - 1
310
315
            s = '%-*.*s' % (width, width, s)
311
316
        self._term_file.write('\r' + s + '\r')
312
317
 
349
354
            return ''
350
355
 
351
356
    def _format_task(self, task):
 
357
        """Format task-specific parts of progress bar.
 
358
 
 
359
        :returns: (text_part, counter_part) both unicode strings.
 
360
        """
352
361
        if not task.show_count:
353
362
            s = ''
354
363
        elif task.current_cnt is not None and task.total_cnt is not None:
364
373
            t = t._parent_task
365
374
            if t.msg:
366
375
                m = t.msg + ':' + m
367
 
        return m + s
 
376
        return m, s
368
377
 
369
378
    def _render_line(self):
370
379
        bar_string = self._render_bar()
371
380
        if self._last_task:
372
 
            task_msg = self._format_task(self._last_task)
 
381
            task_part, counter_part = self._format_task(self._last_task)
373
382
        else:
374
 
            task_msg = ''
 
383
            task_part = counter_part = ''
375
384
        if self._last_task and not self._last_task.show_transport_activity:
376
385
            trans = ''
377
386
        else:
378
387
            trans = self._last_transport_msg
379
 
            if trans:
380
 
                trans += ' | '
381
 
        return (bar_string + trans + task_msg)
 
388
        # the bar separates the transport activity from the message, so even
 
389
        # if there's no bar or spinner, we must show something if both those
 
390
        # fields are present
 
391
        if (task_part or trans) and not bar_string:
 
392
            bar_string = '| '
 
393
        # preferentially truncate the task message if we don't have enough
 
394
        # space
 
395
        avail_width = self._avail_width()
 
396
        if avail_width is not None:
 
397
            # if terminal avail_width is unknown, don't truncate
 
398
            current_len = len(bar_string) + len(trans) + len(task_part) + len(counter_part)
 
399
            gap = current_len - avail_width
 
400
            if gap > 0:
 
401
                task_part = task_part[:-gap-2] + '..'
 
402
        s = trans + bar_string + task_part + counter_part
 
403
        if avail_width is not None:
 
404
            if len(s) < avail_width:
 
405
                s = s.ljust(avail_width)
 
406
            elif len(s) > avail_width:
 
407
                s = s[:avail_width]
 
408
        return s
382
409
 
383
410
    def _repaint(self):
384
411
        s = self._render_line()
440
467
            rate = (self._bytes_since_update
441
468
                    / (now - self._transport_update_time))
442
469
            # using base-10 units (see HACKING.txt).
443
 
            msg = ("%6dkB %5dkB/s" %
 
470
            msg = ("%6dkB %5dkB/s " %
444
471
                    (self._total_byte_count / 1000, int(rate) / 1000,))
445
472
            self._transport_update_time = now
446
473
            self._last_repaint = now