/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
3882.8.4 by Martin Pool
All UI factories should support note()
132
    def note(self, fmt_string, *args):
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
133
        """Record a note without disrupting the progress bar."""
134
        # XXX: shouldn't be here; put it in mutter or the ui instead
3943.2.3 by Martin Pool
Don't do string interpolation if there are no arguments
135
        if args:
136
            self.ui_factory.note(fmt_string % args)
137
        else:
138
            self.ui_factory.note(fmt_string)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
139
140
    def clear(self):
141
        # XXX: shouldn't be here; put it in mutter or the ui instead
3882.8.2 by Martin Pool
ProgressTask holds a reference to the ui that displays it
142
        self.ui_factory.clear_term()
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
143
649 by Martin Pool
- some cleanups for the progressbar method
144
4415.1.1 by Martin Pool
Deprecate ProgressBar factory
145
@deprecated_function(deprecated_in((1, 16, 0)))
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
146
def ProgressBar(to_file=None, **kwargs):
4463.1.1 by Martin Pool
Update docstrings for recent progress changes
147
    """Construct a progress bar.
148
149
    Deprecated; ask the ui_factory for a progress task instead.
150
    """
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
151
    if to_file is None:
152
        to_file = sys.stderr
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
153
    requested_bar_type = os.environ.get('BZR_PROGRESS_BAR')
154
    # An value of '' or not set reverts to standard processing
155
    if requested_bar_type in (None, ''):
156
        if _supports_progress(to_file):
157
            return TTYProgressBar(to_file=to_file, **kwargs)
158
        else:
2599.1.1 by Martin Pool
Don't show dots progress indicatiors in noninteractive mode
159
            return DummyProgress(to_file=to_file, **kwargs)
964 by Martin Pool
- show progress on dumb terminals by printing dots
160
    else:
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
161
        # Minor sanitation to prevent spurious errors
162
        requested_bar_type = requested_bar_type.lower().strip()
163
        # TODO: jam 20060710 Arguably we shouldn't raise an exception
164
        #       but should instead just disable progress bars if we
165
        #       don't recognize the type
166
        if requested_bar_type not in _progress_bar_types:
167
            raise errors.InvalidProgressBarType(requested_bar_type,
168
                                                _progress_bar_types.keys())
169
        return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
170
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
171
964 by Martin Pool
- show progress on dumb terminals by printing dots
172
class _BaseProgressBar(object):
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
173
964 by Martin Pool
- show progress on dumb terminals by printing dots
174
    def __init__(self,
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
175
                 to_file=None,
964 by Martin Pool
- show progress on dumb terminals by printing dots
176
                 show_pct=False,
177
                 show_spinner=False,
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
178
                 show_eta=False,
964 by Martin Pool
- show progress on dumb terminals by printing dots
179
                 show_bar=True,
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
180
                 show_count=True,
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
181
                 to_messages_file=None,
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
182
                 _stack=None):
964 by Martin Pool
- show progress on dumb terminals by printing dots
183
        object.__init__(self)
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
184
        if to_file is None:
185
            to_file = sys.stderr
186
        if to_messages_file is None:
187
            to_messages_file = sys.stdout
964 by Martin Pool
- show progress on dumb terminals by printing dots
188
        self.to_file = to_file
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
189
        self.to_messages_file = to_messages_file
964 by Martin Pool
- show progress on dumb terminals by printing dots
190
        self.last_msg = None
191
        self.last_cnt = None
192
        self.last_total = None
193
        self.show_pct = show_pct
194
        self.show_spinner = show_spinner
195
        self.show_eta = show_eta
196
        self.show_bar = show_bar
197
        self.show_count = show_count
1594.1.1 by Robert Collins
Introduce new bzr progress bar api. ui_factory.nested_progress_bar.
198
        self._stack = _stack
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
199
        # seed throttler
200
        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
201
        now = time.time()
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
202
        # starting now
2745.6.52 by Andrew Bennetts
Revert bad change to bzrlib/progress.py
203
        self.start_time = now
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
204
        # next update should not throttle
205
        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.
206
207
    def finished(self):
208
        """Return this bar to its progress stack."""
209
        self.clear()
210
        self._stack.return_pb(self)
1104 by Martin Pool
- Add a simple UIFactory
211
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
212
    def note(self, fmt_string, *args, **kwargs):
