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