/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

Add WSGI smart server.

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
 
60
 
 
61
 
def ProgressBar(to_file=sys.stderr, **kwargs):
 
59
_progress_bar_types = {}
 
60
 
 
61
 
 
62
def ProgressBar(to_file=None, **kwargs):
62
63
    """Abstract factory"""
63
 
    if _supports_progress(to_file):
64
 
        return TTYProgressBar(to_file=to_file, **kwargs)
 
64
    if to_file is None:
 
65
        to_file = sys.stderr
 
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)
65
73
    else:
66
 
        return DotsProgressBar(to_file=to_file, **kwargs)
67
 
    
 
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
 
68
84
 
69
85
class ProgressBarStack(object):
70
86
    """A stack of progress bars."""
71
87
 
72
88
    def __init__(self,
73
 
                 to_file=sys.stderr,
 
89
                 to_file=None,
74
90
                 show_pct=False,
75
91
                 show_spinner=True,
76
92
                 show_eta=False,
77
93
                 show_bar=True,
78
94
                 show_count=True,
79
 
                 to_messages_file=sys.stdout,
 
95
                 to_messages_file=None,
80
96
                 klass=None):
81
97
        """Setup the stack with the parameters the progress bars should have."""
 
98
        if to_file is None:
 
99
            to_file = sys.stderr
 
100
        if to_messages_file is None:
 
101
            to_messages_file = sys.stdout
82
102
        self._to_file = to_file
83
103
        self._show_pct = show_pct
84
104
        self._show_spinner = show_spinner
87
107
        self._show_count = show_count
88
108
        self._to_messages_file = to_messages_file
89
109
        self._stack = []
90
 
        self._klass = klass or TTYProgressBar
 
110
        self._klass = klass or ProgressBar
91
111
 
92
112
    def top(self):
93
113
        if len(self._stack) != 0:
128
148
class _BaseProgressBar(object):
129
149
 
130
150
    def __init__(self,
131
 
                 to_file=sys.stderr,
 
151
                 to_file=None,
132
152
                 show_pct=False,
133
153
                 show_spinner=False,
134
 
                 show_eta=True,
 
154
                 show_eta=False,
135
155
                 show_bar=True,
136
156
                 show_count=True,
137
 
                 to_messages_file=sys.stdout,
 
157
                 to_messages_file=None,
138
158
                 _stack=None):
139
159
        object.__init__(self)
 
160
        if to_file is None:
 
161
            to_file = sys.stderr
 
162
        if to_messages_file is None:
 
163
            to_messages_file = sys.stdout
140
164
        self.to_file = to_file
141
165
        self.to_messages_file = to_messages_file
142
166
        self.last_msg = None
195
219
    def child_progress(self, **kwargs):
196
220
        return DummyProgress(**kwargs)
197
221
 
 
222
 
 
223
_progress_bar_types['dummy'] = DummyProgress
 
224
_progress_bar_types['none'] = DummyProgress
 
225
 
 
226
 
198
227
class DotsProgressBar(_BaseProgressBar):
199
228
 
200
229
    def __init__(self, **kwargs):
209
238
        if msg and msg != self.last_msg:
210
239
            if self.need_nl:
211
240
                self.to_file.write('\n')
212
 
            
213
241
            self.to_file.write(msg + ': ')
214
242
            self.last_msg = msg
215
243
        self.need_nl = True
218
246
    def clear(self):
219
247
        if self.need_nl:
220
248
            self.to_file.write('\n')
 
249
        self.need_nl = False
221
250
        
222
251
    def child_update(self, message, current, total):
223
252
        self.tick()
 
253
 
 
254
 
 
255
_progress_bar_types['dots'] = DotsProgressBar
 
256
 
224
257
    
225
258
class TTYProgressBar(_BaseProgressBar):
226
259
    """Progress bar display object.
250
283
        _BaseProgressBar.__init__(self, **kwargs)
251
284
        self.spin_pos = 0
252
285
        self.width = terminal_width()
253
 
        self.start_time = None
254
 
        self.last_updates = deque()
 
286
        self.last_updates = []
 
287
        self._max_last_updates = 10
255
288
        self.child_fraction = 0
 
289
        self._have_output = False
256
290
    
257
291
 
258
 
    def throttle(self):
 
292
    def throttle(self, old_msg):
259
293
        """Return True if the bar was updated too recently"""
260
294
        # time.time consistently takes 40/4000 ms = 0.01 ms.
261
295
        # but every single update to the pb invokes it.
262
296
        # so we use time.clock which takes 20/4000 ms = 0.005ms
263
297
        # on the downside, time.clock() appears to have approximately
264
298
        # 10ms granularity, so we treat a zero-time change as 'throttled.'
265
 
        
266
299
        now = time.clock()
 
300
        if self.start_time is not None and (now - self.start_time) < 1:
 
301
            return True
 
302
        if old_msg != self.last_msg:
 
303
            return False
267
304
        interval = now - self.last_update
268
305
        # if interval > 0
269
306
        if interval < self.MIN_PAUSE:
270
307
            return True
271
308
 
272
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:]
273
312
        self.last_update = now
274
313
        return False
275
314
        
276
 
 
277
315
    def tick(self):
278
316
        self.update(self.last_msg, self.last_cnt, self.last_total, 
279
317
                    self.child_fraction)
291
329
            self.last_msg = ''
292
330
        self.tick()
293
331
 
294
 
 
295
332
    def update(self, msg, current_cnt=None, total_cnt=None, 
296
333
               child_fraction=0):
297
334
        """Update and redraw progress bar."""
 
335
        if msg is None:
 
336
            msg = self.last_msg
 
337
 
 
338
        if total_cnt is None:
 
339
            total_cnt = self.last_total
298
340
 
299
341
        if current_cnt < 0:
300
342
            current_cnt = 0
326
368
        # but multiple that by 4000 calls -> starts to cost.
327
369
        # so anything to make this function call faster
328
370
        # will improve base 'diff' time by up to 0.1 seconds.
329
 
        if old_msg == self.last_msg and self.throttle():
 
371
        if self.throttle(old_msg):
330
372
            return
331
373
 
332
374
        if self.show_eta and self.start_time and self.last_total:
388
430
 
389
431
        assert len(m) < self.width
390
432
        self.to_file.write('\r' + m.ljust(self.width - 1))
 
433
        self._have_output = True
391
434
        #self.to_file.flush()
392
435
            
393
436
    def clear(self):        
394
 
        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
395
440
        #self.to_file.flush()        
396
441
 
397
442
 
 
443
_progress_bar_types['tty'] = TTYProgressBar
 
444
 
 
445
 
398
446
class ChildProgress(_BaseProgressBar):
399
447
    """A progress indicator that pushes its data to the parent"""
 
448
 
400
449
    def __init__(self, _stack, **kwargs):
401
450
        _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
402
451
        self.parent = _stack.top()
469
518
    assert total_duration >= elapsed
470
519
 
471
520
    if last_updates and len(last_updates) >= n_recent:
472
 
        while len(last_updates) > n_recent:
473
 
            last_updates.popleft()
474
521
        avg = sum(last_updates) / float(len(last_updates))
475
522
        time_left = avg * (total - current)
476
523