213
        """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
214
        self.clear()
1558.7.9 by Aaron Bentley
Bad change. (broke tests). Reverted.
215
        self.to_messages_file.write(fmt_string % args)
216
        self.to_messages_file.write('\n')
1104 by Martin Pool
- Add a simple UIFactory
217
4415.1.4 by Martin Pool
Deprecate child_progress and ChildProgress and remove old tests
218
    @deprecated_function(deprecated_in((1, 16, 0)))
1551.2.29 by Aaron Bentley
Got stack handling under test
219
    def child_progress(self, **kwargs):
220
        return ChildProgress(**kwargs)
221
1534.11.7 by Robert Collins
Test and correct the problem with nested test logs breaking further in-test logs.
222
1104 by Martin Pool
- Add a simple UIFactory
223
class DummyProgress(_BaseProgressBar):
224
    """Progress-bar standin that does nothing.
225
226
    This can be used as the default argument for methods that
227
    take an optional progress indicator."""
3882.8.8 by Martin Pool
Progress and UI test cleanups
228
1104 by Martin Pool
- Add a simple UIFactory
229
    def tick(self):
230
        pass
231
232
    def update(self, msg=None, current=None, total=None):
233
        pass
234
1551.2.27 by Aaron Bentley
Got propogation under test
235
    def child_update(self, message, current, total):
236
        pass
237
1104 by Martin Pool
- Add a simple UIFactory
238
    def clear(self):
239
        pass
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
240
1534.5.6 by Robert Collins
split out converter logic into per-format objects.
241
    def note(self, fmt_string, *args, **kwargs):
242
        """See _BaseProgressBar.note()."""
1534.5.9 by Robert Collins
Advise users running upgrade on a checkout to also run it on the branch.
243
1551.2.29 by Aaron Bentley
Got stack handling under test
244
    def child_progress(self, **kwargs):
245
        return DummyProgress(**kwargs)
1534.5.9 by Robert Collins
Advise users running upgrade on a checkout to also run it on the branch.
246
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
247
964 by Martin Pool
- show progress on dumb terminals by printing dots
248
class DotsProgressBar(_BaseProgressBar):
1594.1.3 by Robert Collins
Fixup pb usage to use nested_progress_bar.
249
4415.1.6 by Martin Pool
Deprecate DotsProgressBar and TTYProgressBar
250
    @deprecated_function(deprecated_in((1, 16, 0)))
964 by Martin Pool
- show progress on dumb terminals by printing dots
251
    def __init__(self, **kwargs):
252
        _BaseProgressBar.__init__(self, **kwargs)
253
        self.last_msg = None
254
        self.need_nl = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
255
964 by Martin Pool
- show progress on dumb terminals by printing dots
256
    def tick(self):
257
        self.update()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
258
964 by Martin Pool
- show progress on dumb terminals by printing dots
259
    def update(self, msg=None, current_cnt=None, total_cnt=None):
260
        if msg and msg != self.last_msg:
261
            if self.need_nl:
262
                self.to_file.write('\n')
263
            self.to_file.write(msg + ': ')
264
            self.last_msg = msg
265
        self.need_nl = True
266
        self.to_file.write('.')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
267
964 by Martin Pool
- show progress on dumb terminals by printing dots
268
    def clear(self):
269
        if self.need_nl:
270
            self.to_file.write('\n')
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
271
        self.need_nl = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
272
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
273
    def child_update(self, message, current, total):
274
        self.tick()
1681.1.2 by Robert Collins
* bzrlib.ui.text.TextUIFactory now accepts a bar_type parameter which
275
1843.3.7 by John Arbash Meinel
new env var 'BZR_PROGRESS_BAR' to select the exact progress type
276
964 by Martin Pool
- show progress on dumb terminals by printing dots
277
class TTYProgressBar(_BaseProgressBar):
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
278
    """Progress bar display object.
279
280
    Several options are available to control the display.  These can
281
    be passed as parameters to the constructor or assigned at any time:
282
283
    show_pct
284
        Show percentage complete.
285
    show_spinner
286
        Show rotating baton.  This ticks over on every update even
287
        if the values don't change.
288
    show_eta
289
        Show predicted time-to-completion.
290
    show_bar
291
        Show bar graph.
292
    show_count
293
        Show numerical counts.
294
295
    The output file should be in line-buffered or unbuffered mode.
