1
# Copyright (C) 2005, 2006, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005 Aaron Bentley <aaron.bentley@utoronto.ca>
2
# Copyright (C) 2005, 2006 Canonical Ltd
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
18
19
"""Progress indicators.
20
21
The usual way to use this is via bzrlib.ui.ui_factory.nested_progress_bar which
21
will manage a conceptual stack of nested activities.
22
will maintain a ProgressBarStack for you.
24
For direct use, the factory ProgressBar will return an auto-detected progress
25
bar that should match your terminal type. You can manually create a
26
ProgressBarStack too if you need multiple levels of cooperating progress bars.
27
Note that bzrlib's internal functions use the ui module, so if you are using
28
bzrlib it really is best to use bzrlib.ui.ui_factory.
31
# TODO: Optionally show elapsed time instead/as well as ETA; nicer
32
# when the rate is unpredictable
38
from bzrlib.lazy_import import lazy_import
39
lazy_import(globals(), """
31
40
from bzrlib import (
37
45
from bzrlib.trace import mutter
38
from bzrlib.symbol_versioning import (
44
48
def _supports_progress(f):
61
class ProgressTask(object):
62
"""Model component of a progress indicator.
64
Most code that needs to indicate progress should update one of these,
65
and it will in turn update the display, if one is present.
67
Code updating the task may also set fields as hints about how to display
68
it: show_pct, show_spinner, show_eta, show_count, show_bar. UIs
69
will not necessarily respect all these fields.
72
def __init__(self, parent_task=None, ui_factory=None):
73
self._parent_task = parent_task
76
self.current_cnt = None
78
self.ui_factory = ui_factory
80
self.show_spinner = True
81
self.show_eta = False,
82
self.show_count = True
86
return '%s(%r/%r, msg=%r)' % (
87
self.__class__.__name__,
92
def update(self, msg, current_cnt=None, total_cnt=None):
94
self.current_cnt = current_cnt
96
self.total_cnt = total_cnt
97
self.ui_factory._progress_updated(self)
100
self.update(self.msg)
103
self.ui_factory._progress_finished(self)
105
def make_sub_task(self):
106
return ProgressTask(self, self.ui_factory)
108
def _overall_completion_fraction(self, child_fraction=0.0):
109
"""Return fractional completion of this task and its parents
111
Returns None if no completion can be computed."""
113
own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
116
if self._parent_task is None:
119
if own_fraction is None:
121
return self._parent_task._overall_completion_fraction(own_fraction)
123
def note(self, fmt_string, *args):
124
"""Record a note without disrupting the progress bar."""
125
# XXX: shouldn't be here; put it in mutter or the ui instead
127
self.ui_factory.note(fmt_string % args)
129
self.ui_factory.note(fmt_string)
132
# XXX: shouldn't be here; put it in mutter or the ui instead
133
self.ui_factory.clear_term()
65
_progress_bar_types = {}
136
68
def ProgressBar(to_file=None, **kwargs):
155
87
_progress_bar_types.keys())
156
88
return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
159
91
class ProgressBarStack(object):
160
"""A stack of progress bars.
162
This class is deprecated: instead, ask the ui factory for a new progress
163
task and finish it when it's done.
92
"""A stack of progress bars."""
166
@deprecated_method(deprecated_in((1, 12, 0)))
167
94
def __init__(self,
220
147
def return_pb(self, bar):
221
148
"""Return bar after its been used."""
222
149
if bar is not self._stack[-1]:
223
warnings.warn("%r is not currently active" % (bar,))
150
raise errors.MissingProgressBarFinish()
228
154
class _BaseProgressBar(object):
300
225
return DummyProgress(**kwargs)
228
_progress_bar_types['dummy'] = DummyProgress
229
_progress_bar_types['none'] = DummyProgress
303
232
class DotsProgressBar(_BaseProgressBar):
305
234
def __init__(self, **kwargs):
401
331
def update(self, msg, current_cnt=None, total_cnt=None,
403
"""Update and redraw progress bar.
333
"""Update and redraw progress bar."""
406
335
msg = self.last_msg
475
401
# make both fields the same size
476
402
t = '%i' % (self.last_total)
477
403
c = '%*i' % (len(t), self.last_cnt)
478
count_str = ' ' + c + '/' + t
404
count_str = ' ' + c + '/' + t
480
406
if self.show_bar:
481
407
# progress bar, if present, soaks up all remaining space
632
558
self.cur_phase += 1
633
559
self.pb.update(self.message, self.cur_phase, self.total)
636
_progress_bar_types = {}
637
_progress_bar_types['dummy'] = DummyProgress
638
_progress_bar_types['none'] = DummyProgress
639
_progress_bar_types['tty'] = TTYProgressBar
640
_progress_bar_types['dots'] = DotsProgressBar