/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3948.2.1 by Martin Pool
Add ProgressTask repr
1
# Copyright (C) 2005, 2006, 2008, 2009 Canonical Ltd
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
648 by Martin Pool
- import aaron's progress-indicator code
16
649 by Martin Pool
- some cleanups for the progressbar method
17
3006.3.3 by Robert Collins
Docstring improvement and remove TODO's from progres.py.
18
"""Progress indicators.
19
20
The usual way to use this is via bzrlib.ui.ui_factory.nested_progress_bar which
3948.2.4 by Martin Pool
Remove some obsolete progress docstring
21
will manage a conceptual stack of nested activities.
649 by Martin Pool
- some cleanups for the progressbar method
22
"""
23
934 by Martin Pool
todo
24
648 by Martin Pool
- import aaron's progress-indicator code
25
import sys
660 by Martin Pool
- use plain unix time, not datetime module
26
import time
964 by Martin Pool
- show progress on dumb terminals by printing dots
27
import os
3882.8.12 by Martin Pool
Give a warning, not an error, if a progress bar is not finished in order
28
import warnings
649 by Martin Pool
- some cleanups for the progressbar method
29
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
30
1996.3.32 by John Arbash Meinel
from bzrlib.ui lazy import progress, and make progress import lazily
31
from bzrlib import (
32
    errors,
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
33
    osutils,
34
    trace,
35
    ui,
1996.3.32 by John Arbash Meinel
from bzrlib.ui lazy import progress, and make progress import lazily
36
    )
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
37
from bzrlib.trace import mutter
3948.2.6 by Martin Pool
ProgressBarStack is deprecated
38
from bzrlib.symbol_versioning import (
4415.1.1 by Martin Pool
Deprecate ProgressBar factory
39
    deprecated_function,
3948.2.6 by Martin Pool
ProgressBarStack is deprecated
40
    deprecated_in,
41
    deprecated_method,
42
    )
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
43
44
4415.1.1 by Martin Pool
Deprecate ProgressBar factory
45
# XXX: deprecated; can be removed when the ProgressBar factory is removed
649 by Martin Pool
- some cleanups for the progressbar method
46
def _supports_progress(f):
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
47
    """Detect if we can use pretty progress bars on the output stream f.
48
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
49
    If this returns true we expect that a human may be looking at that
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
50
    output, and that we can repaint a line to update it.
51
    """
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
52
    isatty = getattr(f, 'isatty', None)
53
    if isatty is None:
695 by Martin Pool
- don't display progress bars on really dumb terminals
54
        return False
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
55
    if not isatty():
695 by Martin Pool
- don't display progress bars on really dumb terminals
56
        return False
57
    if os.environ.get('TERM') == 'dumb':
58
        # e.g. emacs compile window
59
        return False
60
    return True
649 by Martin Pool
- some cleanups for the progressbar method
61
62
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
63
class ProgressTask(object):
64
    """Model component of a progress indicator.
65
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
66
    Most code that needs to indicate progress should update one of these,
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
67
    and it will in turn update the display, if one is present.
3882.8.5 by Martin Pool
Progress tasks can indicate what kind of display is useful
68
69
    Code updating the task may also set fields as hints about how to display
70
    it: show_pct, show_spinner, show_eta, show_count, show_bar.  UIs
71
    will not necessarily respect all these fields.
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
72
    """
73
3882.8.2 by Martin Pool
ProgressTask holds a reference to the ui that displays it
74
    def __init__(self, parent_task=None, ui_factory=None):
4110.2.13 by Martin Pool
doc
75
        """Construct a new progress task.
76
77
        Normally you should not call this directly but rather through
78
        `ui_factory.nested_progress_bar`.
79
        """
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
80
        self._parent_task = parent_task
81
        self._last_update = 0
82
        self.total_cnt = None
83
        self.current_cnt = None
84
        self.msg = ''
3882.8.2 by Martin Pool
ProgressTask holds a reference to the ui that displays it
85
        self.ui_factory = ui_factory
3882.8.5 by Martin Pool
Progress tasks can indicate what kind of display is useful
86
        self.show_pct = False
87
        self.show_spinner = True
88
        self.show_eta = False,
89
        self.show_count = True
