~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
import sys
40
40
import time
41
41
import os
42
 
from collections import deque
43
 
 
44
42
 
45
43
import bzrlib.errors as errors
46
 
from bzrlib.trace import mutter 
 
44
from bzrlib.trace import mutter
47
45
 
48
46
 
49
47
def _supports_progress(f):
50
 
    if not hasattr(f, 'isatty'):
 
48
    isatty = getattr(f, 'isatty', None)
 
49
    if isatty is None:
51
50
        return False
52
 
    if not f.isatty():
 
51
    if not isatty():
53
52
        return False
54
53
    if os.environ.get('TERM') == 'dumb':
55
54
        # e.g. emacs compile window
57
56
    return True
58
57
 
59
58
 
 
59
_progress_bar_types = {}
 
60
 
60
61
 
61
62
def ProgressBar(to_file=None, **kwargs):
62
63
    """Abstract factory"""
63
64
    if to_file is None:
64
65
        to_file = sys.stderr
65
 
    if _supports_progress(to_file):
66
 
        return TTYProgressBar(to_file=to_file, **kwargs)
 
66
    requested_bar_type = os.environ.get('BZR_PROGRESS_BAR')
 
67
    # An value of '' or not set reverts to standard processing
 
68
    if requested_bar_type in (None, ''):
 
69
        if _supports_progress(to_file):
 
70
            return TTYProgressBar(to_file=to_file, **kwargs)
 
71
        else:
 
72
            return DotsProgressBar(to_file=to_file, **kwargs)
67
73
    else:
68
 
        return DotsProgressBar(to_file=to_file, **kwargs)
69
 
    
 
74
        # Minor sanitation to prevent spurious errors
 
75
        requested_bar_type = requested_bar_type.lower().strip()
 
76
        # TODO: jam 20060710 Arguably we shouldn't raise an exception
 
77
        #       but should instead just disable progress bars if we
 
78
        #       don't recognize the type
 
79
        if requested_bar_type not in _progress_bar_types:
 
80
            raise errors.InvalidProgressBarType(requested_bar_type,
 
81
                                                _progress_bar_types.keys())
 
82
        return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
 
83
 
70
84
 
71
85
class ProgressBarStack(object):
72
86
    """A stack of progress bars."""
93
107
        self._show_count = show_count
94
108
        self._to_messages_file = to_messages_file
95
109
        self._stack = []
96
 
        self._klass = klass or TTYProgressBar
 
110
        self._klass = klass or ProgressBar
97
111
 
98
112
    def top(self):
99
113
        if len(self._stack) != 0:
206
220
        return DummyProgress(**kwargs)
207
221
 
208
222
 
 
223
_progress_bar_types['dummy'] = DummyProgress
 
224
_progress_bar_types['none'] = DummyProgress
 
225
 
 
226
 
209
227
class DotsProgressBar(_BaseProgressBar):
210
228
 
211
229
    def __init__(self, **kwargs):
233
251
    def child_update(self, message, current, total):
234
252
        self.tick()
235
253
 
 
254
 
 
255
_progress_bar_types['dots'] = DotsProgressBar
 
256
 
236
257
    
237
258
class TTYProgressBar(_BaseProgressBar):
238
259
    """Progress bar display object.
262
283
        _BaseProgressBar.__init__(self, **kwargs)
263
284
        self.spin_pos = 0
264
285
        self.width = terminal_width()
265
 
        self.last_updates = deque()
 
286
        self.last_updates = []
 
287
        self._max_last_updates = 10
266
288
        self.child_fraction = 0
 
289
        self._have_output = False
267
290
    
268
291
 
269
292
    def throttle(self, old_msg):
284
307
            return True
285
308
 
286
309
        self.last_updates.append(now - self.last_update)
 
310
        # Don't let the queue grow without bound
 
311
        self.last_updates = self.last_updates[-self._max_last_updates:]
287
312
        self.last_update = now
288
313
        return False
289
314
        
405
430
 
406
431
        assert len(m) < self.width
407
432
        self.to_file.write('\r' + m.ljust(self.width - 1))
 
433
        self._have_output = True
408
434
        #self.to_file.flush()
409
435
            
410
436
    def clear(self):        
411
 
        self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
 
437
        if self._have_output:
 
438
            self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
 
439
        self._have_output = False
412
440
        #self.to_file.flush()        
413
441
 
414
442
 
 
443
_progress_bar_types['tty'] = TTYProgressBar
 
444
 
 
445
 
415
446
class ChildProgress(_BaseProgressBar):
416
447
    """A progress indicator that pushes its data to the parent"""
417
448
 
487
518
    assert total_duration >= elapsed
488
519
 
489
520
    if last_updates and len(last_updates) >= n_recent:
490
 
        while len(last_updates) > n_recent:
491
 
            last_updates.popleft()
492
521
        avg = sum(last_updates) / float(len(last_updates))
493
522
        time_left = avg * (total - current)
494
523