##// END OF EJS Templates
progress: remove useless statement left by bab267e7fc1a
Patrick Mezard -
r14247:c9720ada default
parent child Browse files
Show More
@@ -1,274 +1,273 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, and item. item defaults to the last 20 characters of the
40 estimate, and item. item defaults to the last 20 characters of the
41 item, but this can be changed by adding either ``-<num>`` which would
41 item, but this can be changed by adding either ``-<num>`` which would
42 take the last num characters, or ``+<num>`` for the first num
42 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.i18n import _
49 from mercurial.i18n import _
50
50
51 def spacejoin(*args):
51 def spacejoin(*args):
52 return ' '.join(s for s in args if s)
52 return ' '.join(s for s in args if s)
53
53
54 def shouldprint(ui):
54 def shouldprint(ui):
55 return (getattr(sys.stderr, 'isatty', None) and
55 return (getattr(sys.stderr, 'isatty', None) and
56 (sys.stderr.isatty() or ui.configbool('progress', 'assume-tty')))
56 (sys.stderr.isatty() 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 if not needprogress:
154 if not needprogress:
155 head = spacejoin(head, add)
155 head = spacejoin(head, add)
156 else:
156 else:
157 tail = spacejoin(tail, add)
157 tail = spacejoin(tail, add)
158 if needprogress:
158 if needprogress:
159 used = 0
159 used = 0
160 if head:
160 if head:
161 used += len(head) + 1
161 used += len(head) + 1
162 if tail:
162 if tail:
163 used += len(tail) + 1
163 used += len(tail) + 1
164 progwidth = termwidth - used - 3
164 progwidth = termwidth - used - 3
165 if total and pos <= total:
165 if total and pos <= total:
166 amt = pos * progwidth // total
166 amt = pos * progwidth // total
167 bar = '=' * (amt - 1)
167 bar = '=' * (amt - 1)
168 if amt > 0:
168 if amt > 0:
169 bar += '>'
169 bar += '>'
170 bar += ' ' * (progwidth - amt)
170 bar += ' ' * (progwidth - amt)
171 else:
171 else:
172 progwidth -= 3
172 progwidth -= 3
173 self.indetcount += 1
173 self.indetcount += 1
174 # mod the count by twice the width so we can make the
174 # mod the count by twice the width so we can make the
175 # cursor bounce between the right and left sides
175 # cursor bounce between the right and left sides
176 amt = self.indetcount % (2 * progwidth)
176 amt = self.indetcount % (2 * progwidth)
177 amt -= progwidth
177 amt -= progwidth
178 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
178 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
179 ' ' * int(abs(amt)))
179 ' ' * int(abs(amt)))
180 prog = ''.join(('[', bar , ']'))
180 prog = ''.join(('[', bar , ']'))
181 out = spacejoin(head, prog, tail)
181 out = spacejoin(head, prog, tail)
182 else:
182 else:
183 out = spacejoin(head, tail)
183 out = spacejoin(head, tail)
184 sys.stderr.write('\r' + out[:termwidth])
184 sys.stderr.write('\r' + out[:termwidth])
185 sys.stderr.flush()
185 sys.stderr.flush()
186
186
187 def clear(self):
187 def clear(self):
188 if not shouldprint(self.ui):
188 if not shouldprint(self.ui):
189 return
189 return
190 sys.stderr.write('\r%s\r' % (' ' * self.width()))
190 sys.stderr.write('\r%s\r' % (' ' * self.width()))
191
191
192 def complete(self):
192 def complete(self):
193 if not shouldprint(self.ui):
193 if not shouldprint(self.ui):
194 return
194 return
195 if self.ui.configbool('progress', 'clear-complete', default=True):
195 if self.ui.configbool('progress', 'clear-complete', default=True):
196 self.clear()
196 self.clear()
197 else:
197 else:
198 sys.stderr.write('\n')
198 sys.stderr.write('\n')
199 sys.stderr.flush()
199 sys.stderr.flush()
200
200
201 def width(self):
201 def width(self):
202 tw = self.ui.termwidth()
202 tw = self.ui.termwidth()
203 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
203 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
204
204
205 def estimate(self, topic, pos, total, now):
205 def estimate(self, topic, pos, total, now):
206 if total is None:
206 if total is None:
207 return ''
207 return ''
208 initialpos = self.startvals[topic]
208 initialpos = self.startvals[topic]
209 target = total - initialpos
209 target = total - initialpos
210 delta = pos - initialpos
210 delta = pos - initialpos
211 if delta > 0:
211 if delta > 0:
212 elapsed = now - self.starttimes[topic]
212 elapsed = now - self.starttimes[topic]
213 if elapsed > float(
213 if elapsed > float(
214 self.ui.config('progress', 'estimate', default=2)):
214 self.ui.config('progress', 'estimate', default=2)):
215 seconds = (elapsed * (target - delta)) // delta + 1
215 seconds = (elapsed * (target - delta)) // delta + 1
216 return fmtremaining(seconds)
216 return fmtremaining(seconds)
217 return ''
217 return ''
218
218
219 def progress(self, topic, pos, item='', unit='', total=None):
219 def progress(self, topic, pos, item='', unit='', total=None):
220 now = time.time()
220 now = time.time()
221 if pos is None:
221 if pos is None:
222 self.starttimes.pop(topic, None)
222 self.starttimes.pop(topic, None)
223 self.startvals.pop(topic, None)
223 self.startvals.pop(topic, None)
224 self.topicstates.pop(topic, None)
224 self.topicstates.pop(topic, None)
225 # reset the progress bar if this is the outermost topic
225 # reset the progress bar if this is the outermost topic
226 if self.topics and self.topics[0] == topic and self.printed:
226 if self.topics and self.topics[0] == topic and self.printed:
227 self.complete()
227 self.complete()
228 self.resetstate()
228 self.resetstate()
229 # truncate the list of topics assuming all topics within
229 # truncate the list of topics assuming all topics within
230 # this one are also closed
230 # this one are also closed
231 if topic in self.topics:
231 if topic in self.topics:
232 self.topics = self.topics[:self.topics.index(topic)]
232 self.topics = self.topics[:self.topics.index(topic)]
233 else:
233 else:
234 if topic not in self.topics:
234 if topic not in self.topics:
235 self.starttimes[topic] = now
235 self.starttimes[topic] = now
236 self.startvals[topic] = pos
236 self.startvals[topic] = pos
237 self.topics.append(topic)
237 self.topics.append(topic)
238 self.topicstates[topic] = pos, item, unit, total
238 self.topicstates[topic] = pos, item, unit, total
239 if now - self.lastprint >= self.refresh and self.topics:
239 if now - self.lastprint >= self.refresh and self.topics:
240 self.lastprint = now
240 self.lastprint = now
241 self.topics[-1]
242 self.show(now, topic, *self.topicstates[topic])
241 self.show(now, topic, *self.topicstates[topic])
243
242
244 def uisetup(ui):
243 def uisetup(ui):
245 class progressui(ui.__class__):
244 class progressui(ui.__class__):
246 _progbar = None
245 _progbar = None
247
246
248 def progress(self, *args, **opts):
247 def progress(self, *args, **opts):
249 self._progbar.progress(*args, **opts)
248 self._progbar.progress(*args, **opts)
250 return super(progressui, self).progress(*args, **opts)
249 return super(progressui, self).progress(*args, **opts)
251
250
252 def write(self, *args, **opts):
251 def write(self, *args, **opts):
253 if self._progbar.printed:
252 if self._progbar.printed:
254 self._progbar.clear()
253 self._progbar.clear()
255 return super(progressui, self).write(*args, **opts)
254 return super(progressui, self).write(*args, **opts)
256
255
257 def write_err(self, *args, **opts):
256 def write_err(self, *args, **opts):
258 if self._progbar.printed:
257 if self._progbar.printed:
259 self._progbar.clear()
258 self._progbar.clear()
260 return super(progressui, self).write_err(*args, **opts)
259 return super(progressui, self).write_err(*args, **opts)
261
260
262 # Apps that derive a class from ui.ui() can use
261 # Apps that derive a class from ui.ui() can use
263 # setconfig('progress', 'disable', 'True') to disable this extension
262 # setconfig('progress', 'disable', 'True') to disable this extension
264 if ui.configbool('progress', 'disable'):
263 if ui.configbool('progress', 'disable'):
265 return
264 return
266 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
265 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
267 ui.__class__ = progressui
266 ui.__class__ = progressui
268 # we instantiate one globally shared progress bar to avoid
267 # we instantiate one globally shared progress bar to avoid
269 # competing progress bars when multiple UI objects get created
268 # competing progress bars when multiple UI objects get created
270 if not progressui._progbar:
269 if not progressui._progbar:
271 progressui._progbar = progbar(ui)
270 progressui._progbar = progbar(ui)
272
271
273 def reposetup(ui, repo):
272 def reposetup(ui, repo):
274 uisetup(repo.ui)
273 uisetup(repo.ui)
General Comments 0
You need to be logged in to leave comments. Login now