90
        self.show_bar = True
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
91
3948.2.1 by Martin Pool
Add ProgressTask repr
92
    def __repr__(self):
93
        return '%s(%r/%r, msg=%r)' % (
94
            self.__class__.__name__,
95
            self.current_cnt,
96
            self.total_cnt,
97
            self.msg)
98
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
99
    def update(self, msg, current_cnt=None, total_cnt=None):
100
        self.msg = msg
101
        self.current_cnt = current_cnt
102
        if total_cnt:
103
            self.total_cnt = total_cnt
3948.2.3 by Martin Pool
Make the interface from ProgressTask to ui more private
104
        self.ui_factory._progress_updated(self)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
105
3882.8.8 by Martin Pool
Progress and UI test cleanups
106
    def tick(self):
107
        self.update(self.msg)
108
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
109
    def finished(self):
3948.2.3 by Martin Pool
Make the interface from ProgressTask to ui more private
110
        self.ui_factory._progress_finished(self)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
111
112
    def make_sub_task(self):
3882.8.3 by Martin Pool
Move display of transport throughput into TextProgressView
113
        return ProgressTask(self, self.ui_factory)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
114
115
    def _overall_completion_fraction(self, child_fraction=0.0):
116
        """Return fractional completion of this task and its parents
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
117
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
118
        Returns None if no completion can be computed."""
4017.1.1 by John Arbash Meinel
Get a pb.tick() to work after calling pb.update()
119
        if self.current_cnt is not None and self.total_cnt:
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
120
            own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
121
        else:
4110.2.17 by Martin Pool
If one ProgressTask has no count, it passes through that of its child
122
            # if this task has no estimation, it just passes on directly
123
            # whatever the child has measured...
124
            own_fraction = child_fraction
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
125
        if self._parent_task is None:
126
            return own_fraction
127
        else:
128
            if own_fraction is None:
129
                own_fraction = 0.0
130
            return self._parent_task._overall_completion_fraction(own_fraction)
131
4471.2.2 by Martin Pool
Deprecate ProgressTask.note
132
    @deprecated_method(deprecated_in((1, 17, 0)))
3882.8.4 by Martin Pool
All UI factories should support note()
133
    def note(self, fmt_string, *args):
4471.2.2 by Martin Pool
Deprecate ProgressTask.note
134
        """Record a note without disrupting the progress bar.
135
        
136
        Deprecated: use ui_factory.note() instead or bzrlib.trace.  Note that
137
        ui_factory.note takes just one string as the argument, not a format
138
        string and arguments.
139
        """
3943.2.3 by Martin Pool
Don't do string interpolation if there are no arguments
140
        if args:
141
            self.ui_factory.note(fmt_string % args)
142
        else:
143
            self.ui_factory.note(fmt_string)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
144
145
    def clear(self):
4471.2.1 by Martin Pool
Comment on deprecating ProgressTask.clear
146
        # TODO: deprecate this method; the model object shouldn't be concerned
147
        # with whether it's shown or not.  Most callers use this because they
148
        # want to write some different non-progress output to the screen, but
149
        # they should probably instead use a stream that's synchronized with
150
        # the progress output.  It may be there is a model-level use for
151
        # saying "this task's not active at the moment" but I don't see it. --
152
        # mbp 20090623
3882.8.2 by Martin Pool
ProgressTask holds a reference to the ui that displays it
153
        self.ui_factory.clear_term()
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
154
649 by Martin Pool
- some cleanups for the progressbar method
155
4415.1.1 by Martin Pool
Deprecate ProgressBar factory
156
@deprecated_function(deprecated_in((1, 16, 0)))
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
157
def ProgressBar(to_file=None, **kwargs):
964 by Martin Pool
- show progress on dumb terminals by printing dots
158
    """Abstract factory"""
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
159
    if to_file is None:
160
        to_file = sys.stderr
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
161
    requested_bar_type = os.environ.get('BZR_PROGRESS_BAR')
162
    # An value of '' or not set reverts to standard processing
163
    if requested_bar_type in (None, ''):
164
        if _supports_progress(to_file):
165
            return TTYProgressBar(to_file=to_file, **kwargs)
166
        else:
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
167
            return DummyProgress(to_file=to_file, **kwargs)
