~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/progress.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
43
43
 
44
44
 
45
45
import bzrlib.errors as errors
 
46
from bzrlib.trace import mutter 
46
47
 
47
48
 
48
49
def _supports_progress(f):
71
72
    def __init__(self,
72
73
                 to_file=sys.stderr,
73
74
                 show_pct=False,
74
 
                 show_spinner=False,
75
 
                 show_eta=True,
 
75
                 show_spinner=True,
 
76
                 show_eta=False,
76
77
                 show_bar=True,
77
78
                 show_count=True,
78
79
                 to_messages_file=sys.stdout,
88
89
        self._stack = []
89
90
        self._klass = klass or TTYProgressBar
90
91
 
 
92
    def top(self):
 
93
        if len(self._stack) != 0:
 
94
            return self._stack[-1]
 
95
        else:
 
96
            return None
 
97
 
91
98
    def get_nested(self):
92
99
        """Return a nested progress bar."""
93
 
        # initial implementation - return a new bar each time.
94
 
        new_bar = self._klass(to_file=self._to_file,
95
 
                              show_pct=self._show_pct,
96
 
                              show_spinner=self._show_spinner,
97
 
                              show_eta=self._show_eta,
98
 
                              show_bar=self._show_bar,
99
 
                              show_count=self._show_count,
100
 
                              to_messages_file=self._to_messages_file,
101
 
                              _stack=self)
 
100
        if len(self._stack) == 0:
 
101
            func = self._klass
 
102
        else:
 
103
            func = self.top().child_progress
 
104
        new_bar = func(to_file=self._to_file,
 
105
                       show_pct=self._show_pct,
 
106
                       show_spinner=self._show_spinner,
 
107
                       show_eta=self._show_eta,
 
108
                       show_bar=self._show_bar,
 
109
                       show_count=self._show_count,
 
110
                       to_messages_file=self._to_messages_file,
 
111
                       _stack=self)
102
112
        self._stack.append(new_bar)
103
113
        return new_bar
104
114
 
145
155
        self.to_messages_file.write(fmt_string % args)
146
156
        self.to_messages_file.write('\n')
147
157
 
 
158
    def child_progress(self, **kwargs):
 
159
        return ChildProgress(**kwargs)
 
160
 
148
161
 
149
162
class DummyProgress(_BaseProgressBar):
150
163
    """Progress-bar standin that does nothing.
157
170
    def update(self, msg=None, current=None, total=None):
158
171
        pass
159
172
 
 
173
    def child_update(self, message, current, total):
 
174
        pass
 
175
 
160
176
    def clear(self):
161
177
        pass
162
178
        
163
179
    def note(self, fmt_string, *args, **kwargs):
164
180
        """See _BaseProgressBar.note()."""
165
181
 
 
182
    def child_progress(self, **kwargs):
 
183
        return DummyProgress(**kwargs)
166
184
 
167
185
class DotsProgressBar(_BaseProgressBar):
168
186
 
188
206
        if self.need_nl:
189
207
            self.to_file.write('\n')
190
208
        
 
209
    def child_update(self, message, current, total):
 
210
        self.tick()
191
211
    
192
212
class TTYProgressBar(_BaseProgressBar):
193
213
    """Progress bar display object.
221
241
        self.start_time = None
222
242
        self.last_update = None
223
243
        self.last_updates = deque()
 
244
        self.child_fraction = 0
224
245
    
225
246
 
226
247
    def throttle(self):
240
261
        
241
262
 
242
263
    def tick(self):
243
 
        self.update(self.last_msg, self.last_cnt, self.last_total)
244
 
                 
245
 
 
246
 
 
247
 
    def update(self, msg, current_cnt=None, total_cnt=None):
 
264
        self.update(self.last_msg, self.last_cnt, self.last_total, 
 
265
                    self.child_fraction)
 
266
 
 
267
    def child_update(self, message, current, total):
 
268
        if current is not None:
 
269
            child_fraction = float(current) / total
 
270
            if self.last_cnt is None:
 
271
                pass
 
272
            elif self.last_cnt + child_fraction <= self.last_total:
 
273
                self.child_fraction = child_fraction
 
274
            else:
 
275
                mutter('not updating child fraction')
 
276
        if self.last_msg is None:
 
277
            self.last_msg = ''
 
278
        self.tick()
 
279
 
 
280
 
 
281
    def update(self, msg, current_cnt=None, total_cnt=None, 
 
282
               child_fraction=0):
248
283
        """Update and redraw progress bar."""
 
284
        self.child_fraction = child_fraction
249
285
 
250
286
        if current_cnt < 0:
251
287
            current_cnt = 0
263
299
            return 
264
300
        
265
301
        if self.show_eta and self.start_time and total_cnt:
266
 
            eta = get_eta(self.start_time, current_cnt, total_cnt,
267
 
                    last_updates = self.last_updates)
 
302
            eta = get_eta(self.start_time, current_cnt+child_fraction, 
 
303
                    total_cnt, last_updates = self.last_updates)
268
304
            eta_str = " " + str_tdelta(eta)
269
305
        else:
270
306
            eta_str = ""
278
314
        self.spin_pos += 1
279
315
 
280
316
        if self.show_pct and total_cnt and current_cnt:
281
 
            pct = 100.0 * current_cnt / total_cnt
 
317
            pct = 100.0 * ((current_cnt + child_fraction) / total_cnt)
282
318
            pct_str = ' (%5.1f%%)' % pct
283
319
        else:
284
320
            pct_str = ''
302
338
 
303
339
            if total_cnt:
304
340
                # number of markers highlighted in bar
305
 
                markers = int(round(float(cols) * current_cnt / total_cnt))
 
341
                markers = int(round(float(cols) * 
 
342
                              (current_cnt + child_fraction) / total_cnt))
306
343
                bar_str = '[' + ('=' * markers).ljust(cols) + '] '
307
344
            elif False:
308
345
                # don't know total, so can't show completion.
326
363
        self.to_file.write('\r%s\r' % (' ' * (self.width - 1)))
327
364
        #self.to_file.flush()        
328
365
 
329
 
        
 
366
 
 
367
class ChildProgress(_BaseProgressBar):
 
368
    """A progress indicator that pushes its data to the parent"""
 
369
    def __init__(self, _stack, **kwargs):
 
370
        _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
 
371
        self.parent = _stack.top()
 
372
        self.current = None
 
373
        self.total = None
 
374
        self.child_fraction = 0
 
375
        self.message = None
 
376
 
 
377
    def update(self, msg, current_cnt=None, total_cnt=None):
 
378
        self.current = current_cnt
 
379
        self.total = total_cnt
 
380
        self.message = msg
 
381
        self.child_fraction = 0
 
382
        self.tick()
 
383
 
 
384
    def child_update(self, message, current, total):
 
385
        if current is None:
 
386
            self.child_fraction = 0
 
387
        else:
 
388
            self.child_fraction = float(current) / total
 
389
        self.tick()
 
390
 
 
391
    def tick(self):
 
392
        if self.current is None:
 
393
            count = None
 
394
        else:
 
395
            count = self.current+self.child_fraction
 
396
            if count > self.total:
 
397
                mutter('clamping count of %d to %d' % (count, self.total))
 
398
                count = self.total
 
399
        self.parent.child_update(self.message, count, self.total)
 
400
 
 
401
    def clear(self):
 
402
        pass
 
403
 
 
404
 
330
405
def str_tdelta(delt):
331
406
    if delt is None:
332
407
        return "-:--:--"
372
447
    return total_duration - elapsed
373
448
 
374
449
 
 
450
class ProgressPhase(object):
 
451
    """Update progress object with the current phase"""
 
452
    def __init__(self, message, total, pb):
 
453
        object.__init__(self)
 
454
        self.pb = pb
 
455
        self.message = message
 
456
        self.total = total
 
457
        self.cur_phase = None
 
458
 
 
459
    def next_phase(self):
 
460
        if self.cur_phase is None:
 
461
            self.cur_phase = 0
 
462
        else:
 
463
            self.cur_phase += 1
 
464
        assert self.cur_phase < self.total 
 
465
        self.pb.update(self.message, self.cur_phase, self.total)
 
466
 
 
467
 
375
468
def run_tests():
376
469
    import doctest
377
470
    result = doctest.testmod()