296
    """
297
    SPIN_CHARS = r'/-\|'
661 by Martin Pool
- limit rate at which progress bar is updated
298
4415.1.6 by Martin Pool
Deprecate DotsProgressBar and TTYProgressBar
299
    @deprecated_function(deprecated_in((1, 16, 0)))
964 by Martin Pool
- show progress on dumb terminals by printing dots
300
    def __init__(self, **kwargs):
1185.33.60 by Martin Pool
Use full terminal width for verbose test output.
301
        from bzrlib.osutils import terminal_width
964 by Martin Pool
- show progress on dumb terminals by printing dots
302
        _BaseProgressBar.__init__(self, **kwargs)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
303
        self.spin_pos = 0
1185.33.60 by Martin Pool
Use full terminal width for verbose test output.
304
        self.width = terminal_width()
1843.3.3 by John Arbash Meinel
Don't let the last_updates list grow without bound.
305
        self.last_updates = []
1843.3.4 by John Arbash Meinel
Remove get_eta's ability to modify last_updates.
306
        self._max_last_updates = 10
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
307
        self.child_fraction = 0
1843.3.1 by John Arbash Meinel
Don't clear anything if nothing has been written.
308
        self._have_output = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
309
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
310
    def throttle(self, old_msg):
964 by Martin Pool
- show progress on dumb terminals by printing dots
311
        """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.
312
        # 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
313
        # time.clock() is faster, but gives us CPU time, not wall-clock time
314
        now = time.time()
1793.1.1 by Aaron Bentley
Hide TTYProgressBars unless they last more than 1 second
315
        if self.start_time is not None and (now - self.start_time) < 1:
316
            return True
317
        if old_msg != self.last_msg:
318
            return False
1596.2.16 by Robert Collins
Microprofiling: progress.update was costing 0.01 ms per call in time.time.
319
        interval = now - self.last_update
320
        # if interval > 0
321
        if interval < self.MIN_PAUSE:
322
            return True
964 by Martin Pool
- show progress on dumb terminals by printing dots
323
1185.16.75 by Martin Pool
- improved eta estimation for progress bar
324
        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.
325
        # Don't let the queue grow without bound
326
        self.last_updates = self.last_updates[-self._max_last_updates:]
964 by Martin Pool
- show progress on dumb terminals by printing dots
327
        self.last_update = now
328
        return False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
329
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
330
    def tick(self):
3006.3.2 by Robert Collins
More formatting corrections.
331
        self.update(self.last_msg, self.last_cnt, self.last_total,
1551.2.27 by Aaron Bentley
Got propogation under test
332
                    self.child_fraction)
333
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
334
    def child_update(self, message, current, total):
1551.2.35 by Aaron Bentley
Fix division-by-zero
335
        if current is not None and total != 0:
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
336
            child_fraction = float(current) / total
337
            if self.last_cnt is None:
338
                pass
339
            elif self.last_cnt + child_fraction <= self.last_total:
340
                self.child_fraction = child_fraction
341
        if self.last_msg is None:
342
            self.last_msg = ''
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
343
        self.tick()
344
3006.3.1 by Robert Collins
Minor PEP8 changes.
345
    def update(self, msg, current_cnt=None, total_cnt=None,
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
346
            child_fraction=0):
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
347
        """Update and redraw progress bar.
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
348
        """
1534.11.1 by Robert Collins
Teach bzr selftest to use a progress bar in non verbose mode.
349
        if msg is None:
350
            msg = self.last_msg
351
352
        if total_cnt is None:
353
            total_cnt = self.last_total
354
1308 by Martin Pool
- make progress bar more tolerant of out-of-range values
355
        if current_cnt < 0:
356
            current_cnt = 0
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
357
1308 by Martin Pool
- make progress bar more tolerant of out-of-range values
358
        if current_cnt > total_cnt:
359
            total_cnt = current_cnt
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
360
361
        ## # optional corner case optimisation
1596.2.17 by Robert Collins
Notes on further progress tuning.
362
        ## # currently does not seem to fire so costs more than saved.
363
        ## # trivial optimal case:
364
        ## # NB if callers are doing a clear and restore with
365
        ## # the saved values, this will prevent that:
366
        ## # in that case add a restore method that calls
367
        ## # _do_update or some such
368
        ## if (self.last_msg == msg and
369
        ##     self.last_cnt == current_cnt and
370
        ##     self.last_total == total_cnt and
371
        ##     self.child_fraction == child_fraction):
372
        ##     return
373
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
374
        if msg is None:
375
            msg = ''
376
1570.1.9 by Robert Collins
Do not throttle updates to progress bars that change the message.
377
        old_msg = self.last_msg
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
378
        # save these for the tick() function
379
        self.last_msg = msg
380
        self.last_cnt = current_cnt
381
        self.last_total = total_cnt
1596.2.17 by Robert Collins
Notes on further progress tuning.
382
        self.child_fraction = child_fraction
383
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
384
        # each function call takes 20ms/4000 = 0.005 ms,