964 by Martin Pool
- show progress on dumb terminals by printing dots
168
    else:
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
169
        # Minor sanitation to prevent spurious errors
170
        requested_bar_type = requested_bar_type.lower().strip()
171
        # TODO: jam 20060710 Arguably we shouldn't raise an exception
172
        #       but should instead just disable progress bars if we
173
        #       don't recognize the type
174
        if requested_bar_type not in _progress_bar_types:
175
            raise errors.InvalidProgressBarType(requested_bar_type,
176
                                                _progress_bar_types.keys())
177
        return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
178
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
179
964 by Martin Pool
- show progress on dumb terminals by printing dots
180
class _BaseProgressBar(object):
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
181
964 by Martin Pool
- show progress on dumb terminals by printing dots
182
    def __init__(self,
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
183
                 to_file=None,
964 by Martin Pool
- show progress on dumb terminals by printing dots
184
                 show_pct=False,
185
                 show_spinner=False,
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
186
                 show_eta=False,
964 by Martin Pool
- show progress on dumb terminals by printing dots
187
                 show_bar=True,
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
188
                 show_count=True,
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
189
                 to_messages_file=None,
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
190
                 _stack=None):
964 by Martin Pool
- show progress on dumb terminals by printing dots
191
        object.__init__(self)
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
192
        if to_file is None:
193
            to_file = sys.stderr
194
        if to_messages_file is None:
195
            to_messages_file = sys.stdout
964 by Martin Pool
- show progress on dumb terminals by printing dots
196
        self.to_file = to_file
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
197
        self.to_messages_file = to_messages_file
964 by Martin Pool
- show progress on dumb terminals by printing dots
198
        self.last_msg = None
199
        self.last_cnt = None
200
        self.last_total = None
201
        self.show_pct = show_pct
202
        self.show_spinner = show_spinner
203
        self.show_eta = show_eta
204
        self.show_bar = show_bar
205
        self.show_count = show_count
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
206
        self._stack = _stack
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
207
        # seed throttler
208
        self.MIN_PAUSE = 0.1 # seconds
2120.1.1 by John Arbash Meinel
Use time.time() because time.clock() is CPU time, not wall time
209
        now = time.time()
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
210
        # starting now
2745.6.52 by Andrew Bennetts
Revert bad change to bzrlib/progress.py
211
        self.start_time = now
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
212
        # next update should not throttle
213
        self.last_update = now - self.MIN_PAUSE - 1
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
214
215
    def finished(self):
216
        """Return this bar to its progress stack."""
217
        self.clear()
218
        self._stack.return_pb(self)
1104 by Martin Pool
- Add a simple UIFactory
219
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
220
    def note(self, fmt_string, *args, **kwargs):
221
        """Record a note without disrupting the progress bar."""
1558.8.5 by Aaron Bentley
Pass note up the stack instead of using bzrlib.ui_factory
222
        self.clear()
1558.7.9 by Aaron Bentley
Bad change. (broke tests). Reverted.
223
        self.to_messages_file.write(fmt_string % args)
224
        self.to_messages_file.write('\n')
1104 by Martin Pool
- Add a simple UIFactory
225
4415.1.4 by Martin Pool
Deprecate child_progress and ChildProgress and remove old tests
226
    @deprecated_function(deprecated_in((1, 16, 0)))
1551.2.29 by Aaron Bentley
Got stack handling under test
227
    def child_progress(self, **kwargs):
228
        return ChildProgress(**kwargs)
229
1534.11.7 by Robert Collins
Test and correct the problem with nested test logs breaking further in-test logs.
230
1104 by Martin Pool
- Add a simple UIFactory
231
class DummyProgress(_BaseProgressBar):
232
    """Progress-bar standin that does nothing.
233
234
    This can be used as the default argument for methods that
235
    take an optional progress indicator."""
3882.8.8 by Martin Pool
Progress and UI test cleanups
236
1104 by Martin Pool
- Add a simple UIFactory
237
    def tick(self):
238
        pass
239
240
    def update(self, msg=None, current=None, total=None):
241
        pass
242
1551.2.27 by Aaron Bentley
Got propogation under test
243
    def child_update(self, message, current, total):
244
        pass
245
1104 by Martin Pool
- Add a simple UIFactory
246
    def clear(self):
