31
30
from bzrlib import (
37
33
from bzrlib.trace import mutter
38
34
from bzrlib.symbol_versioning import (
44
41
def _supports_progress(f):
45
"""Detect if we can use pretty progress bars on the output stream f.
42
"""Detect if we can use pretty progress bars on file F.
47
44
If this returns true we expect that a human may be looking at that
48
45
output, and that we can repaint a line to update it.
47
This doesn't check the policy for whether we *should* use them.
50
49
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.
55
58
if os.environ.get('TERM') == 'dumb':
56
59
# e.g. emacs compile window
67
70
Code updating the task may also set fields as hints about how to display
68
71
it: show_pct, show_spinner, show_eta, show_count, show_bar. UIs
69
72
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
72
def __init__(self, parent_task=None, ui_factory=None):
84
def __init__(self, parent_task=None, ui_factory=None, progress_view=None):
73
85
"""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.
75
94
Normally you should not call this directly but rather through
76
95
`ui_factory.nested_progress_bar`.
80
99
self.total_cnt = None
81
100
self.current_cnt = None
102
# TODO: deprecate passing ui_factory
83
103
self.ui_factory = ui_factory
104
self.progress_view = progress_view
84
105
self.show_pct = False
85
106
self.show_spinner = True
86
107
self.show_eta = False,
87
108
self.show_count = True
88
109
self.show_bar = True
110
self.update_latency = 0.1
111
self.show_transport_activity = True
90
113
def __repr__(self):
91
114
return '%s(%r/%r, msg=%r)' % (
99
122
self.current_cnt = current_cnt
101
124
self.total_cnt = total_cnt
102
self.ui_factory._progress_updated(self)
125
if self.progress_view:
126
self.progress_view.show_progress(self)
128
self.ui_factory._progress_updated(self)
105
131
self.update(self.msg)
107
133
def finished(self):
108
self.ui_factory._progress_finished(self)
134
if self.progress_view:
135
self.progress_view.task_finished(self)
137
self.ui_factory._progress_finished(self)
110
139
def make_sub_task(self):
111
return ProgressTask(self, self.ui_factory)
140
return ProgressTask(self, ui_factory=self.ui_factory,
141
progress_view=self.progress_view)
113
143
def _overall_completion_fraction(self, child_fraction=0.0):
114
144
"""Return fractional completion of this task and its parents
127
157
own_fraction = 0.0
128
158
return self._parent_task._overall_completion_fraction(own_fraction)
160
@deprecated_method(deprecated_in((2, 1, 0)))
130
161
def note(self, fmt_string, *args):
131
"""Record a note without disrupting the progress bar."""
132
# XXX: shouldn't be here; put it in mutter or the ui instead
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.
134
169
self.ui_factory.note(fmt_string % args)
136
171
self.ui_factory.note(fmt_string)
139
# XXX: shouldn't be here; put it in mutter or the ui instead
140
self.ui_factory.clear_term()
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)))
143
188
def ProgressBar(to_file=None, **kwargs):
144
"""Abstract factory"""
189
"""Construct a progress bar.
191
Deprecated; ask the ui_factory for a progress task instead.
145
193
if to_file is None:
146
194
to_file = sys.stderr
147
195
requested_bar_type = os.environ.get('BZR_PROGRESS_BAR')
163
211
return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
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,))
214
# NOTE: This is also deprecated; you should provide a ProgressView instead.
235
215
class _BaseProgressBar(object):
237
217
def __init__(self,
278
258
self.to_messages_file.write(fmt_string % args)
279
259
self.to_messages_file.write('\n')
261
@deprecated_function(deprecated_in((1, 16, 0)))
281
262
def child_progress(self, **kwargs):
282
263
return ChildProgress(**kwargs)
310
291
class DotsProgressBar(_BaseProgressBar):
293
@deprecated_function(deprecated_in((1, 16, 0)))
312
294
def __init__(self, **kwargs):
313
295
_BaseProgressBar.__init__(self, **kwargs)
314
296
self.last_msg = None
360
340
SPIN_CHARS = r'/-\|'
342
@deprecated_function(deprecated_in((1, 16, 0)))
363
343
def __init__(self, **kwargs):
364
344
from bzrlib.osutils import terminal_width
365
345
_BaseProgressBar.__init__(self, **kwargs)
524
504
class ChildProgress(_BaseProgressBar):
525
505
"""A progress indicator that pushes its data to the parent"""
507
@deprecated_function(deprecated_in((1, 16, 0)))
527
508
def __init__(self, _stack, **kwargs):
528
509
_BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
529
510
self.parent = _stack.top()
565
546
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
585
549
def str_tdelta(delt):