~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

  • Committer: John Arbash Meinel
  • Date: 2008-07-11 21:41:24 UTC
  • mto: This revision was merged to the branch mainline in revision 3543.
  • Revision ID: john@arbash-meinel.com-20080711214124-qi09irlj7pd5cuzg
Shortcut the case when one revision is in the ancestry of the other.

At the cost of a heads() check, when one parent supersedes, we don't have to extract
the text for the other. Changes merge time from 3m37s => 3m21s. Using a
CachingParentsProvider would drop the time down to 3m11s.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005 Aaron Bentley <aaron.bentley@utoronto.ca>
 
2
# Copyright (C) 2005, 2006 Canonical Ltd
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
18
19
"""Progress indicators.
19
20
 
20
21
The usual way to use this is via bzrlib.ui.ui_factory.nested_progress_bar which
21
 
will manage a conceptual stack of nested activities.
 
22
will maintain a ProgressBarStack for you.
 
23
 
 
24
For direct use, the factory ProgressBar will return an auto-detected progress
 
25
bar that should match your terminal type. You can manually create a
 
26
ProgressBarStack too if you need multiple levels of cooperating progress bars.
 
27
Note that bzrlib's internal functions use the ui module, so if you are using
 
28
bzrlib it really is best to use bzrlib.ui.ui_factory.
22
29
"""
23
30
 
 
31
# TODO: Optionally show elapsed time instead/as well as ETA; nicer
 
32
# when the rate is unpredictable
24
33
 
25
34
import sys
26
35
import time
27
36
import os
28
 
import warnings
29
 
 
30
 
 
 
37
 
 
38
from bzrlib.lazy_import import lazy_import
 
39
lazy_import(globals(), """
31
40
from bzrlib import (
32
41
    errors,
33
 
    osutils,
34
 
    trace,
35
 
    ui,
36
42
    )
 
43
""")
 
44
 
37
45
from bzrlib.trace import mutter
38
 
from bzrlib.symbol_versioning import (
39
 
    deprecated_in,
40
 
    deprecated_method,
41
 
    )
42
46
 
43
47
 
44
48
def _supports_progress(f):
58
62
    return True
59
63
 
60
64
 
61
 
class ProgressTask(object):
62
 
    """Model component of a progress indicator.
63
 
 
64
 
    Most code that needs to indicate progress should update one of these, 
65
 
    and it will in turn update the display, if one is present.
66
 
 
67
 
    Code updating the task may also set fields as hints about how to display
68
 
    it: show_pct, show_spinner, show_eta, show_count, show_bar.  UIs
69
 
    will not necessarily respect all these fields.
70
 
    """
71
 
 
72
 
    def __init__(self, parent_task=None, ui_factory=None):
73
 
        self._parent_task = parent_task
74
 
        self._last_update = 0
75
 
        self.total_cnt = None
76
 
        self.current_cnt = None
77
 
        self.msg = ''
78
 
        self.ui_factory = ui_factory
79
 
        self.show_pct = False
80
 
        self.show_spinner = True
81
 
        self.show_eta = False,
82
 
        self.show_count = True
83
 
        self.show_bar = True
84
 
 
85
 
    def __repr__(self):
86
 
        return '%s(%r/%r, msg=%r)' % (
87
 
            self.__class__.__name__,
88
 
            self.current_cnt,
89
 
            self.total_cnt,
90
 
            self.msg)
91
 
 
92
 
    def update(self, msg, current_cnt=None, total_cnt=None):
93
 
        self.msg = msg
94
 
        self.current_cnt = current_cnt
95
 
        if total_cnt:
96
 
            self.total_cnt = total_cnt
97
 
        self.ui_factory._progress_updated(self)
98
 
 
99
 
    def tick(self):
100
 
        self.update(self.msg)
101
 
 
102
 
    def finished(self):
103
 
        self.ui_factory._progress_finished(self)
104
 
 
105
 
    def make_sub_task(self):
106
 
        return ProgressTask(self, self.ui_factory)
107
 
 
108
 
    def _overall_completion_fraction(self, child_fraction=0.0):
109
 
        """Return fractional completion of this task and its parents
110
 
        
111
 
        Returns None if no completion can be computed."""
112
 
        if self.total_cnt:
113
 
            own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
114
 
        else:
115
 
            own_fraction = None
116
 
        if self._parent_task is None:
117
 
            return own_fraction
118
 
        else:
119
 
            if own_fraction is None:
120
 
                own_fraction = 0.0
121
 
            return self._parent_task._overall_completion_fraction(own_fraction)
122
 
 
123
 
    def note(self, fmt_string, *args):