247
        pass
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
248
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
249
    def note(self, fmt_string, *args, **kwargs):
250
        """See _BaseProgressBar.note()."""
1534.5.9 by Robert Collins
Advise users running upgrade on a checkout to also run it on the branch.
251
1551.2.29 by Aaron Bentley
Got stack handling under test
252
    def child_progress(self, **kwargs):
253
        return DummyProgress(**kwargs)
1534.5.9 by Robert Collins
Advise users running upgrade on a checkout to also run it on the branch.
254
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
255
964 by Martin Pool
- show progress on dumb terminals by printing dots
256
class DotsProgressBar(_BaseProgressBar):
1594.1.3 by Robert Collins
Fixup pb usage to use nested_progress_bar.
257
4415.1.6 by Martin Pool
Deprecate DotsProgressBar and TTYProgressBar
258
    @deprecated_function(deprecated_in((1, 16, 0)))
964 by Martin Pool
- show progress on dumb terminals by printing dots
259
    def __init__(self, **kwargs):
260
        _BaseProgressBar.__init__(self, **kwargs)
261
        self.last_msg = None
262
        self.need_nl = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
263
964 by Martin Pool
- show progress on dumb terminals by printing dots
264
    def tick(self):
265
        self.update()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
266
964 by Martin Pool
- show progress on dumb terminals by printing dots
267
    def update(self, msg=None, current_cnt=None, total_cnt=None):
268
        if msg and msg != self.last_msg:
269
            if self.need_nl:
270
                self.to_file.write('\n')
271
            self.to_file.write(msg + ': ')
272
            self.last_msg = msg
273
        self.need_nl = True
274
        self.to_file.write('.')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
275
964 by Martin Pool
- show progress on dumb terminals by printing dots
276
    def clear(self):
277
        if self.need_nl:
278
            self.to_file.write('\n')
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
279
        self.need_nl = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
280
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
281
    def child_update(self, message, current, total):
282
        self.tick()
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
283
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
284
964 by Martin Pool
- show progress on dumb terminals by printing dots
285
class TTYProgressBar(_BaseProgressBar):
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
286
    """Progress bar display object.
287
288
    Several options are available to control the display.  These can
289
    be passed as parameters to the constructor or assigned at any time:
290
291
    show_pct
292
        Show percentage complete.
293
    show_spinner
294
        Show rotating baton.  This ticks over on every update even
295
        if the values don't change.
296
    show_eta
297
        Show predicted time-to-completion.
298
    show_bar
299
        Show bar graph.
300
    show_count
301
        Show numerical counts.
302
303
    The output file should be in line-buffered or unbuffered mode.
304
    """
305
    SPIN_CHARS = r'/-\|'
661 by Martin Pool
- limit rate at which progress bar is updated
306
4415.1.6 by Martin Pool
Deprecate DotsProgressBar and TTYProgressBar
307
    @deprecated_function(deprecated_in((1, 16, 0)))
964 by Martin Pool
- show progress on dumb terminals by printing dots
308
    def __init__(self, **kwargs):
1185.33.60 by Martin Pool
Use full terminal width for verbose test output.
309
        from bzrlib.osutils import terminal_width
964 by Martin Pool
- show progress on dumb terminals by printing dots
310
        _BaseProgressBar.__init__(self, **kwargs)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
311
        self.spin_pos = 0
1185.33.60 by Martin Pool
Use full terminal width for verbose test output.
312
        self.width = terminal_width()
1843.3.3 by John Arbash Meinel
Don't let the last_updates list grow without bound.
313
        self.last_updates = []
1843.3.4 by John Arbash Meinel
Remove get_eta's ability to modify last_updates.
314
        self._max_last_updates = 10
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
315
        self.child_fraction = 0
1843.3.1 by John Arbash Meinel
Don't clear anything if nothing has been written.
316
        self._have_output = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
317
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
318
    def throttle(self, old_msg):
964 by Martin Pool
- show progress on dumb terminals by printing dots
319
        """Return True if the bar was updated too recently"""
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
320
        # time.time consistently takes 40/4000 ms = 0.01 ms.
2120.1.1 by John Arbash Meinel
Use time.time() because time.clock() is CPU time, not wall time
321
        # time.clock() is faster, but gives us CPU time, not wall-clock time
