##// END OF EJS Templates
progress: use 'encoding.trim' to trim output line correctly...
FUJIWARA Katsunori -
r21859:be4270d2 default
parent child Browse files
Show More
@@ -1,303 +1,305 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 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
45
44 def spacejoin(*args):
46 def spacejoin(*args):
45 return ' '.join(s for s in args if s)
47 return ' '.join(s for s in args if s)
46
48
47 def shouldprint(ui):
49 def shouldprint(ui):
48 return not ui.plain() and (ui._isatty(sys.stderr) or
50 return not ui.plain() and (ui._isatty(sys.stderr) or
49 ui.configbool('progress', 'assume-tty'))
51 ui.configbool('progress', 'assume-tty'))
50
52
51 def fmtremaining(seconds):
53 def fmtremaining(seconds):
52 if seconds < 60:
54 if seconds < 60:
53 # i18n: format XX seconds as "XXs"
55 # i18n: format XX seconds as "XXs"
54 return _("%02ds") % (seconds)
56 return _("%02ds") % (seconds)
55 minutes = seconds // 60
57 minutes = seconds // 60
56 if minutes < 60:
58 if minutes < 60:
57 seconds -= minutes * 60
59 seconds -= minutes * 60
58 # i18n: format X minutes and YY seconds as "XmYYs"
60 # i18n: format X minutes and YY seconds as "XmYYs"
59 return _("%dm%02ds") % (minutes, seconds)
61 return _("%dm%02ds") % (minutes, seconds)
60 # we're going to ignore seconds in this case
62 # we're going to ignore seconds in this case
61 minutes += 1
63 minutes += 1
62 hours = minutes // 60
64 hours = minutes // 60
63 minutes -= hours * 60
65 minutes -= hours * 60
64 if hours < 30:
66 if hours < 30:
65 # i18n: format X hours and YY minutes as "XhYYm"
67 # i18n: format X hours and YY minutes as "XhYYm"
66 return _("%dh%02dm") % (hours, minutes)
68 return _("%dh%02dm") % (hours, minutes)
67 # we're going to ignore minutes in this case
69 # we're going to ignore minutes in this case
68 hours += 1
70 hours += 1
69 days = hours // 24
71 days = hours // 24
70 hours -= days * 24
72 hours -= days * 24
71 if days < 15:
73 if days < 15:
72 # i18n: format X days and YY hours as "XdYYh"
74 # i18n: format X days and YY hours as "XdYYh"
73 return _("%dd%02dh") % (days, hours)
75 return _("%dd%02dh") % (days, hours)
74 # we're going to ignore hours in this case
76 # we're going to ignore hours in this case
75 days += 1
77 days += 1
76 weeks = days // 7
78 weeks = days // 7
77 days -= weeks * 7
79 days -= weeks * 7
78 if weeks < 55:
80 if weeks < 55:
79 # i18n: format X weeks and YY days as "XwYYd"
81 # i18n: format X weeks and YY days as "XwYYd"
80 return _("%dw%02dd") % (weeks, days)
82 return _("%dw%02dd") % (weeks, days)
81 # 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
82 weeks += 1
84 weeks += 1
83 years = weeks // 52
85 years = weeks // 52
84 weeks -= years * 52
86 weeks -= years * 52
85 # i18n: format X years and YY weeks as "XyYYw"
87 # i18n: format X years and YY weeks as "XyYYw"
86 return _("%dy%02dw") % (years, weeks)
88 return _("%dy%02dw") % (years, weeks)
87
89
88 class progbar(object):
90 class progbar(object):
89 def __init__(self, ui):
91 def __init__(self, ui):
90 self.ui = ui
92 self.ui = ui
91 self.resetstate()
93 self.resetstate()
92
94
93 def resetstate(self):
95 def resetstate(self):
94 self.topics = []
96 self.topics = []
95 self.topicstates = {}
97 self.topicstates = {}
96 self.starttimes = {}
98 self.starttimes = {}
97 self.startvals = {}
99 self.startvals = {}
98 self.printed = False
100 self.printed = False
99 self.lastprint = time.time() + float(self.ui.config(
101 self.lastprint = time.time() + float(self.ui.config(
100 'progress', 'delay', default=3))
102 'progress', 'delay', default=3))
101 self.lasttopic = None
103 self.lasttopic = None
102 self.indetcount = 0
104 self.indetcount = 0
103 self.refresh = float(self.ui.config(
105 self.refresh = float(self.ui.config(
104 'progress', 'refresh', default=0.1))
106 'progress', 'refresh', default=0.1))
105 self.changedelay = max(3 * self.refresh,
107 self.changedelay = max(3 * self.refresh,
106 float(self.ui.config(
108 float(self.ui.config(
107 'progress', 'changedelay', default=1)))
109 'progress', 'changedelay', default=1)))
108 self.order = self.ui.configlist(
110 self.order = self.ui.configlist(
109 'progress', 'format',
111 'progress', 'format',
110 default=['topic', 'bar', 'number', 'estimate'])
112 default=['topic', 'bar', 'number', 'estimate'])
111
113
112 def show(self, now, topic, pos, item, unit, total):
114 def show(self, now, topic, pos, item, unit, total):
113 if not shouldprint(self.ui):
115 if not shouldprint(self.ui):
114 return
116 return
115 termwidth = self.width()
117 termwidth = self.width()
116 self.printed = True
118 self.printed = True
117 head = ''
119 head = ''
118 needprogress = False
120 needprogress = False
119 tail = ''
121 tail = ''
120 for indicator in self.order:
122 for indicator in self.order:
121 add = ''
123 add = ''
122 if indicator == 'topic':
124 if indicator == 'topic':
123 add = topic
125 add = topic
124 elif indicator == 'number':
126 elif indicator == 'number':
125 if total:
127 if total:
126 add = ('% ' + str(len(str(total))) +
128 add = ('% ' + str(len(str(total))) +
127 's/%s') % (pos, total)
129 's/%s') % (pos, total)
128 else:
130 else:
129 add = str(pos)
131 add = str(pos)
130 elif indicator.startswith('item') and item:
132 elif indicator.startswith('item') and item:
131 slice = 'end'
133 slice = 'end'
132 if '-' in indicator:
134 if '-' in indicator:
133 wid = int(indicator.split('-')[1])
135 wid = int(indicator.split('-')[1])
134 elif '+' in indicator:
136 elif '+' in indicator:
135 slice = 'beginning'
137 slice = 'beginning'
136 wid = int(indicator.split('+')[1])
138 wid = int(indicator.split('+')[1])
137 else:
139 else:
138 wid = 20
140 wid = 20
139 if slice == 'end':
141 if slice == 'end':
140 add = item[-wid:]
142 add = item[-wid:]
141 else:
143 else:
142 add = item[:wid]
144 add = item[:wid]
143 add += (wid - len(add)) * ' '
145 add += (wid - len(add)) * ' '
144 elif indicator == 'bar':
146 elif indicator == 'bar':
145 add = ''
147 add = ''
146 needprogress = True
148 needprogress = True
147 elif indicator == 'unit' and unit:
149 elif indicator == 'unit' and unit:
148 add = unit
150 add = unit
149 elif indicator == 'estimate':
151 elif indicator == 'estimate':
150 add = self.estimate(topic, pos, total, now)
152 add = self.estimate(topic, pos, total, now)
151 elif indicator == 'speed':
153 elif indicator == 'speed':
152 add = self.speed(topic, pos, unit, now)
154 add = self.speed(topic, pos, unit, now)
153 if not needprogress:
155 if not needprogress:
154 head = spacejoin(head, add)
156 head = spacejoin(head, add)
155 else:
157 else:
156 tail = spacejoin(tail, add)
158 tail = spacejoin(tail, add)
157 if needprogress:
159 if needprogress:
158 used = 0
160 used = 0
159 if head:
161 if head:
160 used += len(head) + 1
162 used += len(head) + 1
161 if tail:
163 if tail:
162 used += len(tail) + 1
164 used += len(tail) + 1
163 progwidth = termwidth - used - 3
165 progwidth = termwidth - used - 3
164 if total and pos <= total:
166 if total and pos <= total:
165 amt = pos * progwidth // total
167 amt = pos * progwidth // total
166 bar = '=' * (amt - 1)
168 bar = '=' * (amt - 1)
167 if amt > 0:
169 if amt > 0:
168 bar += '>'
170 bar += '>'
169 bar += ' ' * (progwidth - amt)
171 bar += ' ' * (progwidth - amt)
170 else:
172 else:
171 progwidth -= 3
173 progwidth -= 3
172 self.indetcount += 1
174 self.indetcount += 1
173 # 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
174 # cursor bounce between the right and left sides
176 # cursor bounce between the right and left sides
175 amt = self.indetcount % (2 * progwidth)
177 amt = self.indetcount % (2 * progwidth)
176 amt -= progwidth
178 amt -= progwidth
177 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
179 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
178 ' ' * int(abs(amt)))
180 ' ' * int(abs(amt)))
179 prog = ''.join(('[', bar , ']'))
181 prog = ''.join(('[', bar , ']'))
180 out = spacejoin(head, prog, tail)
182 out = spacejoin(head, prog, tail)
181 else:
183 else:
182 out = spacejoin(head, tail)
184 out = spacejoin(head, tail)
183 sys.stderr.write('\r' + out[:termwidth])
185 sys.stderr.write('\r' + encoding.trim(out, termwidth))
184 self.lasttopic = topic
186 self.lasttopic = topic
185 sys.stderr.flush()
187 sys.stderr.flush()
186
188
187 def clear(self):
189 def clear(self):
188 if not shouldprint(self.ui):
190 if not shouldprint(self.ui):
189 return
191 return
190 sys.stderr.write('\r%s\r' % (' ' * self.width()))
192 sys.stderr.write('\r%s\r' % (' ' * self.width()))
191
193
192 def complete(self):
194 def complete(self):
193 if not shouldprint(self.ui):
195 if not shouldprint(self.ui):
194 return
196 return
195 if self.ui.configbool('progress', 'clear-complete', default=True):
197 if self.ui.configbool('progress', 'clear-complete', default=True):
196 self.clear()
198 self.clear()
197 else:
199 else:
198 sys.stderr.write('\n')
200 sys.stderr.write('\n')
199 sys.stderr.flush()
201 sys.stderr.flush()
200
202
201 def width(self):
203 def width(self):
202 tw = self.ui.termwidth()
204 tw = self.ui.termwidth()
203 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
205 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
204
206
205 def estimate(self, topic, pos, total, now):
207 def estimate(self, topic, pos, total, now):
206 if total is None:
208 if total is None:
207 return ''
209 return ''
208 initialpos = self.startvals[topic]
210 initialpos = self.startvals[topic]
209 target = total - initialpos
211 target = total - initialpos
210 delta = pos - initialpos
212 delta = pos - initialpos
211 if delta > 0:
213 if delta > 0:
212 elapsed = now - self.starttimes[topic]
214 elapsed = now - self.starttimes[topic]
213 if elapsed > float(
215 if elapsed > float(
214 self.ui.config('progress', 'estimate', default=2)):
216 self.ui.config('progress', 'estimate', default=2)):
215 seconds = (elapsed * (target - delta)) // delta + 1
217 seconds = (elapsed * (target - delta)) // delta + 1
216 return fmtremaining(seconds)
218 return fmtremaining(seconds)
217 return ''
219 return ''
218
220
219 def speed(self, topic, pos, unit, now):
221 def speed(self, topic, pos, unit, now):
220 initialpos = self.startvals[topic]
222 initialpos = self.startvals[topic]
221 delta = pos - initialpos
223 delta = pos - initialpos
222 elapsed = now - self.starttimes[topic]
224 elapsed = now - self.starttimes[topic]
223 if elapsed > float(
225 if elapsed > float(
224 self.ui.config('progress', 'estimate', default=2)):
226 self.ui.config('progress', 'estimate', default=2)):
225 return _('%d %s/sec') % (delta / elapsed, unit)
227 return _('%d %s/sec') % (delta / elapsed, unit)
226 return ''
228 return ''
227
229
228 def progress(self, topic, pos, item='', unit='', total=None):
230 def progress(self, topic, pos, item='', unit='', total=None):
229 now = time.time()
231 now = time.time()
230 if pos is None:
232 if pos is None:
231 self.starttimes.pop(topic, None)
233 self.starttimes.pop(topic, None)
232 self.startvals.pop(topic, None)
234 self.startvals.pop(topic, None)
233 self.topicstates.pop(topic, None)
235 self.topicstates.pop(topic, None)
234 # reset the progress bar if this is the outermost topic
236 # reset the progress bar if this is the outermost topic
235 if self.topics and self.topics[0] == topic and self.printed:
237 if self.topics and self.topics[0] == topic and self.printed:
236 self.complete()
238 self.complete()
237 self.resetstate()
239 self.resetstate()
238 # truncate the list of topics assuming all topics within
240 # truncate the list of topics assuming all topics within
239 # this one are also closed
241 # this one are also closed
240 if topic in self.topics:
242 if topic in self.topics:
241 self.topics = self.topics[:self.topics.index(topic)]
243 self.topics = self.topics[:self.topics.index(topic)]
242 # reset the last topic to the one we just unwound to,
244 # reset the last topic to the one we just unwound to,
243 # so that higher-level topics will be stickier than
245 # so that higher-level topics will be stickier than
244 # lower-level topics
246 # lower-level topics
245 if self.topics:
247 if self.topics:
246 self.lasttopic = self.topics[-1]
248 self.lasttopic = self.topics[-1]
247 else:
249 else:
248 self.lasttopic = None
250 self.lasttopic = None
249 else:
251 else:
250 if topic not in self.topics:
252 if topic not in self.topics:
251 self.starttimes[topic] = now
253 self.starttimes[topic] = now
252 self.startvals[topic] = pos
254 self.startvals[topic] = pos
253 self.topics.append(topic)
255 self.topics.append(topic)
254 self.topicstates[topic] = pos, item, unit, total
256 self.topicstates[topic] = pos, item, unit, total
255 if now - self.lastprint >= self.refresh and self.topics:
257 if now - self.lastprint >= self.refresh and self.topics:
256 if (self.lasttopic is None # first time we printed
258 if (self.lasttopic is None # first time we printed
257 # not a topic change
259 # not a topic change
258 or topic == self.lasttopic
260 or topic == self.lasttopic
259 # it's been long enough we should print anyway
261 # it's been long enough we should print anyway
260 or now - self.lastprint >= self.changedelay):
262 or now - self.lastprint >= self.changedelay):
261 self.lastprint = now
263 self.lastprint = now
262 self.show(now, topic, *self.topicstates[topic])
264 self.show(now, topic, *self.topicstates[topic])
263
265
264 _singleton = None
266 _singleton = None
265
267
266 def uisetup(ui):
268 def uisetup(ui):
267 global _singleton
269 global _singleton
268 class progressui(ui.__class__):
270 class progressui(ui.__class__):
269 _progbar = None
271 _progbar = None
270
272
271 def _quiet(self):
273 def _quiet(self):
272 return self.debugflag or self.quiet
274 return self.debugflag or self.quiet
273
275
274 def progress(self, *args, **opts):
276 def progress(self, *args, **opts):
275 if not self._quiet():
277 if not self._quiet():
276 self._progbar.progress(*args, **opts)
278 self._progbar.progress(*args, **opts)
277 return super(progressui, self).progress(*args, **opts)
279 return super(progressui, self).progress(*args, **opts)
278
280
279 def write(self, *args, **opts):
281 def write(self, *args, **opts):
280 if not self._quiet() and self._progbar.printed:
282 if not self._quiet() and self._progbar.printed:
281 self._progbar.clear()
283 self._progbar.clear()
282 return super(progressui, self).write(*args, **opts)
284 return super(progressui, self).write(*args, **opts)
283
285
284 def write_err(self, *args, **opts):
286 def write_err(self, *args, **opts):
285 if not self._quiet() and self._progbar.printed:
287 if not self._quiet() and self._progbar.printed:
286 self._progbar.clear()
288 self._progbar.clear()
287 return super(progressui, self).write_err(*args, **opts)
289 return super(progressui, self).write_err(*args, **opts)
288
290
289 # Apps that derive a class from ui.ui() can use
291 # Apps that derive a class from ui.ui() can use
290 # setconfig('progress', 'disable', 'True') to disable this extension
292 # setconfig('progress', 'disable', 'True') to disable this extension
291 if ui.configbool('progress', 'disable'):
293 if ui.configbool('progress', 'disable'):
292 return
294 return
293 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
295 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
294 ui.__class__ = progressui
296 ui.__class__ = progressui
295 # we instantiate one globally shared progress bar to avoid
297 # we instantiate one globally shared progress bar to avoid
296 # competing progress bars when multiple UI objects get created
298 # competing progress bars when multiple UI objects get created
297 if not progressui._progbar:
299 if not progressui._progbar:
298 if _singleton is None:
300 if _singleton is None:
299 _singleton = progbar(ui)
301 _singleton = progbar(ui)
300 progressui._progbar = _singleton
302 progressui._progbar = _singleton
301
303
302 def reposetup(ui, repo):
304 def reposetup(ui, repo):
303 uisetup(repo.ui)
305 uisetup(repo.ui)
@@ -1,240 +1,277 b''
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('loop', i, 'loop.%d' % i, 'loopnum', total)
36 > ui.progress(topiclabel, i, 'loop.%d' % 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('loop', None, 'loop.done', 'loopnum', total)
48 > ui.progress(topiclabel, None, 'loop.done', 'loopnum', total)
49 >
50 > topiclabel = 'loop'
49 >
51 >
50 > EOF
52 > EOF
51
53
52 $ cp $HGRCPATH $HGRCPATH.orig
54 $ cp $HGRCPATH $HGRCPATH.orig
53 $ echo "[extensions]" >> $HGRCPATH
55 $ echo "[extensions]" >> $HGRCPATH
54 $ echo "progress=" >> $HGRCPATH
56 $ echo "progress=" >> $HGRCPATH
55 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
57 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
56 $ echo "[progress]" >> $HGRCPATH
58 $ echo "[progress]" >> $HGRCPATH
57 $ echo "format = topic bar number" >> $HGRCPATH
59 $ echo "format = topic bar number" >> $HGRCPATH
58 $ echo "assume-tty=1" >> $HGRCPATH
60 $ echo "assume-tty=1" >> $HGRCPATH
59 $ echo "width=60" >> $HGRCPATH
61 $ echo "width=60" >> $HGRCPATH
60
62
61 test default params, display nothing because of delay
63 test default params, display nothing because of delay
62
64
63 $ hg -y loop 3
65 $ hg -y loop 3
64 $ echo "delay=0" >> $HGRCPATH
66 $ echo "delay=0" >> $HGRCPATH
65 $ echo "refresh=0" >> $HGRCPATH
67 $ echo "refresh=0" >> $HGRCPATH
66
68
67 test with delay=0, refresh=0
69 test with delay=0, refresh=0
68
70
69 $ hg -y loop 3
71 $ hg -y loop 3
70 \r (no-eol) (esc)
72 \r (no-eol) (esc)
71 loop [ ] 0/3\r (no-eol) (esc)
73 loop [ ] 0/3\r (no-eol) (esc)
72 loop [===============> ] 1/3\r (no-eol) (esc)
74 loop [===============> ] 1/3\r (no-eol) (esc)
73 loop [===============================> ] 2/3\r (no-eol) (esc)
75 loop [===============================> ] 2/3\r (no-eol) (esc)
74 \r (no-eol) (esc)
76 \r (no-eol) (esc)
75
77
76
78
77 test nested short-lived topics (which shouldn't display with nestdelay):
79 test nested short-lived topics (which shouldn't display with nestdelay):
78
80
79 $ hg -y loop 3 --nested
81 $ hg -y loop 3 --nested
80 \r (no-eol) (esc)
82 \r (no-eol) (esc)
81 loop [ ] 0/3\r (no-eol) (esc)
83 loop [ ] 0/3\r (no-eol) (esc)
82 loop [===============> ] 1/3\r (no-eol) (esc)
84 loop [===============> ] 1/3\r (no-eol) (esc)
83 loop [===============================> ] 2/3\r (no-eol) (esc)
85 loop [===============================> ] 2/3\r (no-eol) (esc)
84 \r (no-eol) (esc)
86 \r (no-eol) (esc)
85
87
86 Test nested long-lived topic which has the same name as a short-lived
88 Test nested long-lived topic which has the same name as a short-lived
87 peer. We shouldn't get stuck showing the short-lived inner steps, and
89 peer. We shouldn't get stuck showing the short-lived inner steps, and
88 should go back to skipping the inner steps when the slow nested step
90 should go back to skipping the inner steps when the slow nested step
89 finishes.
91 finishes.
90
92
91 $ hg -y loop 7 --nested
93 $ hg -y loop 7 --nested
92 \r (no-eol) (esc)
94 \r (no-eol) (esc)
93 loop [ ] 0/7\r (no-eol) (esc)
95 loop [ ] 0/7\r (no-eol) (esc)
94 loop [=====> ] 1/7\r (no-eol) (esc)
96 loop [=====> ] 1/7\r (no-eol) (esc)
95 loop [============> ] 2/7\r (no-eol) (esc)
97 loop [============> ] 2/7\r (no-eol) (esc)
96 loop [===================> ] 3/7\r (no-eol) (esc)
98 loop [===================> ] 3/7\r (no-eol) (esc)
97 loop [==========================> ] 4/7\r (no-eol) (esc)
99 loop [==========================> ] 4/7\r (no-eol) (esc)
98 nested [==========================> ] 3/5\r (no-eol) (esc)
100 nested [==========================> ] 3/5\r (no-eol) (esc)
99 nested [===================================> ] 4/5\r (no-eol) (esc)
101 nested [===================================> ] 4/5\r (no-eol) (esc)
100 loop [=================================> ] 5/7\r (no-eol) (esc)
102 loop [=================================> ] 5/7\r (no-eol) (esc)
101 loop [========================================> ] 6/7\r (no-eol) (esc)
103 loop [========================================> ] 6/7\r (no-eol) (esc)
102 \r (no-eol) (esc)
104 \r (no-eol) (esc)
103
105
104
106
105 $ hg --config progress.changedelay=0 -y loop 3 --nested
107 $ hg --config progress.changedelay=0 -y loop 3 --nested
106 \r (no-eol) (esc)
108 \r (no-eol) (esc)
107 loop [ ] 0/3\r (no-eol) (esc)
109 loop [ ] 0/3\r (no-eol) (esc)
108 nested [ ] 0/2\r (no-eol) (esc)
110 nested [ ] 0/2\r (no-eol) (esc)
109 nested [======================> ] 1/2\r (no-eol) (esc)
111 nested [======================> ] 1/2\r (no-eol) (esc)
110 loop [===============> ] 1/3\r (no-eol) (esc)
112 loop [===============> ] 1/3\r (no-eol) (esc)
111 nested [ ] 0/2\r (no-eol) (esc)
113 nested [ ] 0/2\r (no-eol) (esc)
112 nested [======================> ] 1/2\r (no-eol) (esc)
114 nested [======================> ] 1/2\r (no-eol) (esc)
113 loop [===============================> ] 2/3\r (no-eol) (esc)
115 loop [===============================> ] 2/3\r (no-eol) (esc)
114 nested [ ] 0/2\r (no-eol) (esc)
116 nested [ ] 0/2\r (no-eol) (esc)
115 nested [======================> ] 1/2\r (no-eol) (esc)
117 nested [======================> ] 1/2\r (no-eol) (esc)
116 \r (no-eol) (esc)
118 \r (no-eol) (esc)
117
119
118
120
119 test two topics being printed in parallel (as when we're doing a local
121 test two topics being printed in parallel (as when we're doing a local
120 --pull clone, where you get the unbundle and bundle progress at the
122 --pull clone, where you get the unbundle and bundle progress at the
121 same time):
123 same time):
122 $ hg loop 3 --parallel
124 $ hg loop 3 --parallel
123 \r (no-eol) (esc)
125 \r (no-eol) (esc)
124 loop [ ] 0/3\r (no-eol) (esc)
126 loop [ ] 0/3\r (no-eol) (esc)
125 loop [===============> ] 1/3\r (no-eol) (esc)
127 loop [===============> ] 1/3\r (no-eol) (esc)
126 loop [===============================> ] 2/3\r (no-eol) (esc)
128 loop [===============================> ] 2/3\r (no-eol) (esc)
127 \r (no-eol) (esc)
129 \r (no-eol) (esc)
128 test refresh is taken in account
130 test refresh is taken in account
129
131
130 $ hg -y --config progress.refresh=100 loop 3
132 $ hg -y --config progress.refresh=100 loop 3
131
133
132 test format options 1
134 test format options 1
133
135
134 $ hg -y --config 'progress.format=number topic item+2' loop 2
136 $ hg -y --config 'progress.format=number topic item+2' loop 2
135 \r (no-eol) (esc)
137 \r (no-eol) (esc)
136 0/2 loop lo\r (no-eol) (esc)
138 0/2 loop lo\r (no-eol) (esc)
137 1/2 loop lo\r (no-eol) (esc)
139 1/2 loop lo\r (no-eol) (esc)
138 \r (no-eol) (esc)
140 \r (no-eol) (esc)
139
141
140 test format options 2
142 test format options 2
141
143
142 $ hg -y --config 'progress.format=number item-3 bar' loop 2
144 $ hg -y --config 'progress.format=number item-3 bar' loop 2
143 \r (no-eol) (esc)
145 \r (no-eol) (esc)
144 0/2 p.0 [ ]\r (no-eol) (esc)
146 0/2 p.0 [ ]\r (no-eol) (esc)
145 1/2 p.1 [=======================> ]\r (no-eol) (esc)
147 1/2 p.1 [=======================> ]\r (no-eol) (esc)
146 \r (no-eol) (esc)
148 \r (no-eol) (esc)
147
149
148 test format options and indeterminate progress
150 test format options and indeterminate progress
149
151
150 $ hg -y --config 'progress.format=number item bar' loop -- -2
152 $ hg -y --config 'progress.format=number item bar' loop -- -2
151 \r (no-eol) (esc)
153 \r (no-eol) (esc)
152 0 loop.0 [ <=> ]\r (no-eol) (esc)
154 0 loop.0 [ <=> ]\r (no-eol) (esc)
153 1 loop.1 [ <=> ]\r (no-eol) (esc)
155 1 loop.1 [ <=> ]\r (no-eol) (esc)
154 \r (no-eol) (esc)
156 \r (no-eol) (esc)
155
157
156 make sure things don't fall over if count > total
158 make sure things don't fall over if count > total
157
159
158 $ hg -y loop --total 4 6
160 $ hg -y loop --total 4 6
159 \r (no-eol) (esc)
161 \r (no-eol) (esc)
160 loop [ ] 0/4\r (no-eol) (esc)
162 loop [ ] 0/4\r (no-eol) (esc)
161 loop [===========> ] 1/4\r (no-eol) (esc)
163 loop [===========> ] 1/4\r (no-eol) (esc)
162 loop [=======================> ] 2/4\r (no-eol) (esc)
164 loop [=======================> ] 2/4\r (no-eol) (esc)
163 loop [===================================> ] 3/4\r (no-eol) (esc)
165 loop [===================================> ] 3/4\r (no-eol) (esc)
164 loop [===============================================>] 4/4\r (no-eol) (esc)
166 loop [===============================================>] 4/4\r (no-eol) (esc)
165 loop [ <=> ] 5/4\r (no-eol) (esc)
167 loop [ <=> ] 5/4\r (no-eol) (esc)
166 \r (no-eol) (esc)
168 \r (no-eol) (esc)
167
169
168 test immediate progress completion
170 test immediate progress completion
169
171
170 $ hg -y loop 0
172 $ hg -y loop 0
171
173
172 test delay time estimates
174 test delay time estimates
173
175
174 $ cat > mocktime.py <<EOF
176 $ cat > mocktime.py <<EOF
175 > import os
177 > import os
176 > import time
178 > import time
177 >
179 >
178 > class mocktime(object):
180 > class mocktime(object):
179 > def __init__(self, increment):
181 > def __init__(self, increment):
180 > self.time = 0
182 > self.time = 0
181 > self.increment = increment
183 > self.increment = increment
182 > def __call__(self):
184 > def __call__(self):
183 > self.time += self.increment
185 > self.time += self.increment
184 > return self.time
186 > return self.time
185 >
187 >
186 > def uisetup(ui):
188 > def uisetup(ui):
187 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
189 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
188 > EOF
190 > EOF
189
191
190 $ cp $HGRCPATH.orig $HGRCPATH
192 $ cp $HGRCPATH.orig $HGRCPATH
191 $ echo "[extensions]" >> $HGRCPATH
193 $ echo "[extensions]" >> $HGRCPATH
192 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
194 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
193 $ echo "progress=" >> $HGRCPATH
195 $ echo "progress=" >> $HGRCPATH
194 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
196 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
195 $ echo "[progress]" >> $HGRCPATH
197 $ echo "[progress]" >> $HGRCPATH
196 $ echo "assume-tty=1" >> $HGRCPATH
198 $ echo "assume-tty=1" >> $HGRCPATH
197 $ echo "delay=25" >> $HGRCPATH
199 $ echo "delay=25" >> $HGRCPATH
198 $ echo "width=60" >> $HGRCPATH
200 $ echo "width=60" >> $HGRCPATH
199
201
200 $ hg -y loop 8
202 $ hg -y loop 8
201 \r (no-eol) (esc)
203 \r (no-eol) (esc)
202 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
204 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
203 loop [===============> ] 3/8 56s\r (no-eol) (esc)
205 loop [===============> ] 3/8 56s\r (no-eol) (esc)
204 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
206 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
205 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
207 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
206 loop [================================> ] 6/8 23s\r (no-eol) (esc)
208 loop [================================> ] 6/8 23s\r (no-eol) (esc)
207 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
209 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
208 \r (no-eol) (esc)
210 \r (no-eol) (esc)
209
211
210 $ MOCKTIME=10000 hg -y loop 4
212 $ MOCKTIME=10000 hg -y loop 4
211 \r (no-eol) (esc)
213 \r (no-eol) (esc)
212 loop [ ] 0/4\r (no-eol) (esc)
214 loop [ ] 0/4\r (no-eol) (esc)
213 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
215 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
214 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
216 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
215 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
217 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
216 \r (no-eol) (esc)
218 \r (no-eol) (esc)
217
219
218 $ MOCKTIME=1000000 hg -y loop 4
220 $ MOCKTIME=1000000 hg -y loop 4
219 \r (no-eol) (esc)
221 \r (no-eol) (esc)
220 loop [ ] 0/4\r (no-eol) (esc)
222 loop [ ] 0/4\r (no-eol) (esc)
221 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
223 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
222 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
224 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
223 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
225 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
224 \r (no-eol) (esc)
226 \r (no-eol) (esc)
225
227
226
228
227 $ MOCKTIME=14000000 hg -y loop 4
229 $ MOCKTIME=14000000 hg -y loop 4
228 \r (no-eol) (esc)
230 \r (no-eol) (esc)
229 loop [ ] 0/4\r (no-eol) (esc)
231 loop [ ] 0/4\r (no-eol) (esc)
230 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
232 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
231 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
233 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
232 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
234 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
233 \r (no-eol) (esc)
235 \r (no-eol) (esc)
234
236
235 Time estimates should not fail when there's no end point:
237 Time estimates should not fail when there's no end point:
236 $ hg -y loop -- -4
238 $ hg -y loop -- -4
237 \r (no-eol) (esc)
239 \r (no-eol) (esc)
238 loop [ <=> ] 2\r (no-eol) (esc)
240 loop [ <=> ] 2\r (no-eol) (esc)
239 loop [ <=> ] 3\r (no-eol) (esc)
241 loop [ <=> ] 3\r (no-eol) (esc)
240 \r (no-eol) (esc)
242 \r (no-eol) (esc)
243
244 test line trimming by '[progress] width', when progress topic contains
245 multi-byte characters, of which length of byte sequence and columns in
246 display are different from each other.
247
248 $ cp $HGRCPATH.orig $HGRCPATH
249 $ cat >> $HGRCPATH <<EOF
250 > [extensions]
251 > progress=
252 > loop=`pwd`/loop.py
253 > [progress]
254 > assume-tty = 1
255 > delay = 0
256 > refresh = 0
257 > EOF
258
259 $ rm -f loop.pyc
260 $ cat >> loop.py <<EOF
261 > # use non-ascii characters as topic label of progress
262 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
263 > topiclabel = u'\u3042\u3044\u3046\u3048'.encode('utf-8')
264 > EOF
265
266 $ cat >> $HGRCPATH <<EOF
267 > [progress]
268 > format = topic number
269 > width= 12
270 > EOF
271
272 $ hg --encoding utf-8 -y loop --total 3 3
273 \r (no-eol) (esc)
274 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 0/3\r (no-eol) (esc)
275 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 1/3\r (no-eol) (esc)
276 \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88 2/3\r (no-eol) (esc)
277 \r (no-eol) (esc)
General Comments 0
You need to be logged in to leave comments. Login now