##// END OF EJS Templates
progress: make determinate bar more like wget progress bar...
Brodie Rao -
r10453:7edc649f default
parent child Browse files
Show More
@@ -1,180 +1,183 b''
1 1 # progress.py show progress bars for some actions
2 2 #
3 3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
4 4 #
5 5 # This program is free software; you can redistribute it and/or modify it
6 6 # under the terms of the GNU General Public License as published by the
7 7 # Free Software Foundation; either version 2 of the License, or (at your
8 8 # option) any later version.
9 9 #
10 10 # This program is distributed in the hope that it will be useful, but
11 11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 13 # Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License along
16 16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 18
19 19 """show progress bars for some actions
20 20
21 21 This extension uses the progress information logged by hg commands
22 22 to draw progress bars that are as informative as possible. Some progress
23 23 bars only offer indeterminate information, while others have a definite
24 24 end point.
25 25
26 26 The following settings are available::
27 27
28 28 [progress]
29 29 delay = 3 # number of seconds (float) before showing the progress bar
30 30 refresh = 0.1 # time in seconds between refreshes of the progress bar
31 31 format = topic bar number # format of the progress bar
32 32 width = <none> # if set, the maximum width of the progress information
33 33 # (that is, min(width, term width) will be used)
34 34 clear-complete = True # clear the progress bar after it's done
35 35
36 36 Valid entries for the format field are topic, bar, number, unit, and item.
37 37 item defaults to the last 20 characters of the item, but this can be
38 38 changed by adding either -<num> which would take the last num characters,
39 39 or +<num> for the first num characters.
40 40 """
41 41
42 42 import math
43 43 import sys
44 44 import time
45 45
46 46 from mercurial import extensions
47 47 from mercurial import util
48 48
49 49 def spacejoin(*args):
50 50 return ' '.join(s for s in args if s)
51 51
52 52 class progbar(object):
53 53 def __init__(self, ui):
54 54 self.ui = ui
55 55 self.resetstate()
56 56
57 57 def resetstate(self):
58 58 self.topics = []
59 59 self.printed = False
60 60 self.lastprint = time.time() + float(self.ui.config(
61 61 'progress', 'delay', default=3))
62 62 self.indetcount = 0
63 63 self.refresh = float(self.ui.config(
64 64 'progress', 'refresh', default=0.1))
65 65 self.order = self.ui.configlist(
66 66 'progress', 'format',
67 67 default=['topic', 'bar', 'number'])
68 68
69 69 def show(self, topic, pos, item, unit, total):
70 70 termwidth = self.width()
71 71 self.printed = True
72 72 head = ''
73 73 needprogress = False
74 74 tail = ''
75 75 for indicator in self.order:
76 76 add = ''
77 77 if indicator == 'topic':
78 78 add = topic
79 79 elif indicator == 'number':
80 80 if total:
81 81 add = ('% ' + str(len(str(total))) +
82 82 's/%s') % (pos, total)
83 83 else:
84 84 add = str(pos)
85 85 elif indicator.startswith('item') and item:
86 86 slice = 'end'
87 87 if '-' in indicator:
88 88 wid = int(indicator.split('-')[1])
89 89 elif '+' in indicator:
90 90 slice = 'beginning'
91 91 wid = int(indicator.split('+')[1])
92 92 else:
93 93 wid = 20
94 94 if slice == 'end':
95 95 add = item[-wid:]
96 96 else:
97 97 add = item[:wid]
98 98 add += (wid - len(add)) * ' '
99 99 elif indicator == 'bar':
100 100 add = ''
101 101 needprogress = True
102 102 elif indicator == 'unit' and unit:
103 103 add = unit
104 104 if not needprogress:
105 105 head = spacejoin(head, add)
106 106 else:
107 107 tail = spacejoin(add, tail)
108 108 if needprogress:
109 109 used = 0
110 110 if head:
111 111 used += len(head) + 1
112 112 if tail:
113 113 used += len(tail) + 1
114 114 progwidth = termwidth - used - 3
115 115 if total:
116 116 amt = pos * progwidth // total
117 bar = '=' * (amt) + ' ' * (progwidth - amt)
117 bar = '=' * (amt - 1)
118 if amt > 0:
119 bar += '>'
120 bar += ' ' * (progwidth - amt)
118 121 else:
119 122 progwidth -= 3
120 123 self.indetcount += 1
121 124 # mod the count by twice the width so we can make the
122 125 # cursor bounce between the right and left sides
123 126 amt = self.indetcount % (2 * progwidth)
124 127 amt -= progwidth
125 128 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
126 129 ' ' * int(abs(amt)))
127 130 prog = ''.join(('[', bar , ']'))
128 131 out = spacejoin(head, prog, tail)
129 132 else:
130 133 out = spacejoin(head, tail)
131 134 sys.stdout.write('\r' + out[:termwidth])
132 135 sys.stdout.flush()
133 136
134 137 def clear(self):
135 138 sys.stdout.write('\r%s\r' % (' ' * self.width()))
136 139
137 140 def complete(self):
138 141 if self.ui.configbool('progress', 'clear-complete', default=True):
139 142 self.clear()
140 143 else:
141 144 sys.stdout.write('\n')
142 145 sys.stdout.flush()
143 146
144 147 def width(self):
145 148 tw = util.termwidth()
146 149 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
147 150
148 151 def progress(self, orig, topic, pos, item='', unit='', total=None):
149 152 if pos is None:
150 153 if self.topics and self.topics[-1] == topic and self.printed:
151 154 self.complete()
152 155 self.resetstate()
153 156 else:
154 157 if topic not in self.topics:
155 158 self.topics.append(topic)
156 159 now = time.time()
157 160 if now - self.lastprint > 0.1 and topic == self.topics[-1]:
158 161 self.lastprint = now
159 162 self.show(topic, pos, item, unit, total)
160 163 return orig(topic, pos, item=item, unit=unit, total=total)
161 164
162 165 def write(self, orig, *args):
163 166 if self.printed:
164 167 self.clear()
165 168 return orig(*args)
166 169
167 170 sharedprog = None
168 171
169 172 def uisetup(ui):
170 173 if ui.interactive() and not ui.debugflag:
171 174 # we instantiate one globally shared progress bar to avoid
172 175 # competing progress bars when multiple UI objects get created
173 176 global sharedprog
174 177 if not sharedprog:
175 178 sharedprog = progbar(ui)
176 179 extensions.wrapfunction(ui, 'progress', sharedprog.progress)
177 180 extensions.wrapfunction(ui, 'write', sharedprog.write)
178 181
179 182 def reposetup(ui, repo):
180 183 uisetup(repo.ui)
General Comments 0
You need to be logged in to leave comments. Login now