322
        now = time.time()
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
323
        if self.start_time is not None and (now - self.start_time) < 1:
324
            return True
325
        if old_msg != self.last_msg:
326
            return False
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
327
        interval = now - self.last_update
328
        # if interval > 0
329
        if interval < self.MIN_PAUSE:
330
            return True
964 by Martin Pool
- show progress on dumb terminals by printing dots
331
1185.16.75 by Martin Pool
- improved eta estimation for progress bar
332
        self.last_updates.append(now - self.last_update)
1843.3.3 by John Arbash Meinel
Don't let the last_updates list grow without bound.
333
        # Don't let the queue grow without bound
334
        self.last_updates = self.last_updates[-self._max_last_updates:]
964 by Martin Pool
- show progress on dumb terminals by printing dots
335
        self.last_update = now
336
        return False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
337
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
338
    def tick(self):
3006.3.2 by Robert Collins
More formatting corrections.
339
        self.update(self.last_msg, self.last_cnt, self.last_total,
1551.2.27 by Aaron Bentley
Got propogation under test
340
                    self.child_fraction)
341
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
342
    def child_update(self, message, current, total):
1551.2.35 by Aaron Bentley
Fix division-by-zero
343
        if current is not None and total != 0:
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
344
            child_fraction = float(current) / total
345
            if self.last_cnt is None:
346
                pass
347
            elif self.last_cnt + child_fraction <= self.last_total:
348
                self.child_fraction = child_fraction
349
        if self.last_msg is None:
350
            self.last_msg = ''
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
351
        self.tick()
352
3006.3.1 by Robert Collins
Minor PEP8 changes.
353
    def update(self, msg, current_cnt=None, total_cnt=None,
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
354
            child_fraction=0):
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
355
        """Update and redraw progress bar.
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
356
        """
1534.11.1 by Robert Collins
Teach bzr selftest to use a progress bar in non verbose mode.
357
        if msg is None:
358
            msg = self.last_msg
359
360
        if total_cnt is None:
361
            total_cnt = self.last_total
362
1308 by Martin Pool
- make progress bar more tolerant of out-of-range values
363
        if current_cnt < 0:
364
            current_cnt = 0
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
365
1308 by Martin Pool
- make progress bar more tolerant of out-of-range values
366
        if current_cnt > total_cnt:
367
            total_cnt = current_cnt
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
368
369
        ## # optional corner case optimisation
1596.2.17 by Robert Collins
Notes on further progress tuning.
370
        ## # currently does not seem to fire so costs more than saved.
371
        ## # trivial optimal case:
372
        ## # NB if callers are doing a clear and restore with
373
        ## # the saved values, this will prevent that:
374
        ## # in that case add a restore method that calls
375
        ## # _do_update or some such
376
        ## if (self.last_msg == msg and
377
        ##     self.last_cnt == current_cnt and
378
        ##     self.last_total == total_cnt and
379
        ##     self.child_fraction == child_fraction):
380
        ##     return
381
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
382
        if msg is None:
383
            msg = ''
384
1570.1.9 by Robert Collins
Do not throttle updates to progress bars that change the message.
385
        old_msg = self.last_msg
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
386
        # save these for the tick() function
387
        self.last_msg = msg
388
        self.last_cnt = current_cnt
389
        self.last_total = total_cnt
1596.2.17 by Robert Collins
Notes on further progress tuning.
390
        self.child_fraction = child_fraction
391
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
392
        # each function call takes 20ms/4000 = 0.005 ms,
1596.2.17 by Robert Collins
Notes on further progress tuning.
393
        # but multiple that by 4000 calls -> starts to cost.
394
        # so anything to make this function call faster
395
        # will improve base 'diff' time by up to 0.1 seconds.
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
396
        if self.throttle(old_msg):
1596.2.17 by Robert Collins
Notes on further progress tuning.
397
            return
398
399
        if self.show_eta and self.start_time and self.last_total:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
400
            eta = get_eta(self.start_time, self.last_cnt + self.child_fraction,
1596.2.17 by Robert Collins
Notes on further progress tuning.
401
                    self.last_total, last_updates = self.last_updates)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
402
            eta_str = " " + str_tdelta(eta)
403
        else:
404
            eta_str = ""
405
406
        if self.show_spinner:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
