13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
"""Progress indicators.
31
30
from bzrlib import (
37
33
from bzrlib.trace import mutter
38
34
from bzrlib.symbol_versioning import (
44
40
def _supports_progress(f):
45
"""Detect if we can use pretty progress bars on the output stream f.
41
"""Detect if we can use pretty progress bars on file F.
47
43
If this returns true we expect that a human may be looking at that
48
44
output, and that we can repaint a line to update it.
46
This doesn't check the policy for whether we *should* use them.
50
48
isatty = getattr(f, 'isatty', None)
53
# The following case also handles Win32 - on that platform $TERM is
54
# typically never set, so the case None is treated as a smart terminal,
55
# not dumb. <https://bugs.launchpad.net/bugs/334808> win32 files do have
56
# isatty methods that return true.
55
57
if os.environ.get('TERM') == 'dumb':
56
58
# e.g. emacs compile window
69
71
will not necessarily respect all these fields.
72
def __init__(self, parent_task=None, ui_factory=None):
74
def __init__(self, parent_task=None, ui_factory=None, progress_view=None):
75
"""Construct a new progress task.
77
:param parent_task: Enclosing ProgressTask or None.
79
:param progress_view: ProgressView to display this ProgressTask.
81
:param ui_factory: The UI factory that will display updates;
82
deprecated in favor of passing progress_view directly.
84
Normally you should not call this directly but rather through
85
`ui_factory.nested_progress_bar`.
73
87
self._parent_task = parent_task
74
88
self._last_update = 0
75
89
self.total_cnt = None
76
90
self.current_cnt = None
92
# TODO: deprecate passing ui_factory
78
93
self.ui_factory = ui_factory
94
self.progress_view = progress_view
79
95
self.show_pct = False
80
96
self.show_spinner = True
81
97
self.show_eta = False,
94
110
self.current_cnt = current_cnt
96
112
self.total_cnt = total_cnt
97
self.ui_factory._progress_updated(self)
113
if self.progress_view:
114
self.progress_view.show_progress(self)
116
self.ui_factory._progress_updated(self)
100
119
self.update(self.msg)
102
121
def finished(self):
103
self.ui_factory._progress_finished(self)
122
if self.progress_view:
123
self.progress_view.task_finished(self)
125
self.ui_factory._progress_finished(self)
105
127
def make_sub_task(self):
106
return ProgressTask(self, self.ui_factory)
128
return ProgressTask(self, ui_factory=self.ui_factory,
129
progress_view=self.progress_view)
108
131
def _overall_completion_fraction(self, child_fraction=0.0):
109
132
"""Return fractional completion of this task and its parents
112
135
if self.current_cnt is not None and self.total_cnt:
113
136
own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
138
# if this task has no estimation, it just passes on directly
139
# whatever the child has measured...
140
own_fraction = child_fraction
116
141
if self._parent_task is None:
117
142
return own_fraction
132
157
# XXX: shouldn't be here; put it in mutter or the ui instead
133
self.ui_factory.clear_term()
158
if self.progress_view:
159
self.progress_view.clear()
161
self.ui_factory.clear_term()
164
@deprecated_function(deprecated_in((1, 16, 0)))
136
165
def ProgressBar(to_file=None, **kwargs):
137
166
"""Abstract factory"""
138
167
if to_file is None:
156
185
return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
159
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.
166
@deprecated_method(deprecated_in((1, 12, 0)))
174
to_messages_file=None,
176
"""Setup the stack with the parameters the progress bars should have."""
179
if to_messages_file is None:
180
to_messages_file = sys.stdout
181
self._to_file = to_file
182
self._show_pct = show_pct
183
self._show_spinner = show_spinner
184
self._show_eta = show_eta
185
self._show_bar = show_bar
186
self._show_count = show_count
187
self._to_messages_file = to_messages_file
189
self._klass = klass or ProgressBar
192
if len(self._stack) != 0:
193
return self._stack[-1]
198
if len(self._stack) != 0:
199
return self._stack[0]
203
def get_nested(self):
204
"""Return a nested progress bar."""
205
if len(self._stack) == 0:
208
func = self.top().child_progress
209
new_bar = func(to_file=self._to_file,
210
show_pct=self._show_pct,
211
show_spinner=self._show_spinner,
212
show_eta=self._show_eta,
213
show_bar=self._show_bar,
214
show_count=self._show_count,
215
to_messages_file=self._to_messages_file,
217
self._stack.append(new_bar)
220
def return_pb(self, bar):
221
"""Return bar after its been used."""
222
if bar is not self._stack[-1]:
223
warnings.warn("%r is not currently active" % (bar,))
188
# NOTE: This is also deprecated; you should provide a ProgressView instead.
228
189
class _BaseProgressBar(object):
230
191
def __init__(self,
271
232
self.to_messages_file.write(fmt_string % args)
272
233
self.to_messages_file.write('\n')
235
@deprecated_function(deprecated_in((1, 16, 0)))
274
236
def child_progress(self, **kwargs):
275
237
return ChildProgress(**kwargs)
303
265
class DotsProgressBar(_BaseProgressBar):
267
@deprecated_function(deprecated_in((1, 16, 0)))
305
268
def __init__(self, **kwargs):
306
269
_BaseProgressBar.__init__(self, **kwargs)
307
270
self.last_msg = None
353
314
SPIN_CHARS = r'/-\|'
316
@deprecated_function(deprecated_in((1, 16, 0)))
356
317
def __init__(self, **kwargs):
357
318
from bzrlib.osutils import terminal_width
358
319
_BaseProgressBar.__init__(self, **kwargs)
517
478
class ChildProgress(_BaseProgressBar):
518
479
"""A progress indicator that pushes its data to the parent"""
481
@deprecated_function(deprecated_in((1, 16, 0)))
520
482
def __init__(self, _stack, **kwargs):
521
483
_BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
522
484
self.parent = _stack.top()
558
520
self.parent.note(*args, **kwargs)
561
class InstrumentedProgress(TTYProgressBar):
562
"""TTYProgress variant that tracks outcomes"""
564
def __init__(self, *args, **kwargs):
565
self.always_throttled = True
566
self.never_throttle = False
567
TTYProgressBar.__init__(self, *args, **kwargs)
569
def throttle(self, old_message):
570
if self.never_throttle:
573
result = TTYProgressBar.throttle(self, old_message)
575
self.always_throttled = False
578
523
def str_tdelta(delt):