30
31
from bzrlib import (
33
37
from bzrlib.trace import mutter
34
38
from bzrlib.symbol_versioning import (
41
44
def _supports_progress(f):
42
"""Detect if we can use pretty progress bars on file F.
45
"""Detect if we can use pretty progress bars on the output stream f.
44
47
If this returns true we expect that a human may be looking at that
45
48
output, and that we can repaint a line to update it.
47
This doesn't check the policy for whether we *should* use them.
49
50
isatty = getattr(f, 'isatty', None)
54
# The following case also handles Win32 - on that platform $TERM is
55
# typically never set, so the case None is treated as a smart terminal,
56
# not dumb. <https://bugs.launchpad.net/bugs/334808> win32 files do have
57
# isatty methods that return true.
58
55
if os.environ.get('TERM') == 'dumb':
59
56
# e.g. emacs compile window
70
67
Code updating the task may also set fields as hints about how to display
71
68
it: show_pct, show_spinner, show_eta, show_count, show_bar. UIs
72
69
will not necessarily respect all these fields.
74
:ivar update_latency: The interval (in seconds) at which the PB should be
75
updated. Setting this to zero suggests every update should be shown
78
:ivar show_transport_activity: If true (default), transport activity
79
will be shown when this task is drawn. Disable it if you're sure
80
that only irrelevant or uninteresting transport activity can occur
84
def __init__(self, parent_task=None, ui_factory=None, progress_view=None):
72
def __init__(self, parent_task=None, ui_factory=None):
85
73
"""Construct a new progress task.
87
:param parent_task: Enclosing ProgressTask or None.
89
:param progress_view: ProgressView to display this ProgressTask.
91
:param ui_factory: The UI factory that will display updates;
92
deprecated in favor of passing progress_view directly.
94
75
Normally you should not call this directly but rather through
95
76
`ui_factory.nested_progress_bar`.
99
80
self.total_cnt = None
100
81
self.current_cnt = None
102
# TODO: deprecate passing ui_factory
103
83
self.ui_factory = ui_factory
104
self.progress_view = progress_view
105
84
self.show_pct = False
106
85
self.show_spinner = True
107
86
self.show_eta = False,
108
87
self.show_count = True
109
88
self.show_bar = True
110
self.update_latency = 0.1
111
self.show_transport_activity = True
113
90
def __repr__(self):
114
91
return '%s(%r/%r, msg=%r)' % (
122
99
self.current_cnt = current_cnt
124
101
self.total_cnt = total_cnt
125
if self.progress_view:
126
self.progress_view.show_progress(self)
128
self.ui_factory._progress_updated(self)
102
self.ui_factory._progress_updated(self)
131
105
self.update(self.msg)
133
107
def finished(self):
134
if self.progress_view:
135
self.progress_view.task_finished(self)
137
self.ui_factory._progress_finished(self)
108
self.ui_factory._progress_finished(self)
139
110
def make_sub_task(self):
140
return ProgressTask(self, ui_factory=self.ui_factory,
141
progress_view=self.progress_view)
111
return ProgressTask(self, self.ui_factory)
143
113
def _overall_completion_fraction(self, child_fraction=0.0):
144
114
"""Return fractional completion of this task and its parents
157
127
own_fraction = 0.0
158
128
return self._parent_task._overall_completion_fraction(own_fraction)
160
@deprecated_method(deprecated_in((2, 1, 0)))
161
130
def note(self, fmt_string, *args):
162
"""Record a note without disrupting the progress bar.
164
Deprecated: use ui_factory.note() instead or bzrlib.trace. Note that
165
ui_factory.note takes just one string as the argument, not a format
166
string and arguments.
131
"""Record a note without disrupting the progress bar."""
132
# XXX: shouldn't be here; put it in mutter or the ui instead
169
134
self.ui_factory.note(fmt_string % args)
171
136
self.ui_factory.note(fmt_string)
174
# TODO: deprecate this method; the model object shouldn't be concerned
175
# with whether it's shown or not. Most callers use this because they
176
# want to write some different non-progress output to the screen, but
177
# they should probably instead use a stream that's synchronized with
178
# the progress output. It may be there is a model-level use for
179
# saying "this task's not active at the moment" but I don't see it. --
181
if self.progress_view:
182
self.progress_view.clear()
184
self.ui_factory.clear_term()
187
@deprecated_function(deprecated_in((1, 16, 0)))
139
# XXX: shouldn't be here; put it in mutter or the ui instead
140
self.ui_factory.clear_term()
188
143
def ProgressBar(to_file=None, **kwargs):
189
"""Construct a progress bar.
191
Deprecated; ask the ui_factory for a progress task instead.
144
"""Abstract factory"""
193
145
if to_file is None:
194
146
to_file = sys.stderr
195
147
requested_bar_type = os.environ.get('BZR_PROGRESS_BAR')
211
163
return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
214
# NOTE: This is also deprecated; you should provide a ProgressView instead.
166
class ProgressBarStack(object):
167
"""A stack of progress bars.
169
This class is deprecated: instead, ask the ui factory for a new progress
170
task and finish it when it's done.
173
@deprecated_method(deprecated_in((1, 12, 0)))
181
to_messages_file=None,
183
"""Setup the stack with the parameters the progress bars should have."""
186
if to_messages_file is None:
187
to_messages_file = sys.stdout
188
self._to_file = to_file
189
self._show_pct = show_pct
190
self._show_spinner = show_spinner
191
self._show_eta = show_eta
192
self._show_bar = show_bar
193
self._show_count = show_count
194
self._to_messages_file = to_messages_file
196
self._klass = klass or ProgressBar
199
if len(self._stack) != 0:
200
return self._stack[-1]
205
if len(self._stack) != 0:
206
return self._stack[0]
210
def get_nested(self):
211
"""Return a nested progress bar."""
212
if len(self._stack) == 0:
215
func = self.top().child_progress
216
new_bar = func(to_file=self._to_file,
217
show_pct=self._show_pct,
218
show_spinner=self._show_spinner,
219
show_eta=self._show_eta,
220
show_bar=self._show_bar,
221
show_count=self._show_count,
222
to_messages_file=self._to_messages_file,
224
self._stack.append(new_bar)
227
def return_pb(self, bar):
228
"""Return bar after its been used."""
229
if bar is not self._stack[-1]:
230
warnings.warn("%r is not currently active" % (bar,))
215
235
class _BaseProgressBar(object):
217
237
def __init__(self,
258
278
self.to_messages_file.write(fmt_string % args)
259
279
self.to_messages_file.write('\n')
261
@deprecated_function(deprecated_in((1, 16, 0)))
262
281
def child_progress(self, **kwargs):
263
282
return ChildProgress(**kwargs)
291
310
class DotsProgressBar(_BaseProgressBar):
293
@deprecated_function(deprecated_in((1, 16, 0)))
294
312
def __init__(self, **kwargs):
295
313
_BaseProgressBar.__init__(self, **kwargs)
296
314
self.last_msg = None
340
360
SPIN_CHARS = r'/-\|'
342
@deprecated_function(deprecated_in((1, 16, 0)))
343
363
def __init__(self, **kwargs):
344
364
from bzrlib.osutils import terminal_width
345
365
_BaseProgressBar.__init__(self, **kwargs)
504
524
class ChildProgress(_BaseProgressBar):
505
525
"""A progress indicator that pushes its data to the parent"""
507
@deprecated_function(deprecated_in((1, 16, 0)))
508
527
def __init__(self, _stack, **kwargs):
509
528
_BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
510
529
self.parent = _stack.top()
546
565
self.parent.note(*args, **kwargs)
568
class InstrumentedProgress(TTYProgressBar):
569
"""TTYProgress variant that tracks outcomes"""
571
def __init__(self, *args, **kwargs):
572
self.always_throttled = True
573
self.never_throttle = False
574
TTYProgressBar.__init__(self, *args, **kwargs)
576
def throttle(self, old_message):
577
if self.never_throttle:
580
result = TTYProgressBar.throttle(self, old_message)
582
self.always_throttled = False
549
585
def str_tdelta(delt):