~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-01-15 07:34:16 UTC
  • mfrom: (3882.7.17 progress)
  • Revision ID: pqm@pqm.ubuntu.com-20090115073416-vnzvkab4dfesetj0
(mbp) transport-based progress bars

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Aaron Bentley <aaron.bentley@utoronto.ca>
2
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008 Canonical Ltd
3
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
28
27
bzrlib it really is best to use bzrlib.ui.ui_factory.
29
28
"""
30
29
 
31
 
# TODO: Optionally show elapsed time instead/as well as ETA; nicer
32
 
# when the rate is unpredictable
33
30
 
34
31
import sys
35
32
import time
36
33
import os
37
 
 
38
 
from bzrlib.lazy_import import lazy_import
39
 
lazy_import(globals(), """
 
34
import warnings
 
35
 
 
36
 
40
37
from bzrlib import (
41
38
    errors,
 
39
    osutils,
 
40
    trace,
 
41
    ui,
42
42
    )
43
 
""")
44
 
 
45
43
from bzrlib.trace import mutter
46
44
 
47
45
 
62
60
    return True
63
61
 
64
62
 
65
 
_progress_bar_types = {}
 
63
class ProgressTask(object):
 
64
    """Model component of a progress indicator.
 
65
 
 
66
    Most code that needs to indicate progress should update one of these, 
 
67
    and it will in turn update the display, if one is present.
 
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.
 
72
    """
 
73
 
 
74
    def __init__(self, parent_task=None, ui_factory=None):
 
75
        self._parent_task = parent_task
 
76
        self._last_update = 0
 
77
        self.total_cnt = None
 
78
        self.current_cnt = None
 
79
        self.msg = ''
 
80
        self.ui_factory = ui_factory
 
81
        self.show_pct = False
 
82
        self.show_spinner = True
 
83
        self.show_eta = False,
 
84
        self.show_count = True
 
85
        self.show_bar = True
 
86
 
 
87
    def update(self, msg, current_cnt=None, total_cnt=None):
 
88
        self.msg = msg
 
89
        self.current_cnt = current_cnt
 
90
        if total_cnt:
 
91
            self.total_cnt = total_cnt
 
92
        self.ui_factory.show_progress(self)
 
93
 
 
94
    def tick(self):
 
95
        self.update(self.msg)
 
96
 
 
97
    def finished(self):
 
98
        self.ui_factory.progress_finished(self)
 
99
 
 
100
    def make_sub_task(self):
 
101
        return ProgressTask(self, self.ui_factory)
 
102
 
 
103
    def _overall_completion_fraction(self, child_fraction=0.0):
 
104
        """Return fractional completion of this task and its parents
 
105
        
 
106
        Returns None if no completion can be computed."""
 
107
        if self.total_cnt:
 
108
            own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
 
109
        else:
 
110
            own_fraction = None
 
111
        if self._parent_task is None:
 
112
            return own_fraction
 
113
        else:
 
114
            if own_fraction is None:
 
115
                own_fraction = 0.0
 
116
            return self._parent_task._overall_completion_fraction(own_fraction)
 
117
 
 
118
    def note(self, fmt_string, *args):
 
119
        """Record a note without disrupting the progress bar."""
 
120
        # XXX: shouldn't be here; put it in mutter or the ui instead
 
121
        self.ui_factory.note(fmt_string % args)
 
122
 
 
123
    def clear(self):
 
124
        # XXX: shouldn't be here; put it in mutter or the ui instead
 
125
        self.ui_factory.clear_term()
66
126
 
67
127
 
68
128
def ProgressBar(to_file=None, **kwargs):
87
147
                                                _progress_bar_types.keys())
88
148
        return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
89
149
 
90
 
 
 
150
 
91
151
class ProgressBarStack(object):
92
152
    """A stack of progress bars."""
93
153
 
147
207
    def return_pb(self, bar):
148
208
        """Return bar after its been used."""
149
209
        if bar is not self._stack[-1]:
150
 
            raise errors.MissingProgressBarFinish()
151
 
        self._stack.pop()
 
210
            warnings.warn("%r is not currently active" % (bar,))
 
211
        else:
 
212
            self._stack.pop()
152
213
 
153
214
 
154
215
class _BaseProgressBar(object):
206
267
 
207
268
    This can be used as the default argument for methods that
208
269
    take an optional progress indicator."""
 
270
 
209
271
    def tick(self):
210
272
        pass
211
273
 
225
287
        return DummyProgress(**kwargs)
226
288
 
227
289
 
228
 
_progress_bar_types['dummy'] = DummyProgress
229
 
_progress_bar_types['none'] = DummyProgress
230
 
 
231
 
 
232
290
class DotsProgressBar(_BaseProgressBar):
233
291
 
234
292
    def __init__(self, **kwargs):
257
315
        self.tick()
258
316
 
259
317
 
260
 
_progress_bar_types['dots'] = DotsProgressBar
261
318
 
262
319
    
263
320
class TTYProgressBar(_BaseProgressBar):
329
386
        self.tick()
330
387
 
331
388
    def update(self, msg, current_cnt=None, total_cnt=None,
332
 
               child_fraction=0):
333
 
        """Update and redraw progress bar."""
 
389
            child_fraction=0):
 
390
        """Update and redraw progress bar.
 
391
        """
334
392
        if msg is None:
335
393
            msg = self.last_msg
336
394
 
356
414
        ##     self.child_fraction == child_fraction):
357
415
        ##     return
358
416
 
 
417
        if msg is None:
 
418
            msg = ''
 
419
 
359
420
        old_msg = self.last_msg
360
421
        # save these for the tick() function
361
422
        self.last_msg = msg
401
462
            # make both fields the same size
402
463
            t = '%i' % (self.last_total)
403
464
            c = '%*i' % (len(t), self.last_cnt)
404
 
            count_str = ' ' + c + '/' + t 
 
465
            count_str = ' ' + c + '/' + t
405
466
 
406
467
        if self.show_bar:
407
468
            # progress bar, if present, soaks up all remaining space
425
486
        else:
426
487
            bar_str = ''
427
488
 
428
 
        m = spin_str + bar_str + self.last_msg + count_str + pct_str + eta_str
 
489
        m = spin_str + bar_str + self.last_msg + count_str \
 
490
            + pct_str + eta_str
429
491
        self.to_file.write('\r%-*.*s' % (self.width - 1, self.width - 1, m))
430
492
        self._have_output = True
431
493
        #self.to_file.flush()
437
499
        #self.to_file.flush()        
438
500
 
439
501
 
440
 
_progress_bar_types['tty'] = TTYProgressBar
441
502
 
442
503
 
443
504
class ChildProgress(_BaseProgressBar):
557
618
        else:
558
619
            self.cur_phase += 1
559
620
        self.pb.update(self.message, self.cur_phase, self.total)
 
621
 
 
622
 
 
623
_progress_bar_types = {}
 
624
_progress_bar_types['dummy'] = DummyProgress
 
625
_progress_bar_types['none'] = DummyProgress
 
626
_progress_bar_types['tty'] = TTYProgressBar
 
627
_progress_bar_types['dots'] = DotsProgressBar