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