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