1596.2.17 by Robert Collins
Notes on further progress tuning.
385
        # but multiple that by 4000 calls -> starts to cost.
386
        # so anything to make this function call faster
387
        # 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
388
        if self.throttle(old_msg):
1596.2.17 by Robert Collins
Notes on further progress tuning.
389
            return
390
391
        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
392
            eta = get_eta(self.start_time, self.last_cnt + self.child_fraction,
1596.2.17 by Robert Collins
Notes on further progress tuning.
393
                    self.last_total, last_updates = self.last_updates)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
394
            eta_str = " " + str_tdelta(eta)
395
        else:
396
            eta_str = ""
397
398
        if self.show_spinner:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
399
            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
400
        else:
401
            spin_str = ''
402
403
        # always update this; it's also used for the bar
404
        self.spin_pos += 1
405
1596.2.17 by Robert Collins
Notes on further progress tuning.
406
        if self.show_pct and self.last_total and self.last_cnt:
407
            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
408
            pct_str = ' (%5.1f%%)' % pct
409
        else:
410
            pct_str = ''
411
412
        if not self.show_count:
413
            count_str = ''
1596.2.17 by Robert Collins
Notes on further progress tuning.
414
        elif self.last_cnt is None:
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
415
            count_str = ''
1596.2.17 by Robert Collins
Notes on further progress tuning.
416
        elif self.last_total is None:
417
            count_str = ' %i' % (self.last_cnt)
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
418
        else:
419
            # make both fields the same size
1596.2.17 by Robert Collins
Notes on further progress tuning.
420
            t = '%i' % (self.last_total)
421
            c = '%*i' % (len(t), self.last_cnt)
3882.7.6 by Martin Pool
Preliminary support for drawing network io into the progress bar
422
            count_str = ' ' + c + '/' + t
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
423
424
        if self.show_bar:
425
            # progress bar, if present, soaks up all remaining space
1596.2.17 by Robert Collins
Notes on further progress tuning.
426
            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
