~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to patches/progress.diff

First programmatic generation of completions.

The list of commands is generated, as is the list of possible switches for
each command. Commands requiring arguments aren't treated specially yet.

For every option name there is a list of switches, and if any switch for the
option is given, then the others will be suppressed.  This might be
incorrect in some cases, but closely mimics the old, static function.  The
list of these switch suppressions might be incomplete, as some switches
might have different alternative forms for different commands, in which
cases only the intersection of all alternatives gets suppressed.  A future
version might do this suppression based on the current command, or drop it
completely.

Show diffs side-by-side

added added

removed removed

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