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