124
 
        """Record a note without disrupting the progress bar."""
125
 
        # XXX: shouldn't be here; put it in mutter or the ui instead
126
 
        if args:
127
 
            self.ui_factory.note(fmt_string % args)
128
 
        else:
129
 
            self.ui_factory.note(fmt_string)
130
 
 
131
 
    def clear(self):
132
 
        # XXX: shouldn't be here; put it in mutter or the ui instead
133
 
        self.ui_factory.clear_term()
 
65
_progress_bar_types = {}
134
66
 
135
67
 
136
68
def ProgressBar(to_file=None, **kwargs):
155
87
                                                _progress_bar_types.keys())
156
88
        return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
157
89
 
158
 
 
 
90
 
159
91
class ProgressBarStack(object):
160
 
    """A stack of progress bars.
161
 
    
162
 
    This class is deprecated: instead, ask the ui factory for a new progress
163
 
    task and finish it when it's done.
164
 
    """
 
92
    """A stack of progress bars."""
165
93
 
166
 
    @deprecated_method(deprecated_in((1, 12, 0)))
167
94
    def __init__(self,
168
95
                 to_file=None,
169
96
                 show_pct=False,
220
147
    def return_pb(self, bar):
221
148
        """Return bar after its been used."""
222
149
        if bar is not self._stack[-1]:
223
 
            warnings.warn("%r is not currently active" % (bar,))
224
 
        else:
225
 
            self._stack.pop()
 
150
            raise errors.MissingProgressBarFinish()
 
151
        self._stack.pop()
226
152
 
227
153
 
228
154
class _BaseProgressBar(object):
280
206
 
281
207
    This can be used as the default argument for methods that
282
208
    take an optional progress indicator."""
283
 
 
284
209
    def tick(self):
285
210
        pass
286
211
 
300
225
        return DummyProgress(**kwargs)
301
226
 
302
227
 
 
228
_progress_bar_types['dummy'] = DummyProgress
 
229
_progress_bar_types['none'] = DummyProgress
 
230
 
 
231
 
303
232
class DotsProgressBar(_BaseProgressBar):
304
233
 
305
234
    def __init__(self, **kwargs):
328
257
        self.tick()
329
258
 
330
259
 
 
260
_progress_bar_types['dots'] = DotsProgressBar
331
261
 
332
262
    
333
263
class TTYProgressBar(_BaseProgressBar):
399
329
        self.tick()
400
330
 
401
331
    def update(self, msg, current_cnt=None, total_cnt=None,
402
 
            child_fraction=0):
403
 
        """Update and redraw progress bar.
404
 
        """
 
332
               child_fraction=0):
 
333
        """Update and redraw progress bar."""
405
334
        if msg is None:
406
335
            msg = self.last_msg
407
336
 
427
356
        ##     self.child_fraction == child_fraction):
428
357
        ##     return
429
358
 
430
 
        if msg is None:
431
 
            msg = ''
432
 
 
433
359
        old_msg = self.last_msg
434
360
        # save these for the tick() function
435
361
        self.last_msg = msg
475
401
            # make both fields the same size
476
402
            t = '%i' % (self.last_total)
477
403
            c = '%*i' % (len(t), self.last_cnt)
478
 
            count_str = ' ' + c + '/' + t
 
404
            count_str = ' ' + c + '/' + t 
479
405
 
480
406
        if self.show_bar:
481
407
            # progress bar, if present, soaks up all remaining space
499
425
        else:
500
426
            bar_str = ''
501
427
 
502
 
        m = spin_str + bar_str + self.last_msg + count_str \
503
 
            + pct_str + eta_str
 
428
        m = spin_str + bar_str + self.last_msg + count_str + pct_str + eta_str
504
429
        self.to_file.write('\r%-*.*s' % (self.width - 1, self.width - 1, m))
505
430
        self._have_output = True
506
431
        #self.to_file.flush()
512
437
        #self.to_file.flush()        
513
438
 
514
439
 
 
440
_progress_bar_types['tty'] = TTYProgressBar
515
441
 
516
442
 
517
443
class ChildProgress(_BaseProgressBar):
631
557
        else:
632
558
            self.cur_phase += 1
633
559
        self.pb.update(self.message, self.cur_phase, self.total)
634
 
 
635
 
 
636
 
_progress_bar_types = {}
637
 
_progress_bar_types['dummy'] = DummyProgress
638
 
_progress_bar_types['none'] = DummyProgress
639
 
_progress_bar_types['tty'] = TTYProgressBar
640
 
_progress_bar_types['dots'] = DotsProgressBar