##// END OF EJS Templates
progress: use 'encoding.colwidth' to get column width of items correctly...
FUJIWARA Katsunori -
r21863:f9c91c63 default
parent child Browse files
Show More
@@ -1,305 +1,305
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 software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """show progress bars for some actions
8 """show progress bars for some actions
9
9
10 This extension uses the progress information logged by hg commands
10 This extension uses the progress information logged by hg commands
11 to draw progress bars that are as informative as possible. Some progress
11 to draw progress bars that are as informative as possible. Some progress
12 bars only offer indeterminate information, while others have a definite
12 bars only offer indeterminate information, while others have a definite
13 end point.
13 end point.
14
14
15 The following settings are available::
15 The following settings are available::
16
16
17 [progress]
17 [progress]
18 delay = 3 # number of seconds (float) before showing the progress bar
18 delay = 3 # number of seconds (float) before showing the progress bar
19 changedelay = 1 # changedelay: minimum delay before showing a new topic.
19 changedelay = 1 # changedelay: minimum delay before showing a new topic.
20 # If set to less than 3 * refresh, that value will
20 # If set to less than 3 * refresh, that value will
21 # be used instead.
21 # be used instead.
22 refresh = 0.1 # time in seconds between refreshes of the progress bar
22 refresh = 0.1 # time in seconds between refreshes of the progress bar
23 format = topic bar number estimate # format of the progress bar
23 format = topic bar number estimate # format of the progress bar
24 width = <none> # if set, the maximum width of the progress information
24 width = <none> # if set, the maximum width of the progress information
25 # (that is, min(width, term width) will be used)
25 # (that is, min(width, term width) will be used)
26 clear-complete = True # clear the progress bar after it's done
26 clear-complete = True # clear the progress bar after it's done
27 disable = False # if true, don't show a progress bar
27 disable = False # if true, don't show a progress bar
28 assume-tty = False # if true, ALWAYS show a progress bar, unless
28 assume-tty = False # if true, ALWAYS show a progress bar, unless
29 # disable is given
29 # disable is given
30
30
31 Valid entries for the format field are topic, bar, number, unit,
31 Valid entries for the format field are topic, bar, number, unit,
32 estimate, speed, and item. item defaults to the last 20 characters of
32 estimate, speed, and item. item defaults to the last 20 characters of
33 the item, but this can be changed by adding either ``-<num>`` which
33 the item, but this can be changed by adding either ``-<num>`` which
34 would take the last num characters, or ``+<num>`` for the first num
34 would take the last num characters, or ``+<num>`` for the first num
35 characters.
35 characters.
36 """
36 """
37
37
38 import sys
38 import sys
39 import time
39 import time
40
40
41 from mercurial.i18n import _
41 from mercurial.i18n import _
42 testedwith = 'internal'
42 testedwith = 'internal'
43
43
44 from mercurial import encoding
44 from mercurial import encoding
45
45
46 def spacejoin(*args):
46 def spacejoin(*args):
47 return ' '.join(s for s in args if s)
47 return ' '.join(s for s in args if s)
48
48
49 def shouldprint(ui):
49 def shouldprint(ui):
50 return not ui.plain() and (ui._isatty(sys.stderr) or
50 return not ui.plain() and (ui._isatty(sys.stderr) or
51 ui.configbool('progress', 'assume-tty'))
51 ui.configbool('progress', 'assume-tty'))
52
52
53 def fmtremaining(seconds):
53 def fmtremaining(seconds):
54 if seconds < 60:
54 if seconds < 60:
55 # i18n: format XX seconds as "XXs"
55 # i18n: format XX seconds as "XXs"
56 return _("%02ds") % (seconds)
56 return _("%02ds") % (seconds)
57 minutes = seconds // 60
57 minutes = seconds // 60
58 if minutes < 60:
58 if minutes < 60:
59 seconds -= minutes * 60
59 seconds -= minutes * 60
60 # i18n: format X minutes and YY seconds as "XmYYs"
60 # i18n: format X minutes and YY seconds as "XmYYs"
61 return _("%dm%02ds") % (minutes, seconds)
61 return _("%dm%02ds") % (minutes, seconds)
62 # we're going to ignore seconds in this case
62 # we're going to ignore seconds in this case
63 minutes += 1
63 minutes += 1
64 hours = minutes // 60
64 hours = minutes // 60
65 minutes -= hours * 60
65 minutes -= hours * 60
66 if hours < 30:
66 if hours < 30:
67 # i18n: format X hours and YY minutes as "XhYYm"
67 # i18n: format X hours and YY minutes as "XhYYm"
68 return _("%dh%02dm") % (hours, minutes)
68 return _("%dh%02dm") % (hours, minutes)
69 # we're going to ignore minutes in this case
69 # we're going to ignore minutes in this case
70 hours += 1
70 hours += 1
71 days = hours // 24
71 days = hours // 24
72 hours -= days * 24
72 hours -= days * 24
73 if days < 15:
73 if days < 15:
74 # i18n: format X days and YY hours as "XdYYh"
74 # i18n: format X days and YY hours as "XdYYh"
75 return _("%dd%02dh") % (days, hours)
75 return _("%dd%02dh") % (days, hours)
76 # we're going to ignore hours in this case
76 # we're going to ignore hours in this case
77 days += 1
77 days += 1
78 weeks = days // 7
78 weeks = days // 7
79 days -= weeks * 7
79 days -= weeks * 7
80 if weeks < 55:
80 if weeks < 55:
81 # i18n: format X weeks and YY days as "XwYYd"
81 # i18n: format X weeks and YY days as "XwYYd"
82 return _("%dw%02dd") % (weeks, days)
82 return _("%dw%02dd") % (weeks, days)
83 # we're going to ignore days and treat a year as 52 weeks
83 # we're going to ignore days and treat a year as 52 weeks
84 weeks += 1
84 weeks += 1
85 years = weeks // 52
85 years = weeks // 52
86 weeks -= years * 52
86 weeks -= years * 52
87 # i18n: format X years and YY weeks as "XyYYw"
87 # i18n: format X years and YY weeks as "XyYYw"
88 return _("%dy%02dw") % (years, weeks)
88 return _("%dy%02dw") % (years, weeks)
89
89
90 class progbar(object):
90 class progbar(object):
91 def __init__(self, ui):
91 def __init__(self, ui):
92 self.ui = ui
92 self.ui = ui
93 self.resetstate()
93 self.resetstate()
94
94
95 def resetstate(self):
95 def resetstate(self):
96 self.topics = []
96 self.topics = []
97 self.topicstates = {}
97 self.topicstates = {}
98 self.starttimes = {}
98 self.starttimes = {}
99 self.startvals = {}
99 self.startvals = {}
100 self.printed = False
100 self.printed = False
101 self.lastprint = time.time() + float(self.ui.config(
101 self.lastprint = time.time() + float(self.ui.config(
102 'progress', 'delay', default=3))
102 'progress', 'delay', default=3))
103 self.lasttopic = None
103 self.lasttopic = None
104 self.indetcount = 0
104 self.indetcount = 0
105 self.refresh = float(self.ui.config(
105 self.refresh = float(self.ui.config(
106 'progress', 'refresh', default=0.1))
106 'progress', 'refresh', default=0.1))
107 self.changedelay = max(3 * self.refresh,
107 self.changedelay = max(3 * self.refresh,
108 float(self.ui.config(
108 float(self.ui.config(
109 'progress', 'changedelay', default=1)))
109 'progress', 'changedelay', default=1)))
110 self.order = self.ui.configlist(
110 self.order = self.ui.configlist(
111 'progress', 'format',
111 'progress', 'format',
112 default=['topic', 'bar', 'number', 'estimate'])
112 default=['topic', 'bar', 'number', 'estimate'])
113
113
114 def show(self, now, topic, pos, item, unit, total):
114 def show(self, now, topic, pos, item, unit, total):
115 if not shouldprint(self.ui):
115 if not shouldprint(self.ui):
116 return
116 return
117 termwidth = self.width()
117 termwidth = self.width()
118 self.printed = True
118 self.printed = True
119 head = ''
119 head = ''
120 needprogress = False
120 needprogress = False
121 tail = ''
121 tail = ''
122 for indicator in self.order:
122 for indicator in self.order:
123 add = ''
123 add = ''
124 if indicator == 'topic':
124 if indicator == 'topic':
125 add = topic
125 add = topic
126 elif indicator == 'number':
126 elif indicator == 'number':
127 if total:
127 if total:
128 add = ('% ' + str(len(str(total))) +
128 add = ('% ' + str(len(str(total))) +
129 's/%s') % (pos, total)
129 's/%s') % (pos, total)
130 else:
130 else:
131 add = str(pos)
131 add = str(pos)
132 elif indicator.startswith('item') and item:
132 elif indicator.startswith('item') and item:
133 slice = 'end'
133 slice = 'end'
134 if '-' in indicator:
134 if '-' in indicator:
135 wid = int(indicator.split('-')[1])
135 wid = int(indicator.split('-')[1])
136 elif '+' in indicator:
136 elif '+' in indicator:
137 slice = 'beginning'
137 slice = 'beginning'
138 wid = int(indicator.split('+')[1])
138 wid = int(indicator.split('+')[1])
139 else:
139 else:
140 wid = 20
140 wid = 20
141 if slice == 'end':
141 if slice == 'end':
142 add = encoding.trim(item, wid, leftside=True)
142 add = encoding.trim(item, wid, leftside=True)
143 else:
143 else:
144 add = encoding.trim(item, wid)
144 add = encoding.trim(item, wid)
145 add += (wid - len(add)) * ' '
145 add += (wid - encoding.colwidth(add)) * ' '
146 elif indicator == 'bar':
146 elif indicator == 'bar':
147 add = ''
147 add = ''
148 needprogress = True
148 needprogress = True
149 elif indicator == 'unit' and unit:
149 elif indicator == 'unit' and unit:
150 add = unit
150 add = unit
151 elif indicator == 'estimate':
151 elif indicator == 'estimate':
152 add = self.estimate(topic, pos, total, now)
152 add = self.estimate(topic, pos, total, now)
153 elif indicator == 'speed':
153 elif indicator == 'speed':
154 add = self.speed(topic, pos, unit, now)
154 add = self.speed(topic, pos, unit, now)
155 if not needprogress:
155 if not needprogress:
156 head = spacejoin(head, add)
156 head = spacejoin(head, add)
157 else:
157 else:
158 tail = spacejoin(tail, add)
158 tail = spacejoin(tail, add)
159 if needprogress:
159 if needprogress:
160 used = 0
160 used = 0
161 if head:
161 if head:
162 used += encoding.colwidth(head) + 1
162 used += encoding.colwidth(head) + 1
163 if tail:
163 if tail:
164 used += encoding.colwidth(tail) + 1
164 used += encoding.colwidth(tail) + 1
165 progwidth = termwidth - used - 3
165 progwidth = termwidth - used - 3
166 if total and pos <= total:
166 if total and pos <= total:
167 amt = pos * progwidth // total
167 amt = pos * progwidth // total
168 bar = '=' * (amt - 1)
168 bar = '=' * (amt - 1)
169 if amt > 0:
169 if amt > 0:
170 bar += '>'
170 bar += '>'
171 bar += ' ' * (progwidth - amt)
171 bar += ' ' * (progwidth - amt)
172 else:
172 else:
173 progwidth -= 3
173 progwidth -= 3
174 self.indetcount += 1
174 self.indetcount += 1
175 # mod the count by twice the width so we can make the
175 # mod the count by twice the width so we can make the
176 # cursor bounce between the right and left sides
176 # cursor bounce between the right and left sides
177 amt = self.indetcount % (2 * progwidth)
177 amt = self.indetcount % (2 * progwidth)
178 amt -= progwidth
178 amt -= progwidth
179 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
179 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
180 ' ' * int(abs(amt)))
180 ' ' * int(abs(amt)))
181 prog = ''.join(('[', bar , ']'))
181 prog = ''.join(('[', bar , ']'))
182 out = spacejoin(head, prog, tail)
182 out = spacejoin(head, prog, tail)
183 else:
183 else:
184 out = spacejoin(head, tail)
184 out = spacejoin(head, tail)
185 sys.stderr.write('\r' + encoding.trim(out, termwidth))
185 sys.stderr.write('\r' + encoding.trim(out, termwidth))
186 self.lasttopic = topic
186 self.lasttopic = topic
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 # reset the last topic to the one we just unwound to,
244 # reset the last topic to the one we just unwound to,
245 # so that higher-level topics will be stickier than
245 # so that higher-level topics will be stickier than
246 # lower-level topics
246 # lower-level topics
247 if self.topics:
247 if self.topics:
248 self.lasttopic = self.topics[-1]
248 self.lasttopic = self.topics[-1]
249 else:
249 else:
250 self.lasttopic = None
250 self.lasttopic = None
251 else:
251 else:
252 if topic not in self.topics:
252 if topic not in self.topics:
253 self.starttimes[topic] = now
253 self.starttimes[topic] = now
254 self.startvals[topic] = pos
254 self.startvals[topic] = pos
255 self.topics.append(topic)
255 self.topics.append(topic)
256 self.topicstates[topic] = pos, item, unit, total
256 self.topicstates[topic] = pos, item, unit, total
257 if now - self.lastprint >= self.refresh and self.topics:
257 if now - self.lastprint >= self.refresh and self.topics:
258 if (self.lasttopic is None # first time we printed
258 if (self.lasttopic is None # first time we printed
259 # not a topic change
259 # not a topic change
260 or topic == self.lasttopic
260 or topic == self.lasttopic
261 # it's been long enough we should print anyway
261 # it's been long enough we should print anyway
262 or now - self.lastprint >= self.changedelay):
262 or now - self.lastprint >= self.changedelay):
263 self.lastprint = now
263 self.lastprint = now
264 self.show(now, topic, *self.topicstates[topic])
264 self.show(now, topic, *self.topicstates[topic])
265
265
266 _singleton = None
266 _singleton = None
267
267
268 def uisetup(ui):
268 def uisetup(ui):
269 global _singleton
269 global _singleton
270 class progressui(ui.__class__):
270 class progressui(ui.__class__):
271 _progbar = None
271 _progbar = None
272
272
273 def _quiet(self):
273 def _quiet(self):
274 return self.debugflag or self.quiet
274 return self.debugflag or self.quiet
275
275
276 def progress(self, *args, **opts):
276 def progress(self, *args, **opts):
277 if not self._quiet():
277 if not self._quiet():
278 self._progbar.progress(*args, **opts)
278 self._progbar.progress(*args, **opts)
279 return super(progressui, self).progress(*args, **opts)
279 return super(progressui, self).progress(*args, **opts)
280
280
281 def write(self, *args, **opts):
281 def write(self, *args, **opts):
282 if not self._quiet() and self._progbar.printed:
282 if not self._quiet() and self._progbar.printed:
283 self._progbar.clear()
283 self._progbar.clear()
284 return super(progressui, self).write(*args, **opts)
284 return super(progressui, self).write(*args, **opts)
285
285
286 def write_err(self, *args, **opts):
286 def write_err(self, *args, **opts):
287 if not self._quiet() and self._progbar.printed:
287 if not self._quiet() and self._progbar.printed:
288 self._progbar.clear()
288 self._progbar.clear()
289 return super(progressui, self).write_err(*args, **opts)
289 return super(progressui, self).write_err(*args, **opts)
290
290
291 # Apps that derive a class from ui.ui() can use
291 # Apps that derive a class from ui.ui() can use
292 # setconfig('progress', 'disable', 'True') to disable this extension
292 # setconfig('progress', 'disable', 'True') to disable this extension
293 if ui.configbool('progress', 'disable'):
293 if ui.configbool('progress', 'disable'):
294 return
294 return
295 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
295 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
296 ui.__class__ = progressui
296 ui.__class__ = progressui
297 # we instantiate one globally shared progress bar to avoid
297 # we instantiate one globally shared progress bar to avoid
298 # competing progress bars when multiple UI objects get created
298 # competing progress bars when multiple UI objects get created
299 if not progressui._progbar:
299 if not progressui._progbar:
300 if _singleton is None:
300 if _singleton is None:
301 _singleton = progbar(ui)
301 _singleton = progbar(ui)
302 progressui._progbar = _singleton
302 progressui._progbar = _singleton
303
303
304 def reposetup(ui, repo):
304 def reposetup(ui, repo):
305 uisetup(repo.ui)
305 uisetup(repo.ui)
@@ -1,336 +1,339
1
1
2 $ cat > loop.py <<EOF
2 $ cat > loop.py <<EOF
3 > from mercurial import cmdutil, commands
3 > from mercurial import cmdutil, commands
4 > import time
4 > import time
5 >
5 >
6 > cmdtable = {}
6 > cmdtable = {}
7 > command = cmdutil.command(cmdtable)
7 > command = cmdutil.command(cmdtable)
8 >
8 >
9 > class incrementingtime(object):
9 > class incrementingtime(object):
10 > def __init__(self):
10 > def __init__(self):
11 > self._time = 0.0
11 > self._time = 0.0
12 > def __call__(self):
12 > def __call__(self):
13 > self._time += 0.25
13 > self._time += 0.25
14 > return self._time
14 > return self._time
15 > time.time = incrementingtime()
15 > time.time = incrementingtime()
16 >
16 >
17 > @command('loop',
17 > @command('loop',
18 > [('', 'total', '', 'override for total'),
18 > [('', 'total', '', 'override for total'),
19 > ('', 'nested', False, 'show nested results'),
19 > ('', 'nested', False, 'show nested results'),
20 > ('', 'parallel', False, 'show parallel sets of results')],
20 > ('', 'parallel', False, 'show parallel sets of results')],
21 > 'hg loop LOOPS',
21 > 'hg loop LOOPS',
22 > norepo=True)
22 > norepo=True)
23 > def loop(ui, loops, **opts):
23 > def loop(ui, loops, **opts):
24 > loops = int(loops)
24 > loops = int(loops)
25 > total = None
25 > total = None
26 > if loops >= 0:
26 > if loops >= 0:
27 > total = loops
27 > total = loops
28 > if opts.get('total', None):
28 > if opts.get('total', None):
29 > total = int(opts.get('total'))
29 > total = int(opts.get('total'))
30 > nested = False
30 > nested = False
31 > if opts.get('nested', None):
31 > if opts.get('nested', None):
32 > nested = True
32 > nested = True
33 > loops = abs(loops)
33 > loops = abs(loops)
34 >
34 >
35 > for i in range(loops):
35 > for i in range(loops):
36 > ui.progress(topiclabel, i, getloopitem(i), 'loopnum', total)
36 > ui.progress(topiclabel, i, getloopitem(i), 'loopnum', total)
37 > if opts.get('parallel'):
37 > if opts.get('parallel'):
38 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
38 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
39 > if nested:
39 > if nested:
40 > nested_steps = 2
40 > nested_steps = 2
41 > if i and i % 4 == 0:
41 > if i and i % 4 == 0:
42 > nested_steps = 5
42 > nested_steps = 5
43 > for j in range(nested_steps):
43 > for j in range(nested_steps):
44 > ui.progress(
44 > ui.progress(
45 > 'nested', j, 'nested.%d' % j, 'nestnum', nested_steps)
45 > 'nested', j, 'nested.%d' % j, 'nestnum', nested_steps)
46 > ui.progress(
46 > ui.progress(
47 > 'nested', None, 'nested.done', 'nestnum', nested_steps)
47 > 'nested', None, 'nested.done', 'nestnum', nested_steps)
48 > ui.progress(topiclabel, None, 'loop.done', 'loopnum', total)
48 > ui.progress(topiclabel, None, 'loop.done', 'loopnum', total)
49 >
49 >
50 > topiclabel = 'loop'
50 > topiclabel = 'loop'
51 > def getloopitem(i):
51 > def getloopitem(i):
52 > return 'loop.%d' % i
52 > return 'loop.%d' % i
53 >
53 >
54 > EOF
54 > EOF
55
55
56 $ cp $HGRCPATH $HGRCPATH.orig
56 $ cp $HGRCPATH $HGRCPATH.orig
57 $ echo "[extensions]" >> $HGRCPATH
57 $ echo "[extensions]" >> $HGRCPATH
58 $ echo "progress=" >> $HGRCPATH
58 $ echo "progress=" >> $HGRCPATH
59 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
59 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
60 $ echo "[progress]" >> $HGRCPATH
60 $ echo "[progress]" >> $HGRCPATH
61 $ echo "format = topic bar number" >> $HGRCPATH
61 $ echo "format = topic bar number" >> $HGRCPATH
62 $ echo "assume-tty=1" >> $HGRCPATH
62 $ echo "assume-tty=1" >> $HGRCPATH
63 $ echo "width=60" >> $HGRCPATH
63 $ echo "width=60" >> $HGRCPATH
64
64
65 test default params, display nothing because of delay
65 test default params, display nothing because of delay
66
66
67 $ hg -y loop 3
67 $ hg -y loop 3
68 $ echo "delay=0" >> $HGRCPATH
68 $ echo "delay=0" >> $HGRCPATH
69 $ echo "refresh=0" >> $HGRCPATH
69 $ echo "refresh=0" >> $HGRCPATH
70
70
71 test with delay=0, refresh=0
71 test with delay=0, refresh=0
72
72
73 $ hg -y loop 3
73 $ hg -y loop 3
74 \r (no-eol) (esc)
74 \r (no-eol) (esc)
75 loop [ ] 0/3\r (no-eol) (esc)
75 loop [ ] 0/3\r (no-eol) (esc)
76 loop [===============> ] 1/3\r (no-eol) (esc)
76 loop [===============> ] 1/3\r (no-eol) (esc)
77 loop [===============================> ] 2/3\r (no-eol) (esc)
77 loop [===============================> ] 2/3\r (no-eol) (esc)
78 \r (no-eol) (esc)
78 \r (no-eol) (esc)
79
79
80
80
81 test nested short-lived topics (which shouldn't display with nestdelay):
81 test nested short-lived topics (which shouldn't display with nestdelay):
82
82
83 $ hg -y loop 3 --nested
83 $ hg -y loop 3 --nested
84 \r (no-eol) (esc)
84 \r (no-eol) (esc)
85 loop [ ] 0/3\r (no-eol) (esc)
85 loop [ ] 0/3\r (no-eol) (esc)
86 loop [===============> ] 1/3\r (no-eol) (esc)
86 loop [===============> ] 1/3\r (no-eol) (esc)
87 loop [===============================> ] 2/3\r (no-eol) (esc)
87 loop [===============================> ] 2/3\r (no-eol) (esc)
88 \r (no-eol) (esc)
88 \r (no-eol) (esc)
89
89
90 Test nested long-lived topic which has the same name as a short-lived
90 Test nested long-lived topic which has the same name as a short-lived
91 peer. We shouldn't get stuck showing the short-lived inner steps, and
91 peer. We shouldn't get stuck showing the short-lived inner steps, and
92 should go back to skipping the inner steps when the slow nested step
92 should go back to skipping the inner steps when the slow nested step
93 finishes.
93 finishes.
94
94
95 $ hg -y loop 7 --nested
95 $ hg -y loop 7 --nested
96 \r (no-eol) (esc)
96 \r (no-eol) (esc)
97 loop [ ] 0/7\r (no-eol) (esc)
97 loop [ ] 0/7\r (no-eol) (esc)
98 loop [=====> ] 1/7\r (no-eol) (esc)
98 loop [=====> ] 1/7\r (no-eol) (esc)
99 loop [============> ] 2/7\r (no-eol) (esc)
99 loop [============> ] 2/7\r (no-eol) (esc)
100 loop [===================> ] 3/7\r (no-eol) (esc)
100 loop [===================> ] 3/7\r (no-eol) (esc)
101 loop [==========================> ] 4/7\r (no-eol) (esc)
101 loop [==========================> ] 4/7\r (no-eol) (esc)
102 nested [==========================> ] 3/5\r (no-eol) (esc)
102 nested [==========================> ] 3/5\r (no-eol) (esc)
103 nested [===================================> ] 4/5\r (no-eol) (esc)
103 nested [===================================> ] 4/5\r (no-eol) (esc)
104 loop [=================================> ] 5/7\r (no-eol) (esc)
104 loop [=================================> ] 5/7\r (no-eol) (esc)
105 loop [========================================> ] 6/7\r (no-eol) (esc)
105 loop [========================================> ] 6/7\r (no-eol) (esc)
106 \r (no-eol) (esc)
106 \r (no-eol) (esc)
107
107
108
108
109 $ hg --config progress.changedelay=0 -y loop 3 --nested
109 $ hg --config progress.changedelay=0 -y loop 3 --nested
110 \r (no-eol) (esc)
110 \r (no-eol) (esc)
111 loop [ ] 0/3\r (no-eol) (esc)
111 loop [ ] 0/3\r (no-eol) (esc)
112 nested [ ] 0/2\r (no-eol) (esc)
112 nested [ ] 0/2\r (no-eol) (esc)
113 nested [======================> ] 1/2\r (no-eol) (esc)
113 nested [======================> ] 1/2\r (no-eol) (esc)
114 loop [===============> ] 1/3\r (no-eol) (esc)
114 loop [===============> ] 1/3\r (no-eol) (esc)
115 nested [ ] 0/2\r (no-eol) (esc)
115 nested [ ] 0/2\r (no-eol) (esc)
116 nested [======================> ] 1/2\r (no-eol) (esc)
116 nested [======================> ] 1/2\r (no-eol) (esc)
117 loop [===============================> ] 2/3\r (no-eol) (esc)
117 loop [===============================> ] 2/3\r (no-eol) (esc)
118 nested [ ] 0/2\r (no-eol) (esc)
118 nested [ ] 0/2\r (no-eol) (esc)
119 nested [======================> ] 1/2\r (no-eol) (esc)
119 nested [======================> ] 1/2\r (no-eol) (esc)
120 \r (no-eol) (esc)
120 \r (no-eol) (esc)
121
121
122
122
123 test two topics being printed in parallel (as when we're doing a local
123 test two topics being printed in parallel (as when we're doing a local
124 --pull clone, where you get the unbundle and bundle progress at the
124 --pull clone, where you get the unbundle and bundle progress at the
125 same time):
125 same time):
126 $ hg loop 3 --parallel
126 $ hg loop 3 --parallel
127 \r (no-eol) (esc)
127 \r (no-eol) (esc)
128 loop [ ] 0/3\r (no-eol) (esc)
128 loop [ ] 0/3\r (no-eol) (esc)
129 loop [===============> ] 1/3\r (no-eol) (esc)
129 loop [===============> ] 1/3\r (no-eol) (esc)
130 loop [===============================> ] 2/3\r (no-eol) (esc)
130 loop [===============================> ] 2/3\r (no-eol) (esc)
131 \r (no-eol) (esc)
131 \r (no-eol) (esc)
132 test refresh is taken in account
132 test refresh is taken in account
133
133
134 $ hg -y --config progress.refresh=100 loop 3
134 $ hg -y --config progress.refresh=100 loop 3
135
135
136 test format options 1
136 test format options 1
137
137
138 $ hg -y --config 'progress.format=number topic item+2' loop 2
138 $ hg -y --config 'progress.format=number topic item+2' loop 2
139 \r (no-eol) (esc)
139 \r (no-eol) (esc)
140 0/2 loop lo\r (no-eol) (esc)
140 0/2 loop lo\r (no-eol) (esc)
141 1/2 loop lo\r (no-eol) (esc)
141 1/2 loop lo\r (no-eol) (esc)
142 \r (no-eol) (esc)
142 \r (no-eol) (esc)
143
143
144 test format options 2
144 test format options 2
145
145
146 $ hg -y --config 'progress.format=number item-3 bar' loop 2
146 $ hg -y --config 'progress.format=number item-3 bar' loop 2
147 \r (no-eol) (esc)
147 \r (no-eol) (esc)
148 0/2 p.0 [ ]\r (no-eol) (esc)
148 0/2 p.0 [ ]\r (no-eol) (esc)
149 1/2 p.1 [=======================> ]\r (no-eol) (esc)
149 1/2 p.1 [=======================> ]\r (no-eol) (esc)
150 \r (no-eol) (esc)
150 \r (no-eol) (esc)
151
151
152 test format options and indeterminate progress
152 test format options and indeterminate progress
153
153
154 $ hg -y --config 'progress.format=number item bar' loop -- -2
154 $ hg -y --config 'progress.format=number item bar' loop -- -2
155 \r (no-eol) (esc)
155 \r (no-eol) (esc)
156 0 loop.0 [ <=> ]\r (no-eol) (esc)
156 0 loop.0 [ <=> ]\r (no-eol) (esc)
157 1 loop.1 [ <=> ]\r (no-eol) (esc)
157 1 loop.1 [ <=> ]\r (no-eol) (esc)
158 \r (no-eol) (esc)
158 \r (no-eol) (esc)
159
159
160 make sure things don't fall over if count > total
160 make sure things don't fall over if count > total
161
161
162 $ hg -y loop --total 4 6
162 $ hg -y loop --total 4 6
163 \r (no-eol) (esc)
163 \r (no-eol) (esc)
164 loop [ ] 0/4\r (no-eol) (esc)
164 loop [ ] 0/4\r (no-eol) (esc)
165 loop [===========> ] 1/4\r (no-eol) (esc)
165 loop [===========> ] 1/4\r (no-eol) (esc)
166 loop [=======================> ] 2/4\r (no-eol) (esc)
166 loop [=======================> ] 2/4\r (no-eol) (esc)
167 loop [===================================> ] 3/4\r (no-eol) (esc)
167 loop [===================================> ] 3/4\r (no-eol) (esc)
168 loop [===============================================>] 4/4\r (no-eol) (esc)
168 loop [===============================================>] 4/4\r (no-eol) (esc)
169 loop [ <=> ] 5/4\r (no-eol) (esc)
169 loop [ <=> ] 5/4\r (no-eol) (esc)
170 \r (no-eol) (esc)
170 \r (no-eol) (esc)
171
171
172 test immediate progress completion
172 test immediate progress completion
173
173
174 $ hg -y loop 0
174 $ hg -y loop 0
175
175
176 test delay time estimates
176 test delay time estimates
177
177
178 $ cat > mocktime.py <<EOF
178 $ cat > mocktime.py <<EOF
179 > import os
179 > import os
180 > import time
180 > import time
181 >
181 >
182 > class mocktime(object):
182 > class mocktime(object):
183 > def __init__(self, increment):
183 > def __init__(self, increment):
184 > self.time = 0
184 > self.time = 0
185 > self.increment = increment
185 > self.increment = increment
186 > def __call__(self):
186 > def __call__(self):
187 > self.time += self.increment
187 > self.time += self.increment
188 > return self.time
188 > return self.time
189 >
189 >
190 > def uisetup(ui):
190 > def uisetup(ui):
191 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
191 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
192 > EOF
192 > EOF
193
193
194 $ cp $HGRCPATH.orig $HGRCPATH
194 $ cp $HGRCPATH.orig $HGRCPATH
195 $ echo "[extensions]" >> $HGRCPATH
195 $ echo "[extensions]" >> $HGRCPATH
196 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
196 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
197 $ echo "progress=" >> $HGRCPATH
197 $ echo "progress=" >> $HGRCPATH
198 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
198 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
199 $ echo "[progress]" >> $HGRCPATH
199 $ echo "[progress]" >> $HGRCPATH
200 $ echo "assume-tty=1" >> $HGRCPATH
200 $ echo "assume-tty=1" >> $HGRCPATH
201 $ echo "delay=25" >> $HGRCPATH
201 $ echo "delay=25" >> $HGRCPATH
202 $ echo "width=60" >> $HGRCPATH
202 $ echo "width=60" >> $HGRCPATH
203
203
204 $ hg -y loop 8
204 $ hg -y loop 8
205 \r (no-eol) (esc)
205 \r (no-eol) (esc)
206 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
206 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
207 loop [===============> ] 3/8 56s\r (no-eol) (esc)
207 loop [===============> ] 3/8 56s\r (no-eol) (esc)
208 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
208 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
209 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
209 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
210 loop [================================> ] 6/8 23s\r (no-eol) (esc)
210 loop [================================> ] 6/8 23s\r (no-eol) (esc)
211 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
211 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
212 \r (no-eol) (esc)
212 \r (no-eol) (esc)
213
213
214 $ MOCKTIME=10000 hg -y loop 4
214 $ MOCKTIME=10000 hg -y loop 4
215 \r (no-eol) (esc)
215 \r (no-eol) (esc)
216 loop [ ] 0/4\r (no-eol) (esc)
216 loop [ ] 0/4\r (no-eol) (esc)
217 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
217 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
218 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
218 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
219 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
219 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
220 \r (no-eol) (esc)
220 \r (no-eol) (esc)
221
221
222 $ MOCKTIME=1000000 hg -y loop 4
222 $ MOCKTIME=1000000 hg -y loop 4
223 \r (no-eol) (esc)
223 \r (no-eol) (esc)
224 loop [ ] 0/4\r (no-eol) (esc)
224 loop [ ] 0/4\r (no-eol) (esc)
225 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
225 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
226 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
226 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
227 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
227 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
228 \r (no-eol) (esc)
228 \r (no-eol) (esc)
229
229
230
230
231 $ MOCKTIME=14000000 hg -y loop 4
231 $ MOCKTIME=14000000 hg -y loop 4
232 \r (no-eol) (esc)
232 \r (no-eol) (esc)
233 loop [ ] 0/4\r (no-eol) (esc)
233 loop [ ] 0/4\r (no-eol) (esc)
234 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
234 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
235 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
235 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
236 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
236 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
237 \r (no-eol) (esc)
237 \r (no-eol) (esc)
238
238
239 Time estimates should not fail when there's no end point:
239 Time estimates should not fail when there's no end point:
240 $ hg -y loop -- -4
240 $ hg -y loop -- -4
241 \r (no-eol) (esc)
241 \r (no-eol) (esc)
242 loop [ <=> ] 2\r (no-eol) (esc)
242 loop [ <=> ] 2\r (no-eol) (esc)
243 loop [ <=> ] 3\r (no-eol) (esc)
243 loop [ <=> ] 3\r (no-eol) (esc)
244 \r (no-eol) (esc)
244 \r (no-eol) (esc)
245
245
246 test line trimming by '[progress] width', when progress topic contains
246 test line trimming by '[progress] width', when progress topic contains
247 multi-byte characters, of which length of byte sequence and columns in
247 multi-byte characters, of which length of byte sequence and columns in
248 display are different from each other.
248 display are different from each other.
249
249
250 $ cp $HGRCPATH.orig $HGRCPATH
250 $ cp $HGRCPATH.orig $HGRCPATH
251 $ cat >> $HGRCPATH <<EOF
251 $ cat >> $HGRCPATH <<EOF
252 > [extensions]
252 > [extensions]
253 > progress=
253 > progress=
254 > loop=`pwd`/loop.py
254 > loop=`pwd`/loop.py
255 > [progress]
255 > [progress]
256 > assume-tty = 1
256 > assume-tty = 1
257 > delay = 0
257 > delay = 0
258 > refresh = 0
258 > refresh = 0
259 > EOF
259 > EOF
260
260
261 $ rm -f loop.pyc
261 $ rm -f loop.pyc
262 $ cat >> loop.py <<EOF
262 $ cat >> loop.py <<EOF
263 > # use non-ascii characters as topic label of progress
263 > # use non-ascii characters as topic label of progress
264 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
264 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
265 > topiclabel = u'\u3042\u3044\u3046\u3048'.encode('utf-8')
265 > topiclabel = u'\u3042\u3044\u3046\u3048'.encode('utf-8')
266 > EOF
266 > EOF
267
267
268 $ cat >> $HGRCPATH <<EOF
268 $ cat >> $HGRCPATH <<EOF
269 > [progress]
269 > [progress]
270 > format = topic number
270 > format = topic number
271 > width= 12
271 > width= 12
272 > EOF
272 > EOF
273
273
274 $ hg --encoding utf-8 -y loop --total 3 3
274 $ hg --encoding utf-8 -y loop --total 3 3
275 \r (no-eol) (esc)
275 \r (no-eol) (esc)
276 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 0/3\r (no-eol) (esc)
276 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 0/3\r (no-eol) (esc)
277 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 1/3\r (no-eol) (esc)
277 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 1/3\r (no-eol) (esc)
278 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 2/3\r (no-eol) (esc)
278 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 2/3\r (no-eol) (esc)
279 \r (no-eol) (esc)
279 \r (no-eol) (esc)
280
280
281 test calculation of bar width, when progress topic contains multi-byte
281 test calculation of bar width, when progress topic contains multi-byte
282 characters, of which length of byte sequence and columns in display
282 characters, of which length of byte sequence and columns in display
283 are different from each other.
283 are different from each other.
284
284
285 $ cat >> $HGRCPATH <<EOF
285 $ cat >> $HGRCPATH <<EOF
286 > [progress]
286 > [progress]
287 > format = topic bar
287 > format = topic bar
288 > width= 21
288 > width= 21
289 > # progwidth should be 9 (= 21 - (8+1) - 3)
289 > # progwidth should be 9 (= 21 - (8+1) - 3)
290 > EOF
290 > EOF
291
291
292 $ hg --encoding utf-8 -y loop --total 3 3
292 $ hg --encoding utf-8 -y loop --total 3 3
293 \r (no-eol) (esc)
293 \r (no-eol) (esc)
294 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [ ]\r (no-eol) (esc)
294 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [ ]\r (no-eol) (esc)
295 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [==> ]\r (no-eol) (esc)
295 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [==> ]\r (no-eol) (esc)
296 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [=====> ]\r (no-eol) (esc)
296 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 [=====> ]\r (no-eol) (esc)
297 \r (no-eol) (esc)
297 \r (no-eol) (esc)
298
298
299 test triming progress items, when they contain multi-byte characters,
299 test triming progress items, when they contain multi-byte characters,
300 of which length of byte sequence and columns in display are different
300 of which length of byte sequence and columns in display are different
301 from each other.
301 from each other.
302
302
303 $ rm -f loop.pyc
303 $ rm -f loop.pyc
304 $ cat >> loop.py <<EOF
304 $ cat >> loop.py <<EOF
305 > # use non-ascii characters as loop items of progress
305 > # use non-ascii characters as loop items of progress
306 > loopitems = [
306 > loopitems = [
307 > u'\u3042\u3044'.encode('utf-8'), # 2 x 2 = 4 columns
307 > u'\u3042\u3044\u3046'.encode('utf-8'), # 2 x 3 = 6 columns
308 > u'\u3042\u3044\u3046'.encode('utf-8'), # 2 x 3 = 6 columns
308 > u'\u3042\u3044\u3046\u3048'.encode('utf-8'), # 2 x 4 = 8 columns
309 > u'\u3042\u3044\u3046\u3048'.encode('utf-8'), # 2 x 4 = 8 columns
309 > ]
310 > ]
310 > def getloopitem(i):
311 > def getloopitem(i):
311 > return loopitems[i % len(loopitems)]
312 > return loopitems[i % len(loopitems)]
312 > EOF
313 > EOF
313
314
314 $ cat >> $HGRCPATH <<EOF
315 $ cat >> $HGRCPATH <<EOF
315 > [progress]
316 > [progress]
316 > # trim at tail side
317 > # trim at tail side
317 > format = item+6
318 > format = item+6
318 > EOF
319 > EOF
319
320
320 $ hg --encoding utf-8 -y loop --total 2 2
321 $ hg --encoding utf-8 -y loop --total 3 3
321 \r (no-eol) (esc)
322 \r (no-eol) (esc)
323 \xe3\x81\x82\xe3\x81\x84 \r (no-eol) (esc)
322 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
324 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
323 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
325 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
324 \r (no-eol) (esc)
326 \r (no-eol) (esc)
325
327
326 $ cat >> $HGRCPATH <<EOF
328 $ cat >> $HGRCPATH <<EOF
327 > [progress]
329 > [progress]
328 > # trim at left side
330 > # trim at left side
329 > format = item-6
331 > format = item-6
330 > EOF
332 > EOF
331
333
332 $ hg --encoding utf-8 -y loop --total 2 2
334 $ hg --encoding utf-8 -y loop --total 3 3
333 \r (no-eol) (esc)
335 \r (no-eol) (esc)
336 \xe3\x81\x82\xe3\x81\x84 \r (no-eol) (esc)
334 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
337 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\r (no-eol) (esc)
335 \xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\r (no-eol) (esc)
338 \xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\r (no-eol) (esc)
336 \r (no-eol) (esc)
339 \r (no-eol) (esc)
General Comments 0
You need to be logged in to leave comments. Login now