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