427
                   - len(eta_str) - len(count_str) - 3
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
428
1596.2.17 by Robert Collins
Notes on further progress tuning.
429
            if self.last_total:
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
430
                # number of markers highlighted in bar
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
431
                markers = int(round(float(cols) *
1596.2.17 by Robert Collins
Notes on further progress tuning.
432
                              (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
433
                bar_str = '[' + ('=' * markers).ljust(cols) + '] '
669 by Martin Pool
- don't show progress bar unless completion is known
434
            elif False:
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
435
                # don't know total, so can't show completion.
436
                # so just show an expanded spinning thingy
437
                m = self.spin_pos % cols
668 by Martin Pool
- fix sweeping bar progress indicator
438
                ms = (' ' * m + '*').ljust(cols)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
439
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
440
                bar_str = '[' + ms + '] '
669 by Martin Pool
- don't show progress bar unless completion is known
441
            else:
442
                bar_str = ''
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
443
        else:
444
            bar_str = ''
445
3882.8.1 by Martin Pool
Remove experimental transport display from TTYProgressBar
446
        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
447
            + pct_str + eta_str
2095.4.4 by mbp at sourcefrog
Truncate progress bar rather than complaining if it's too long
448
        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.
449
        self._have_output = True
658 by Martin Pool
- clean up and add a bunch of options to the progress indicator
450
        #self.to_file.flush()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
451
3006.3.2 by Robert Collins
More formatting corrections.
452
    def clear(self):
1843.3.1 by John Arbash Meinel
Don't clear anything if nothing has been written.
453
        if self._have_output:
454
            self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
455
        self._have_output = False
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
456
        #self.to_file.flush()
649 by Martin Pool
- some cleanups for the progressbar method
457
1551.2.27 by Aaron Bentley
Got propogation under test
458
1551.2.28 by Aaron Bentley
Ensure all ProgressBar implementations can be used as parents
459
class ChildProgress(_BaseProgressBar):
1551.2.27 by Aaron Bentley
Got propogation under test
460
    """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
461
4415.1.4 by Martin Pool
Deprecate child_progress and ChildProgress and remove old tests
462
    @deprecated_function(deprecated_in((1, 16, 0)))
1551.2.29 by Aaron Bentley
Got stack handling under test
463
    def __init__(self, _stack, **kwargs):
464
        _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
465
        self.parent = _stack.top()
1551.2.27 by Aaron Bentley
Got propogation under test
466
        self.current = None
467
        self.total = None
468
        self.child_fraction = 0
469
        self.message = None
470
471
    def update(self, msg, current_cnt=None, total_cnt=None):
472
        self.current = current_cnt
2592.6.11 by Robert Collins
* A progress bar has been added for knitpack -> knitpack fetching.
473
        if total_cnt is not None:
474
            self.total = total_cnt
1551.2.27 by Aaron Bentley
Got propogation under test
475
        self.message = msg
476
        self.child_fraction = 0
477
        self.tick()
478
479
    def child_update(self, message, current, total):
1551.2.35 by Aaron Bentley
Fix division-by-zero
480
        if current is None or total == 0:
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
481
            self.child_fraction = 0
482
        else:
483
            self.child_fraction = float(current) / total
1551.2.27 by Aaron Bentley
Got propogation under test
484
        self.tick()
485
486
    def tick(self):
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
487
        if self.current is None:
488
            count = None
489
        else:
490
            count = self.current+self.child_fraction
491
            if count > self.total:
1596.2.35 by Robert Collins
Subclass SequenceMatcher to get a slightly faster (in our case) find_longest_match routine.
492
                if __debug__:
493
                    mutter('clamping count of %d to %d' % (count, self.total))
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
494
                count = self.total
1551.2.27 by Aaron Bentley
Got propogation under test
495
        self.parent.child_update(self.message, count, self.total)
496
1551.2.29 by Aaron Bentley
Got stack handling under test
497
    def clear(self):
1551.2.30 by Aaron Bentley
Bugfixes to progress stuff
498
        pass
1551.2.29 by Aaron Bentley
Got stack handling under test
499
1558.8.6 by Aaron Bentley
Fix note implementation
500
    def note(self, *args, **kwargs):
1558.8.5 by Aaron Bentley
Pass note up the stack instead of using bzrlib.ui_factory
501
        self.parent.note(*args, **kwargs)
502
3146.6.1 by Aaron Bentley
InterDifferingSerializer shows a progress bar
503
648 by Martin Pool
- import aaron's progress-indicator code
504
def str_tdelta(delt):
505
    if delt is None:
506
        return "-:--:--"
660 by Martin Pool
- use plain unix time, not datetime module
507
    delt = int(round(delt))
508
    return '%d:%02d:%02d' % (delt/3600,
509
                             (delt/60) % 60,
510
                             delt % 60)
511
512
1185.16.75 by Martin Pool
- improved eta estimation for progress bar
513
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
514
    if start_time is None:
515
        return None
516
517
    if not total:
518
        return None
519
520
    if current < enough_samples:
521
        return None
522
523
    if current > total:
524
        return None                     # wtf?
525
2120.1.1 by John Arbash Meinel
Use time.time() because time.clock() is CPU time, not wall time
526
    elapsed = time.time() - start_time
660 by Martin Pool
- use plain unix time, not datetime module
527
528
    if elapsed < 2.0:                   # not enough time to estimate
529
        return None
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
530
660 by Martin Pool
- use plain unix time, not datetime module
531
    total_duration = float(elapsed) * float(total) / float(current)
532
1185.16.75 by Martin Pool
- improved eta estimation for progress bar
533
    if last_updates and len(last_updates) >= n_recent:
534
        avg = sum(last_updates) / float(len(last_updates))
535
        time_left = avg * (total - current)
536
537
        old_time_left = total_duration - elapsed
538
539
        # We could return the average, or some other value here
540
        return (time_left + old_time_left) / 2
541
660 by Martin Pool
- use plain unix time, not datetime module
542
    return total_duration - elapsed
648 by Martin Pool
- import aaron's progress-indicator code
543
649 by Martin Pool
- some cleanups for the progressbar method
544
1551.2.32 by Aaron Bentley
Handle progress phases more nicely in merge
545
class ProgressPhase(object):
546
    """Update progress object with the current phase"""
547
    def __init__(self, message, total, pb):
548
        object.__init__(self)
549
        self.pb = pb
550
        self.message = message
551
        self.total = total
552
        self.cur_phase = None
553
554
    def next_phase(self):
555
        if self.cur_phase is None:
556
            self.cur_phase = 0
557
        else:
558
            self.cur_phase += 1
559
        self.pb.update(self.message, self.cur_phase, self.total)
3882.7.7 by Martin Pool
Change progress bars to a more MVC style
560
561
562
_progress_bar_types = {}
563
_progress_bar_types['dummy'] = DummyProgress
564
_progress_bar_types['none'] = DummyProgress
565
_progress_bar_types['tty'] = TTYProgressBar
566
_progress_bar_types['dots'] = DotsProgressBar