407
            spin_str = self.SPIN_CHARS[self.spin_pos % 4] + ' '
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
408
        else:
409
            spin_str = ''
410
411
        # always update this; it's also used for the bar
412
        self.spin_pos += 1
413
1596.2.17 by Robert Collins
Notes on further progress tuning.
414
        if self.show_pct and self.last_total and self.last_cnt:
415
            pct = 100.0 * ((self.last_cnt + self.child_fraction) / self.last_total)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
416
            pct_str = ' (%5.1f%%)' % pct
417
        else:
418
            pct_str = ''
419
420
        if not self.show_count:
421
            count_str = ''
1596.2.17 by Robert Collins
Notes on further progress tuning.
422
        elif self.last_cnt is None:
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
423
            count_str = ''
1596.2.17 by Robert Collins
Notes on further progress tuning.
424
        elif self.last_total is None:
425
            count_str = ' %i' % (self.last_cnt)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
426
        else:
427
            # make both fields the same size
1596.2.17 by Robert Collins
Notes on further progress tuning.
428
            t = '%i' % (self.last_total)
429
            c = '%*i' % (len(t), self.last_cnt)
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
430
            count_str = ' ' + c + '/' + t
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
431
432
        if self.show_bar:
433
            # progress bar, if present, soaks up all remaining space
1596.2.17 by Robert Collins
Notes on further progress tuning.
434
            cols = self.width - 1 - len(self.last_msg) - len(spin_str) - len(pct_str) \
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
435
                   - len(eta_str) - len(count_str) - 3
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
436
1596.2.17 by Robert Collins
Notes on further progress tuning.
437
            if self.last_total:
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
438
                # number of markers highlighted in bar
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
439
                markers = int(round(float(cols) *
1596.2.17 by Robert Collins
Notes on further progress tuning.
440
                              (self.last_cnt + self.child_fraction) / self.last_total))
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
441
                bar_str = '[' + ('=' * markers).ljust(cols) + '] '
669 by Martin Pool
- don't show progress bar unless completion is known
442
            elif False:
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
443
                # don't know total, so can't show completion.
444
                # so just show an expanded spinning thingy
445
                m = self.spin_pos % cols
668 by Martin Pool
- fix sweeping bar progress indicator
446
                ms = (' ' * m + '*').ljust(cols)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
447
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
448
                bar_str = '[' + ms + '] '
669 by Martin Pool
- don't show progress bar unless completion is known
449
            else:
450
                bar_str = ''
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
451
        else:
452
            bar_str = ''
453
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
454
        m = spin_str + bar_str + self.last_msg + count_str \
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
455
            + pct_str + eta_str
2095.4.4 by mbp at sourcefrog
Truncate progress bar rather than complaining if it's too long
456
        self.to_file.write('\r%-*.*s' % (self.width - 1, self.width - 1, m))
1843.3.1 by John Arbash Meinel
Don't clear anything if nothing has been written.
457
        self._have_output = True
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
458
        #self.to_file.flush()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
459
3006.3.2 by Robert Collins
More formatting corrections.
460
    def clear(self):
1843.3.1 by John Arbash Meinel
Don't clear anything if nothing has been written.
461
        if self._have_output:
462
            self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
463
        self._have_output = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
464
        #self.to_file.flush()
649 by Martin Pool
- some cleanups for the progressbar method
465
1551.2.27 by Aaron Bentley
Got propogation under test
466
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
467
class ChildProgress(_BaseProgressBar):
1551.2.27 by Aaron Bentley
Got propogation under test
468
    """A progress indicator that pushes its data to the parent"""
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
469
4415.1.4 by Martin Pool
Deprecate child_progress and ChildProgress and remove old tests
470
    @deprecated_function(deprecated_in((1, 16, 0)))
1551.2.29 by Aaron Bentley
Got stack handling under test
471
    def __init__(self, _stack, **kwargs):
472
        _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
473
        self.parent = _stack.top()
1551.2.27 by Aaron Bentley
Got propogation under test
474
        self.current = None
475
        self.total = None
476
        self.child_fraction = 0
477
        self.message = None
478
479
    def update(self, msg, current_cnt=None, total_cnt=None):
480
        self.current = current_cnt
