##// END OF EJS Templates
progress: remove superfluous parens
Augie Fackler -
r14836:925cab23 default
parent child Browse files
Show More
@@ -1,284 +1,284 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 estimate # format of the progress bar
31 format = topic bar number estimate # 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 disable = False # if true, don't show a progress bar
35 disable = False # if true, don't show a progress bar
36 assume-tty = False # if true, ALWAYS show a progress bar, unless
36 assume-tty = False # if true, ALWAYS show a progress bar, unless
37 # disable is given
37 # disable is given
38
38
39 Valid entries for the format field are topic, bar, number, unit,
39 Valid entries for the format field are topic, bar, number, unit,
40 estimate, speed, and item. item defaults to the last 20 characters of
40 estimate, speed, and item. item defaults to the last 20 characters of
41 the item, but this can be changed by adding either ``-<num>`` which
41 the item, but this can be changed by adding either ``-<num>`` which
42 would take the last num characters, or ``+<num>`` for the first num
42 would take the last num characters, or ``+<num>`` for the first num
43 characters.
43 characters.
44 """
44 """
45
45
46 import sys
46 import sys
47 import time
47 import time
48
48
49 from mercurial import util
49 from mercurial import util
50 from mercurial.i18n import _
50 from mercurial.i18n import _
51
51
52 def spacejoin(*args):
52 def spacejoin(*args):
53 return ' '.join(s for s in args if s)
53 return ' '.join(s for s in args if s)
54
54
55 def shouldprint(ui):
55 def shouldprint(ui):
56 return (util.isatty(sys.stderr) or ui.configbool('progress', 'assume-tty'))
56 return util.isatty(sys.stderr) or ui.configbool('progress', 'assume-tty')
57
57
58 def fmtremaining(seconds):
58 def fmtremaining(seconds):
59 if seconds < 60:
59 if seconds < 60:
60 # i18n: format XX seconds as "XXs"
60 # i18n: format XX seconds as "XXs"
61 return _("%02ds") % (seconds)
61 return _("%02ds") % (seconds)
62 minutes = seconds // 60
62 minutes = seconds // 60
63 if minutes < 60:
63 if minutes < 60:
64 seconds -= minutes * 60
64 seconds -= minutes * 60
65 # i18n: format X minutes and YY seconds as "XmYYs"
65 # i18n: format X minutes and YY seconds as "XmYYs"
66 return _("%dm%02ds") % (minutes, seconds)
66 return _("%dm%02ds") % (minutes, seconds)
67 # we're going to ignore seconds in this case
67 # we're going to ignore seconds in this case
68 minutes += 1
68 minutes += 1
69 hours = minutes // 60
69 hours = minutes // 60
70 minutes -= hours * 60
70 minutes -= hours * 60
71 if hours < 30:
71 if hours < 30:
72 # i18n: format X hours and YY minutes as "XhYYm"
72 # i18n: format X hours and YY minutes as "XhYYm"
73 return _("%dh%02dm") % (hours, minutes)
73 return _("%dh%02dm") % (hours, minutes)
74 # we're going to ignore minutes in this case
74 # we're going to ignore minutes in this case
75 hours += 1
75 hours += 1
76 days = hours // 24
76 days = hours // 24
77 hours -= days * 24
77 hours -= days * 24
78 if days < 15:
78 if days < 15:
79 # i18n: format X days and YY hours as "XdYYh"
79 # i18n: format X days and YY hours as "XdYYh"
80 return _("%dd%02dh") % (days, hours)
80 return _("%dd%02dh") % (days, hours)
81 # we're going to ignore hours in this case
81 # we're going to ignore hours in this case
82 days += 1
82 days += 1
83 weeks = days // 7
83 weeks = days // 7
84 days -= weeks * 7
84 days -= weeks * 7
85 if weeks < 55:
85 if weeks < 55:
86 # i18n: format X weeks and YY days as "XwYYd"
86 # i18n: format X weeks and YY days as "XwYYd"
87 return _("%dw%02dd") % (weeks, days)
87 return _("%dw%02dd") % (weeks, days)
88 # we're going to ignore days and treat a year as 52 weeks
88 # we're going to ignore days and treat a year as 52 weeks
89 weeks += 1
89 weeks += 1
90 years = weeks // 52
90 years = weeks // 52
91 weeks -= years * 52
91 weeks -= years * 52
92 # i18n: format X years and YY weeks as "XyYYw"
92 # i18n: format X years and YY weeks as "XyYYw"
93 return _("%dy%02dw") % (years, weeks)
93 return _("%dy%02dw") % (years, weeks)
94
94
95 class progbar(object):
95 class progbar(object):
96 def __init__(self, ui):
96 def __init__(self, ui):
97 self.ui = ui
97 self.ui = ui
98 self.resetstate()
98 self.resetstate()
99
99
100 def resetstate(self):
100 def resetstate(self):
101 self.topics = []
101 self.topics = []
102 self.topicstates = {}
102 self.topicstates = {}
103 self.starttimes = {}
103 self.starttimes = {}
104 self.startvals = {}
104 self.startvals = {}
105 self.printed = False
105 self.printed = False
106 self.lastprint = time.time() + float(self.ui.config(
106 self.lastprint = time.time() + float(self.ui.config(
107 'progress', 'delay', default=3))
107 'progress', 'delay', default=3))
108 self.indetcount = 0
108 self.indetcount = 0
109 self.refresh = float(self.ui.config(
109 self.refresh = float(self.ui.config(
110 'progress', 'refresh', default=0.1))
110 'progress', 'refresh', default=0.1))
111 self.order = self.ui.configlist(
111 self.order = self.ui.configlist(
112 'progress', 'format',
112 'progress', 'format',
113 default=['topic', 'bar', 'number', 'estimate'])
113 default=['topic', 'bar', 'number', 'estimate'])
114
114
115 def show(self, now, topic, pos, item, unit, total):
115 def show(self, now, topic, pos, item, unit, total):
116 if not shouldprint(self.ui):
116 if not shouldprint(self.ui):
117 return
117 return
118 termwidth = self.width()
118 termwidth = self.width()
119 self.printed = True
119 self.printed = True
120 head = ''
120 head = ''
121 needprogress = False
121 needprogress = False
122 tail = ''
122 tail = ''
123 for indicator in self.order:
123 for indicator in self.order:
124 add = ''
124 add = ''
125 if indicator == 'topic':
125 if indicator == 'topic':
126 add = topic
126 add = topic
127 elif indicator == 'number':
127 elif indicator == 'number':
128 if total:
128 if total:
129 add = ('% ' + str(len(str(total))) +
129 add = ('% ' + str(len(str(total))) +
130 's/%s') % (pos, total)
130 's/%s') % (pos, total)
131 else:
131 else:
132 add = str(pos)
132 add = str(pos)
133 elif indicator.startswith('item') and item:
133 elif indicator.startswith('item') and item:
134 slice = 'end'
134 slice = 'end'
135 if '-' in indicator:
135 if '-' in indicator:
136 wid = int(indicator.split('-')[1])
136 wid = int(indicator.split('-')[1])
137 elif '+' in indicator:
137 elif '+' in indicator:
138 slice = 'beginning'
138 slice = 'beginning'
139 wid = int(indicator.split('+')[1])
139 wid = int(indicator.split('+')[1])
140 else:
140 else:
141 wid = 20
141 wid = 20
142 if slice == 'end':
142 if slice == 'end':
143 add = item[-wid:]
143 add = item[-wid:]
144 else:
144 else:
145 add = item[:wid]
145 add = item[:wid]
146 add += (wid - len(add)) * ' '
146 add += (wid - len(add)) * ' '
147 elif indicator == 'bar':
147 elif indicator == 'bar':
148 add = ''
148 add = ''
149 needprogress = True
149 needprogress = True
150 elif indicator == 'unit' and unit:
150 elif indicator == 'unit' and unit:
151 add = unit
151 add = unit
152 elif indicator == 'estimate':
152 elif indicator == 'estimate':
153 add = self.estimate(topic, pos, total, now)
153 add = self.estimate(topic, pos, total, now)
154 elif indicator == 'speed':
154 elif indicator == 'speed':
155 add = self.speed(topic, pos, unit, now)
155 add = self.speed(topic, pos, unit, now)
156 if not needprogress:
156 if not needprogress:
157 head = spacejoin(head, add)
157 head = spacejoin(head, add)
158 else:
158 else:
159 tail = spacejoin(tail, add)
159 tail = spacejoin(tail, add)
160 if needprogress:
160 if needprogress:
161 used = 0
161 used = 0
162 if head:
162 if head:
163 used += len(head) + 1
163 used += len(head) + 1
164 if tail:
164 if tail:
165 used += len(tail) + 1
165 used += len(tail) + 1
166 progwidth = termwidth - used - 3
166 progwidth = termwidth - used - 3
167 if total and pos <= total:
167 if total and pos <= total:
168 amt = pos * progwidth // total
168 amt = pos * progwidth // total
169 bar = '=' * (amt - 1)
169 bar = '=' * (amt - 1)
170 if amt > 0:
170 if amt > 0:
171 bar += '>'
171 bar += '>'
172 bar += ' ' * (progwidth - amt)
172 bar += ' ' * (progwidth - amt)
173 else:
173 else:
174 progwidth -= 3
174 progwidth -= 3
175 self.indetcount += 1
175 self.indetcount += 1
176 # mod the count by twice the width so we can make the
176 # mod the count by twice the width so we can make the
177 # cursor bounce between the right and left sides
177 # cursor bounce between the right and left sides
178 amt = self.indetcount % (2 * progwidth)
178 amt = self.indetcount % (2 * progwidth)
179 amt -= progwidth
179 amt -= progwidth
180 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
180 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
181 ' ' * int(abs(amt)))
181 ' ' * int(abs(amt)))
182 prog = ''.join(('[', bar , ']'))
182 prog = ''.join(('[', bar , ']'))
183 out = spacejoin(head, prog, tail)
183 out = spacejoin(head, prog, tail)
184 else:
184 else:
185 out = spacejoin(head, tail)
185 out = spacejoin(head, tail)
186 sys.stderr.write('\r' + out[:termwidth])
186 sys.stderr.write('\r' + out[:termwidth])
187 sys.stderr.flush()
187 sys.stderr.flush()
188
188
189 def clear(self):
189 def clear(self):
190 if not shouldprint(self.ui):
190 if not shouldprint(self.ui):
191 return
191 return
192 sys.stderr.write('\r%s\r' % (' ' * self.width()))
192 sys.stderr.write('\r%s\r' % (' ' * self.width()))
193
193
194 def complete(self):
194 def complete(self):
195 if not shouldprint(self.ui):
195 if not shouldprint(self.ui):
196 return
196 return
197 if self.ui.configbool('progress', 'clear-complete', default=True):
197 if self.ui.configbool('progress', 'clear-complete', default=True):
198 self.clear()
198 self.clear()
199 else:
199 else:
200 sys.stderr.write('\n')
200 sys.stderr.write('\n')
201 sys.stderr.flush()
201 sys.stderr.flush()
202
202
203 def width(self):
203 def width(self):
204 tw = self.ui.termwidth()
204 tw = self.ui.termwidth()
205 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
205 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
206
206
207 def estimate(self, topic, pos, total, now):
207 def estimate(self, topic, pos, total, now):
208 if total is None:
208 if total is None:
209 return ''
209 return ''
210 initialpos = self.startvals[topic]
210 initialpos = self.startvals[topic]
211 target = total - initialpos
211 target = total - initialpos
212 delta = pos - initialpos
212 delta = pos - initialpos
213 if delta > 0:
213 if delta > 0:
214 elapsed = now - self.starttimes[topic]
214 elapsed = now - self.starttimes[topic]
215 if elapsed > float(
215 if elapsed > float(
216 self.ui.config('progress', 'estimate', default=2)):
216 self.ui.config('progress', 'estimate', default=2)):
217 seconds = (elapsed * (target - delta)) // delta + 1
217 seconds = (elapsed * (target - delta)) // delta + 1
218 return fmtremaining(seconds)
218 return fmtremaining(seconds)
219 return ''
219 return ''
220
220
221 def speed(self, topic, pos, unit, now):
221 def speed(self, topic, pos, unit, now):
222 initialpos = self.startvals[topic]
222 initialpos = self.startvals[topic]
223 delta = pos - initialpos
223 delta = pos - initialpos
224 elapsed = now - self.starttimes[topic]
224 elapsed = now - self.starttimes[topic]
225 if elapsed > float(
225 if elapsed > float(
226 self.ui.config('progress', 'estimate', default=2)):
226 self.ui.config('progress', 'estimate', default=2)):
227 return _('%d %s/sec') % (delta / elapsed, unit)
227 return _('%d %s/sec') % (delta / elapsed, unit)
228 return ''
228 return ''
229
229
230 def progress(self, topic, pos, item='', unit='', total=None):
230 def progress(self, topic, pos, item='', unit='', total=None):
231 now = time.time()
231 now = time.time()
232 if pos is None:
232 if pos is None:
233 self.starttimes.pop(topic, None)
233 self.starttimes.pop(topic, None)
234 self.startvals.pop(topic, None)
234 self.startvals.pop(topic, None)
235 self.topicstates.pop(topic, None)
235 self.topicstates.pop(topic, None)
236 # reset the progress bar if this is the outermost topic
236 # reset the progress bar if this is the outermost topic
237 if self.topics and self.topics[0] == topic and self.printed:
237 if self.topics and self.topics[0] == topic and self.printed:
238 self.complete()
238 self.complete()
239 self.resetstate()
239 self.resetstate()
240 # truncate the list of topics assuming all topics within
240 # truncate the list of topics assuming all topics within
241 # this one are also closed
241 # this one are also closed
242 if topic in self.topics:
242 if topic in self.topics:
243 self.topics = self.topics[:self.topics.index(topic)]
243 self.topics = self.topics[:self.topics.index(topic)]
244 else:
244 else:
245 if topic not in self.topics:
245 if topic not in self.topics:
246 self.starttimes[topic] = now
246 self.starttimes[topic] = now
247 self.startvals[topic] = pos
247 self.startvals[topic] = pos
248 self.topics.append(topic)
248 self.topics.append(topic)
249 self.topicstates[topic] = pos, item, unit, total
249 self.topicstates[topic] = pos, item, unit, total
250 if now - self.lastprint >= self.refresh and self.topics:
250 if now - self.lastprint >= self.refresh and self.topics:
251 self.lastprint = now
251 self.lastprint = now
252 self.show(now, topic, *self.topicstates[topic])
252 self.show(now, topic, *self.topicstates[topic])
253
253
254 def uisetup(ui):
254 def uisetup(ui):
255 class progressui(ui.__class__):
255 class progressui(ui.__class__):
256 _progbar = None
256 _progbar = None
257
257
258 def progress(self, *args, **opts):
258 def progress(self, *args, **opts):
259 self._progbar.progress(*args, **opts)
259 self._progbar.progress(*args, **opts)
260 return super(progressui, self).progress(*args, **opts)
260 return super(progressui, self).progress(*args, **opts)
261
261
262 def write(self, *args, **opts):
262 def write(self, *args, **opts):
263 if self._progbar.printed:
263 if self._progbar.printed:
264 self._progbar.clear()
264 self._progbar.clear()
265 return super(progressui, self).write(*args, **opts)
265 return super(progressui, self).write(*args, **opts)
266
266
267 def write_err(self, *args, **opts):
267 def write_err(self, *args, **opts):
268 if self._progbar.printed:
268 if self._progbar.printed:
269 self._progbar.clear()
269 self._progbar.clear()
270 return super(progressui, self).write_err(*args, **opts)
270 return super(progressui, self).write_err(*args, **opts)
271
271
272 # Apps that derive a class from ui.ui() can use
272 # Apps that derive a class from ui.ui() can use
273 # setconfig('progress', 'disable', 'True') to disable this extension
273 # setconfig('progress', 'disable', 'True') to disable this extension
274 if ui.configbool('progress', 'disable'):
274 if ui.configbool('progress', 'disable'):
275 return
275 return
276 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
276 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
277 ui.__class__ = progressui
277 ui.__class__ = progressui
278 # we instantiate one globally shared progress bar to avoid
278 # we instantiate one globally shared progress bar to avoid
279 # competing progress bars when multiple UI objects get created
279 # competing progress bars when multiple UI objects get created
280 if not progressui._progbar:
280 if not progressui._progbar:
281 progressui._progbar = progbar(ui)
281 progressui._progbar = progbar(ui)
282
282
283 def reposetup(ui, repo):
283 def reposetup(ui, repo):
284 uisetup(repo.ui)
284 uisetup(repo.ui)
General Comments 0
You need to be logged in to leave comments. Login now