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