2592.6.11 by Robert Collins
* A progress bar has been added for knitpack -> knitpack fetching.
481
        if total_cnt is not None:
482
            self.total = total_cnt
1551.2.27 by Aaron Bentley
Got propogation under test
483
        self.message = msg
484
        self.child_fraction = 0
485
        self.tick()
486
487
    def child_update(self, message, current, total):
1551.2.35 by Aaron Bentley
Fix division-by-zero
488
        if current is None or total == 0:
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
489
            self.child_fraction = 0
490
        else:
491
            self.child_fraction = float(current) / total
1551.2.27 by Aaron Bentley
Got propogation under test
492
        self.tick()
493
494
    def tick(self):
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
495
        if self.current is None:
496
            count = None
497
        else:
498
            count = self.current+self.child_fraction
499
            if count > self.total:
1596.2.35 by Robert Collins
Subclass SequenceMatcher to get a slightly faster (in our case) find_longest_match routine.
500
                if __debug__:
501
                    mutter('clamping count of %d to %d' % (count, self.total))
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
502
                count = self.total
1551.2.27 by Aaron Bentley
Got propogation under test
503
        self.parent.child_update(self.message, count, self.total)
504
1551.2.29 by Aaron Bentley
Got stack handling under test
505
    def clear(self):
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
506
        pass
1551.2.29 by Aaron Bentley
Got stack handling under test
507
1558.8.6 by Aaron Bentley
Fix note implementation
508
    def note(self, *args, **kwargs):
1558.8.5 by Aaron Bentley
Pass note up the stack instead of using bzrlib.ui_factory
509
        self.parent.note(*args, **kwargs)
510
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
511
648 by Martin Pool
- import aaron's progress-indicator code
512
def str_tdelta(delt):
513
    if delt is None:
514
        return "-:--:--"
660 by Martin Pool
- use plain unix time, not datetime module
515
    delt = int(round(delt))
516
    return '%d:%02d:%02d' % (delt/3600,
517
                             (delt/60) % 60,
518
                             delt % 60)
519
520
1185.16.75 by Martin Pool
- improved eta estimation for progress bar
521
def get_eta(start_time, current, total, enough_samples=3, last_updates=None, n_recent=10):
660 by Martin Pool
- use plain unix time, not datetime module
522
    if start_time is None:
523
        return None
524
525
    if not total:
526
        return None
527
528
    if current < enough_samples:
529
        return None
530
531
    if current > total:
532
        return None                     # wtf?
533
2120.1.1 by John Arbash Meinel
Use time.time() because time.clock() is CPU time, not wall time
534
    elapsed = time.time() - start_time
660 by Martin Pool
- use plain unix time, not datetime module
535
536
    if elapsed < 2.0:                   # not enough time to estimate
537
        return None
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
538
660 by Martin Pool
- use plain unix time, not datetime module
539
    total_duration = float(elapsed) * float(total) / float(current)
540
1185.16.75 by Martin Pool
- improved eta estimation for progress bar
541
    if last_updates and len(last_updates) >= n_recent:
542
        avg = sum(last_updates) / float(len(last_updates))
543
        time_left = avg * (total - current)
544
545
        old_time_left = total_duration - elapsed
546
547
        # We could return the average, or some other value here
548
        return (time_left + old_time_left) / 2
549
660 by Martin Pool
- use plain unix time, not datetime module
550
    return total_duration - elapsed
648 by Martin Pool
- import aaron's progress-indicator code
551
649 by Martin Pool
- some cleanups for the progressbar method
552
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
553
class ProgressPhase(object):
554
    """Update progress object with the current phase"""
555
    def __init__(self, message, total, pb):
556
        object.__init__(self)
557
        self.pb = pb
558
        self.message = message
559
        self.total = total
560
        self.cur_phase = None
561
562
    def next_phase(self):
563
        if self.cur_phase is None:
564
            self.cur_phase = 0
565
        else:
566
            self.cur_phase += 1
567
        self.pb.update(self.message, self.cur_phase, self.total)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
568
569
570
_progress_bar_types = {}
571
_progress_bar_types['dummy'] = DummyProgress
572
_progress_bar_types['none'] = DummyProgress
573
_progress_bar_types['tty'] = TTYProgressBar
574
_progress_bar_types['dots'] = DotsProgressBar