/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
648 by Martin Pool
- import aaron's progress-indicator code
1
# Copyright (C) 2005 Aaron Bentley
2
# <aaron.bentley@utoronto.ca>
3
#
4
#    This program is free software; you can redistribute it and/or modify
5
#    it under the terms of the GNU General Public License as published by
6
#    the Free Software Foundation; either version 2 of the License, or
7
#    (at your option) any later version.
8
#
9
#    This program is distributed in the hope that it will be useful,
10
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
#    GNU General Public License for more details.
13
#
14
#    You should have received a copy of the GNU General Public License
15
#    along with this program; if not, write to the Free Software
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
import sys
19
import datetime
20
21
class Progress(object):
22
    def __init__(self, units, current, total=None):
23
        self.units = units
24
        self.current = current
25
        self.total = total
26
27
    def _get_percent(self):
28
        if self.total is not None and self.current is not None:
29
            return 100.0 * self.current / self.total
30
31
    percent = property(_get_percent)
32
33
    def __str__(self):
34
        if self.total is not None:
35
            return "%i of %i %s %.1f%%" % (self.current, self.total, self.units,
36
                                         self.percent)
37
        else:
38
            return "%i %s" (self.current, self.units) 
39
40
class ProgressBar(object):
41
    def __init__(self):
42
        self.start = None
43
        object.__init__(self)
44
45
    def __call__(self, progress):
46
        if self.start is None:
47
            self.start = datetime.datetime.now()
48
        progress_bar(progress, start_time=self.start)
49
        
50
def divide_timedelta(delt, divisor):
51
    """Divides a timedelta object"""
52
    return datetime.timedelta(float(delt.days)/divisor, 
53
                              float(delt.seconds)/divisor, 
54
                              float(delt.microseconds)/divisor)
55
56
def str_tdelta(delt):
57
    if delt is None:
58
        return "-:--:--"
59
    return str(datetime.timedelta(delt.days, delt.seconds))
60
61
def get_eta(start_time, progress, enough_samples=20):
62
    if start_time is None or progress.current == 0:
63
        return None
64
    elif progress.current < enough_samples:
65
        return None
66
    elapsed = datetime.datetime.now() - start_time
67
    total_duration = divide_timedelta((elapsed) * long(progress.total), 
68
                                      progress.current)
69
    if elapsed < total_duration:
70
        eta = total_duration - elapsed
71
    else:
72
        eta = total_duration - total_duration
73
    return eta
74
75
def progress_bar(progress, start_time=None):
76
    eta = get_eta(start_time, progress)
77
    if start_time is not None:
78
        eta_str = " "+str_tdelta(eta)
79
    else:
80
        eta_str = ""
81
82
    fmt = " %i of %i %s (%.1f%%)"
83
    f = fmt % (progress.total, progress.total, progress.units, 100.0)
84
    max = len(f)
85
    cols = 77 - max
86
    if start_time is not None:
87
        cols -= len(eta_str)
88
    markers = int (float(cols) * progress.current / progress.total)
89
    txt = fmt % (progress.current, progress.total, progress.units,
90
                 progress.percent)
91
    sys.stderr.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
92
                                       eta_str))
93
94
def clear_progress_bar():
95
    sys.stderr.write('\r%s\r' % (' '*79))
96
97
def spinner_str(progress, show_text=False):
98
    """
99
    Produces the string for a textual "spinner" progress indicator
100
    :param progress: an object represinting current progress
101
    :param show_text: If true, show progress text as well
102
    :return: The spinner string
103
104
    >>> spinner_str(Progress("baloons", 0))
105
    '|'
106
    >>> spinner_str(Progress("baloons", 5))
107
    '/'
108
    >>> spinner_str(Progress("baloons", 6), show_text=True)
109
    '- 6 baloons'
110
    """
111
    positions = ('|', '/', '-', '\\')
112
    text = positions[progress.current % 4]
113
    if show_text:
114
        text+=" %i %s" % (progress.current, progress.units)
115
    return text
116
117
def spinner(progress, show_text=False, output=sys.stderr):
118
    """
119
    Update a spinner progress indicator on an output
120
    :param progress: The progress to display
121
    :param show_text: If true, show text as well as spinner
122
    :param output: The output to write to
123
124
    >>> spinner(Progress("baloons", 6), show_text=True, output=sys.stdout)
125
    \r- 6 baloons
126
    """
127
    output.write('\r%s' % spinner_str(progress, show_text))
128
129
def run_tests():
130
    import doctest
131
    result = doctest.testmod()
132
    if result[1] > 0:
133
        if result[0] == 0:
134
            print "All tests passed"
135
    else:
136
        print "No tests to run"
137
if __name__ == "__main__":
138
    run_tests()