##// END OF EJS Templates
progress: add a changedelay to prevent parallel topics from flapping (issue2698)...
Augie Fackler -
r14838:5d261fd0 default
parent child Browse files
Show More
@@ -1,289 +1,302 b''
1 1 # progress.py show progress bars for some actions
2 2 #
3 3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
4 4 #
5 5 # This program is free software; you can redistribute it and/or modify it
6 6 # under the terms of the GNU General Public License as published by the
7 7 # Free Software Foundation; either version 2 of the License, or (at your
8 8 # option) any later version.
9 9 #
10 10 # This program is distributed in the hope that it will be useful, but
11 11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 13 # Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License along
16 16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 18
19 19 """show progress bars for some actions
20 20
21 21 This extension uses the progress information logged by hg commands
22 22 to draw progress bars that are as informative as possible. Some progress
23 23 bars only offer indeterminate information, while others have a definite
24 24 end point.
25 25
26 26 The following settings are available::
27 27
28 28 [progress]
29 29 delay = 3 # number of seconds (float) before showing the progress bar
30 changedelay = 1 # changedelay: minimum delay before showing a new topic.
31 # If set to less than 3 * refresh, that value will
32 # be used instead.
30 33 refresh = 0.1 # time in seconds between refreshes of the progress bar
31 34 format = topic bar number estimate # format of the progress bar
32 35 width = <none> # if set, the maximum width of the progress information
33 36 # (that is, min(width, term width) will be used)
34 37 clear-complete = True # clear the progress bar after it's done
35 38 disable = False # if true, don't show a progress bar
36 39 assume-tty = False # if true, ALWAYS show a progress bar, unless
37 40 # disable is given
38 41
39 42 Valid entries for the format field are topic, bar, number, unit,
40 43 estimate, speed, and item. item defaults to the last 20 characters of
41 44 the item, but this can be changed by adding either ``-<num>`` which
42 45 would take the last num characters, or ``+<num>`` for the first num
43 46 characters.
44 47 """
45 48
46 49 import sys
47 50 import time
48 51
49 52 from mercurial import util
50 53 from mercurial.i18n import _
51 54
52 55 def spacejoin(*args):
53 56 return ' '.join(s for s in args if s)
54 57
55 58 def shouldprint(ui):
56 59 return util.isatty(sys.stderr) or ui.configbool('progress', 'assume-tty')
57 60
58 61 def fmtremaining(seconds):
59 62 if seconds < 60:
60 63 # i18n: format XX seconds as "XXs"
61 64 return _("%02ds") % (seconds)
62 65 minutes = seconds // 60
63 66 if minutes < 60:
64 67 seconds -= minutes * 60
65 68 # i18n: format X minutes and YY seconds as "XmYYs"
66 69 return _("%dm%02ds") % (minutes, seconds)
67 70 # we're going to ignore seconds in this case
68 71 minutes += 1
69 72 hours = minutes // 60
70 73 minutes -= hours * 60
71 74 if hours < 30:
72 75 # i18n: format X hours and YY minutes as "XhYYm"
73 76 return _("%dh%02dm") % (hours, minutes)
74 77 # we're going to ignore minutes in this case
75 78 hours += 1
76 79 days = hours // 24
77 80 hours -= days * 24
78 81 if days < 15:
79 82 # i18n: format X days and YY hours as "XdYYh"
80 83 return _("%dd%02dh") % (days, hours)
81 84 # we're going to ignore hours in this case
82 85 days += 1
83 86 weeks = days // 7
84 87 days -= weeks * 7
85 88 if weeks < 55:
86 89 # i18n: format X weeks and YY days as "XwYYd"
87 90 return _("%dw%02dd") % (weeks, days)
88 91 # we're going to ignore days and treat a year as 52 weeks
89 92 weeks += 1
90 93 years = weeks // 52
91 94 weeks -= years * 52
92 95 # i18n: format X years and YY weeks as "XyYYw"
93 96 return _("%dy%02dw") % (years, weeks)
94 97
95 98 class progbar(object):
96 99 def __init__(self, ui):
97 100 self.ui = ui
98 101 self.resetstate()
99 102
100 103 def resetstate(self):
101 104 self.topics = []
102 105 self.topicstates = {}
103 106 self.starttimes = {}
104 107 self.startvals = {}
105 108 self.printed = False
106 109 self.lastprint = time.time() + float(self.ui.config(
107 110 'progress', 'delay', default=3))
111 self.lasttopic = None
108 112 self.indetcount = 0
109 113 self.refresh = float(self.ui.config(
110 114 'progress', 'refresh', default=0.1))
115 self.changedelay = max(3 * self.refresh,
116 float(self.ui.config(
117 'progress', 'changedelay', default=1)))
111 118 self.order = self.ui.configlist(
112 119 'progress', 'format',
113 120 default=['topic', 'bar', 'number', 'estimate'])
114 121
115 122 def show(self, now, topic, pos, item, unit, total):
116 123 if not shouldprint(self.ui):
117 124 return
118 125 termwidth = self.width()
119 126 self.printed = True
120 127 head = ''
121 128 needprogress = False
122 129 tail = ''
123 130 for indicator in self.order:
124 131 add = ''
125 132 if indicator == 'topic':
126 133 add = topic
127 134 elif indicator == 'number':
128 135 if total:
129 136 add = ('% ' + str(len(str(total))) +
130 137 's/%s') % (pos, total)
131 138 else:
132 139 add = str(pos)
133 140 elif indicator.startswith('item') and item:
134 141 slice = 'end'
135 142 if '-' in indicator:
136 143 wid = int(indicator.split('-')[1])
137 144 elif '+' in indicator:
138 145 slice = 'beginning'
139 146 wid = int(indicator.split('+')[1])
140 147 else:
141 148 wid = 20
142 149 if slice == 'end':
143 150 add = item[-wid:]
144 151 else:
145 152 add = item[:wid]
146 153 add += (wid - len(add)) * ' '
147 154 elif indicator == 'bar':
148 155 add = ''
149 156 needprogress = True
150 157 elif indicator == 'unit' and unit:
151 158 add = unit
152 159 elif indicator == 'estimate':
153 160 add = self.estimate(topic, pos, total, now)
154 161 elif indicator == 'speed':
155 162 add = self.speed(topic, pos, unit, now)
156 163 if not needprogress:
157 164 head = spacejoin(head, add)
158 165 else:
159 166 tail = spacejoin(tail, add)
160 167 if needprogress:
161 168 used = 0
162 169 if head:
163 170 used += len(head) + 1
164 171 if tail:
165 172 used += len(tail) + 1
166 173 progwidth = termwidth - used - 3
167 174 if total and pos <= total:
168 175 amt = pos * progwidth // total
169 176 bar = '=' * (amt - 1)
170 177 if amt > 0:
171 178 bar += '>'
172 179 bar += ' ' * (progwidth - amt)
173 180 else:
174 181 progwidth -= 3
175 182 self.indetcount += 1
176 183 # mod the count by twice the width so we can make the
177 184 # cursor bounce between the right and left sides
178 185 amt = self.indetcount % (2 * progwidth)
179 186 amt -= progwidth
180 187 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
181 188 ' ' * int(abs(amt)))
182 189 prog = ''.join(('[', bar , ']'))
183 190 out = spacejoin(head, prog, tail)
184 191 else:
185 192 out = spacejoin(head, tail)
186 193 sys.stderr.write('\r' + out[:termwidth])
194 self.lasttopic = topic
187 195 sys.stderr.flush()
188 196
189 197 def clear(self):
190 198 if not shouldprint(self.ui):
191 199 return
192 200 sys.stderr.write('\r%s\r' % (' ' * self.width()))
193 201
194 202 def complete(self):
195 203 if not shouldprint(self.ui):
196 204 return
197 205 if self.ui.configbool('progress', 'clear-complete', default=True):
198 206 self.clear()
199 207 else:
200 208 sys.stderr.write('\n')
201 209 sys.stderr.flush()
202 210
203 211 def width(self):
204 212 tw = self.ui.termwidth()
205 213 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
206 214
207 215 def estimate(self, topic, pos, total, now):
208 216 if total is None:
209 217 return ''
210 218 initialpos = self.startvals[topic]
211 219 target = total - initialpos
212 220 delta = pos - initialpos
213 221 if delta > 0:
214 222 elapsed = now - self.starttimes[topic]
215 223 if elapsed > float(
216 224 self.ui.config('progress', 'estimate', default=2)):
217 225 seconds = (elapsed * (target - delta)) // delta + 1
218 226 return fmtremaining(seconds)
219 227 return ''
220 228
221 229 def speed(self, topic, pos, unit, now):
222 230 initialpos = self.startvals[topic]
223 231 delta = pos - initialpos
224 232 elapsed = now - self.starttimes[topic]
225 233 if elapsed > float(
226 234 self.ui.config('progress', 'estimate', default=2)):
227 235 return _('%d %s/sec') % (delta / elapsed, unit)
228 236 return ''
229 237
230 238 def progress(self, topic, pos, item='', unit='', total=None):
231 239 now = time.time()
232 240 if pos is None:
233 241 self.starttimes.pop(topic, None)
234 242 self.startvals.pop(topic, None)
235 243 self.topicstates.pop(topic, None)
236 244 # reset the progress bar if this is the outermost topic
237 245 if self.topics and self.topics[0] == topic and self.printed:
238 246 self.complete()
239 247 self.resetstate()
240 248 # truncate the list of topics assuming all topics within
241 249 # this one are also closed
242 250 if topic in self.topics:
243 251 self.topics = self.topics[:self.topics.index(topic)]
244 252 else:
245 253 if topic not in self.topics:
246 254 self.starttimes[topic] = now
247 255 self.startvals[topic] = pos
248 256 self.topics.append(topic)
249 257 self.topicstates[topic] = pos, item, unit, total
250 258 if now - self.lastprint >= self.refresh and self.topics:
251 self.lastprint = now
252 self.show(now, topic, *self.topicstates[topic])
259 if (self.lasttopic is None # first time we printed
260 # not a topic change
261 or topic == self.lasttopic
262 # it's been long enough we should print anyway
263 or now - self.lastprint >= self.changedelay):
264 self.lastprint = now
265 self.show(now, topic, *self.topicstates[topic])
253 266
254 267 _singleton = None
255 268
256 269 def uisetup(ui):
257 270 global _singleton
258 271 class progressui(ui.__class__):
259 272 _progbar = None
260 273
261 274 def progress(self, *args, **opts):
262 275 self._progbar.progress(*args, **opts)
263 276 return super(progressui, self).progress(*args, **opts)
264 277
265 278 def write(self, *args, **opts):
266 279 if self._progbar.printed:
267 280 self._progbar.clear()
268 281 return super(progressui, self).write(*args, **opts)
269 282
270 283 def write_err(self, *args, **opts):
271 284 if self._progbar.printed:
272 285 self._progbar.clear()
273 286 return super(progressui, self).write_err(*args, **opts)
274 287
275 288 # Apps that derive a class from ui.ui() can use
276 289 # setconfig('progress', 'disable', 'True') to disable this extension
277 290 if ui.configbool('progress', 'disable'):
278 291 return
279 292 if shouldprint(ui) and not ui.debugflag and not ui.quiet:
280 293 ui.__class__ = progressui
281 294 # we instantiate one globally shared progress bar to avoid
282 295 # competing progress bars when multiple UI objects get created
283 296 if not progressui._progbar:
284 297 if _singleton is None:
285 298 _singleton = progbar(ui)
286 299 progressui._progbar = _singleton
287 300
288 301 def reposetup(ui, repo):
289 302 uisetup(repo.ui)
@@ -1,248 +1,249 b''
1 1
2 2 $ "$TESTDIR/hghave" svn svn-bindings || exit 80
3 3
4 4 $ fixpath()
5 5 > {
6 6 > tr '\\' /
7 7 > }
8 8 $ cat >> $HGRCPATH <<EOF
9 9 > [extensions]
10 10 > convert =
11 11 > graphlog =
12 12 > EOF
13 13
14 14 $ svnadmin create svn-repo
15 15 $ svnadmin load -q svn-repo < "$TESTDIR/svn/move.svndump"
16 16 $ svnpath=`pwd | fixpath`
17 17
18 18 SVN wants all paths to start with a slash. Unfortunately,
19 19 Windows ones don't. Handle that.
20 20
21 21 $ expr "$svnpath" : "\/" > /dev/null
22 22 > if [ $? -ne 0 ]; then
23 23 > svnpath="/$svnpath"
24 24 > fi
25 25 > svnurl="file://$svnpath/svn-repo"
26 26
27 27 Convert trunk and branches
28 28
29 29 $ hg convert --datesort "$svnurl"/subproject A-hg
30 30 initializing destination A-hg repository
31 31 scanning source...
32 32 sorting...
33 33 converting...
34 34 13 createtrunk
35 35 12 moved1
36 36 11 moved1
37 37 10 moved2
38 38 9 changeb and rm d2
39 39 8 changeb and rm d2
40 40 7 moved1again
41 41 6 moved1again
42 42 5 copyfilefrompast
43 43 4 copydirfrompast
44 44 3 add d3
45 45 2 copy dir and remove subdir
46 46 1 add d4old
47 47 0 rename d4old into d4new
48 48
49 49 $ cd A-hg
50 50 $ hg glog --template '{rev} {desc|firstline} files: {files}\n'
51 51 o 13 rename d4old into d4new files: d4new/g d4old/g
52 52 |
53 53 o 12 add d4old files: d4old/g
54 54 |
55 55 o 11 copy dir and remove subdir files: d3/d31/e d4/d31/e d4/f
56 56 |
57 57 o 10 add d3 files: d3/d31/e d3/f
58 58 |
59 59 o 9 copydirfrompast files: d2/d
60 60 |
61 61 o 8 copyfilefrompast files: d
62 62 |
63 63 o 7 moved1again files: d1/b d1/c
64 64 |
65 65 | o 6 moved1again files:
66 66 | |
67 67 o | 5 changeb and rm d2 files: d1/b d2/d
68 68 | |
69 69 | o 4 changeb and rm d2 files: b
70 70 | |
71 71 o | 3 moved2 files: d2/d
72 72 | |
73 73 o | 2 moved1 files: d1/b d1/c
74 74 | |
75 75 | o 1 moved1 files: b c
76 76 |
77 77 o 0 createtrunk files:
78 78
79 79
80 80 Check move copy records
81 81
82 82 $ hg st --rev 12:13 --copies
83 83 A d4new/g
84 84 d4old/g
85 85 R d4old/g
86 86
87 87 Check branches
88 88
89 89 $ hg branches
90 90 default 13:* (glob)
91 91 d1 6:* (glob)
92 92 $ cd ..
93 93
94 94 $ mkdir test-replace
95 95 $ cd test-replace
96 96 $ svnadmin create svn-repo
97 97 $ svnadmin load -q svn-repo < "$TESTDIR/svn/replace.svndump"
98 98
99 99 Convert files being replaced by directories
100 100
101 101 $ hg convert svn-repo hg-repo
102 102 initializing destination hg-repo repository
103 103 scanning source...
104 104 sorting...
105 105 converting...
106 106 6 initial
107 107 5 clobber symlink
108 108 4 clobber1
109 109 3 clobber2
110 110 2 adddb
111 111 1 branch
112 112 0 clobberdir
113 113
114 114 $ cd hg-repo
115 115
116 116 Manifest before
117 117
118 118 $ hg -v manifest -r 1
119 119 644 a
120 120 644 d/b
121 121 644 d2/a
122 122 644 @ dlink
123 123 644 @ dlink2
124 124 644 dlink3
125 125
126 126 Manifest after clobber1
127 127
128 128 $ hg -v manifest -r 2
129 129 644 a/b
130 130 644 d/b
131 131 644 d2/a
132 132 644 dlink/b
133 133 644 @ dlink2
134 134 644 dlink3
135 135
136 136 Manifest after clobber2
137 137
138 138 $ hg -v manifest -r 3
139 139 644 a/b
140 140 644 d/b
141 141 644 d2/a
142 142 644 dlink/b
143 143 644 @ dlink2
144 144 644 @ dlink3
145 145
146 146 Manifest after clobberdir
147 147
148 148 $ hg -v manifest -r 6
149 149 644 a/b
150 150 644 d/b
151 151 644 d2/a
152 152 644 d2/c
153 153 644 dlink/b
154 154 644 @ dlink2
155 155 644 @ dlink3
156 156
157 157 Try updating
158 158
159 159 $ hg up -qC default
160 160 $ cd ..
161 161
162 162 Test convert progress bar'
163 163
164 164 $ cat >> $HGRCPATH <<EOF
165 165 > [extensions]
166 166 > progress =
167 167 > [progress]
168 168 > assume-tty = 1
169 169 > delay = 0
170 > changedelay = 0
170 171 > format = topic bar number
171 172 > refresh = 0
172 173 > width = 60
173 174 > EOF
174 175
175 176 $ hg convert svn-repo hg-progress 2>&1 | $TESTDIR/filtercr.py
176 177
177 178 scanning [ <=> ] 1
178 179 scanning [ <=> ] 2
179 180 scanning [ <=> ] 3
180 181 scanning [ <=> ] 4
181 182 scanning [ <=> ] 5
182 183 scanning [ <=> ] 6
183 184 scanning [ <=> ] 7
184 185
185 186 converting [ ] 0/7
186 187 getting files [=====> ] 1/6
187 188 getting files [============> ] 2/6
188 189 getting files [==================> ] 3/6
189 190 getting files [=========================> ] 4/6
190 191 getting files [===============================> ] 5/6
191 192 getting files [======================================>] 6/6
192 193
193 194 converting [=====> ] 1/7
194 195 scanning paths [ ] 0/1
195 196 getting files [======================================>] 1/1
196 197
197 198 converting [===========> ] 2/7
198 199 scanning paths [ ] 0/2
199 200 scanning paths [==================> ] 1/2
200 201 getting files [========> ] 1/4
201 202 getting files [==================> ] 2/4
202 203 getting files [============================> ] 3/4
203 204 getting files [======================================>] 4/4
204 205
205 206 converting [=================> ] 3/7
206 207 scanning paths [ ] 0/1
207 208 getting files [======================================>] 1/1
208 209
209 210 converting [=======================> ] 4/7
210 211 scanning paths [ ] 0/1
211 212 getting files [======================================>] 1/1
212 213
213 214 converting [=============================> ] 5/7
214 215 scanning paths [ ] 0/3
215 216 scanning paths [===========> ] 1/3
216 217 scanning paths [========================> ] 2/3
217 218 getting files [===> ] 1/8
218 219 getting files [========> ] 2/8
219 220 getting files [=============> ] 3/8
220 221 getting files [==================> ] 4/8
221 222 getting files [=======================> ] 5/8
222 223 getting files [============================> ] 6/8
223 224 getting files [=================================> ] 7/8
224 225 getting files [======================================>] 8/8
225 226
226 227 converting [===================================> ] 6/7
227 228 scanning paths [ ] 0/1
228 229 getting files [===> ] 1/8
229 230 getting files [========> ] 2/8
230 231 getting files [=============> ] 3/8
231 232 getting files [==================> ] 4/8
232 233 getting files [=======================> ] 5/8
233 234 getting files [============================> ] 6/8
234 235 getting files [=================================> ] 7/8
235 236 getting files [======================================>] 8/8
236 237
237 238 initializing destination hg-progress repository
238 239 scanning source...
239 240 sorting...
240 241 converting...
241 242 6 initial
242 243 5 clobber symlink
243 244 4 clobber1
244 245 3 clobber2
245 246 2 adddb
246 247 1 branch
247 248 0 clobberdir
248 249
@@ -1,166 +1,214 b''
1 1
2 2 $ cat > loop.py <<EOF
3 3 > from mercurial import commands
4 4 >
5 5 > def loop(ui, loops, **opts):
6 6 > loops = int(loops)
7 7 > total = None
8 8 > if loops >= 0:
9 9 > total = loops
10 10 > if opts.get('total', None):
11 11 > total = int(opts.get('total'))
12 > nested = False
13 > if opts.get('nested', None):
14 > nested = True
12 15 > loops = abs(loops)
13 16 >
14 17 > for i in range(loops):
15 18 > ui.progress('loop', i, 'loop.%d' % i, 'loopnum', total)
19 > if opts.get('parallel'):
20 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
21 > if nested:
22 > for j in range(2):
23 > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
24 > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
16 25 > ui.progress('loop', None, 'loop.done', 'loopnum', total)
17 26 >
18 27 > commands.norepo += " loop"
19 28 >
20 29 > cmdtable = {
21 > "loop": (loop, [('', 'total', '', 'override for total')],
30 > "loop": (loop, [('', 'total', '', 'override for total'),
31 > ('', 'nested', False, 'show nested results'),
32 > ('', 'parallel', False, 'show parallel sets of results'),
33 > ],
22 34 > 'hg loop LOOPS'),
23 35 > }
24 36 > EOF
25 37
26 38 $ echo "[extensions]" >> $HGRCPATH
27 39 $ echo "progress=" >> $HGRCPATH
28 40 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
29 41 $ echo "[progress]" >> $HGRCPATH
30 42 $ echo "format = topic bar number" >> $HGRCPATH
31 43 $ echo "assume-tty=1" >> $HGRCPATH
32 44 $ echo "width=60" >> $HGRCPATH
33 45
34 46 test default params, display nothing because of delay
35 47
36 48 $ hg -y loop 3 2>&1 | $TESTDIR/filtercr.py
37 49
38 50 $ echo "delay=0" >> $HGRCPATH
39 51 $ echo "refresh=0" >> $HGRCPATH
40 52
41 53 test with delay=0, refresh=0
42 54
43 55 $ hg -y loop 3 2>&1 | $TESTDIR/filtercr.py
44 56
45 57 loop [ ] 0/3
46 58 loop [===============> ] 1/3
47 59 loop [===============================> ] 2/3
48 60 \r (esc)
49 61
62
63 test nested short-lived topics (which shouldn't display with nestdelay):
64
65 $ hg -y loop 3 --nested 2>&1 | \
66 > python $TESTDIR/filtercr.py
67
68 loop [ ] 0/3
69 loop [===============> ] 1/3
70 loop [===============================> ] 2/3
71 \r (esc)
72
73
74 $ hg --config progress.changedelay=0 -y loop 3 --nested 2>&1 | \
75 > python $TESTDIR/filtercr.py
76
77 loop [ ] 0/3
78 nested [ ] 0/2
79 nested [======================> ] 1/2
80 loop [===============> ] 1/3
81 nested [ ] 0/2
82 nested [======================> ] 1/2
83 loop [===============================> ] 2/3
84 nested [ ] 0/2
85 nested [======================> ] 1/2
86 \r (esc)
87
88
89 test two topics being printed in parallel (as when we're doing a local
90 --pull clone, where you get the unbundle and bundle progress at the
91 same time):
92 $ hg loop 3 --parallel 2>&1 | python $TESTDIR/filtercr.py
93
94 loop [ ] 0/3
95 loop [===============> ] 1/3
96 loop [===============================> ] 2/3
97 \r (esc)
50 98 test refresh is taken in account
51 99
52 100 $ hg -y --config progress.refresh=100 loop 3 2>&1 | $TESTDIR/filtercr.py
53 101
54 102
55 103 test format options 1
56 104
57 105 $ hg -y --config 'progress.format=number topic item+2' loop 2 2>&1 \
58 106 > | $TESTDIR/filtercr.py
59 107
60 108 0/2 loop lo
61 109 1/2 loop lo
62 110 \r (esc)
63 111
64 112 test format options 2
65 113
66 114 $ hg -y --config 'progress.format=number item-3 bar' loop 2 2>&1 \
67 115 > | $TESTDIR/filtercr.py
68 116
69 117 0/2 p.0 [ ]
70 118 1/2 p.1 [=======================> ]
71 119 \r (esc)
72 120
73 121 test format options and indeterminate progress
74 122
75 123 $ hg -y --config 'progress.format=number item bar' loop -- -2 2>&1 \
76 124 > | $TESTDIR/filtercr.py
77 125
78 126 0 loop.0 [ <=> ]
79 127 1 loop.1 [ <=> ]
80 128 \r (esc)
81 129
82 130 make sure things don't fall over if count > total
83 131
84 132 $ hg -y loop --total 4 6 2>&1 | $TESTDIR/filtercr.py
85 133
86 134 loop [ ] 0/4
87 135 loop [===========> ] 1/4
88 136 loop [=======================> ] 2/4
89 137 loop [===================================> ] 3/4
90 138 loop [===============================================>] 4/4
91 139 loop [ <=> ] 5/4
92 140 \r (esc)
93 141
94 142 test immediate progress completion
95 143
96 144 $ hg -y loop 0 2>&1 | $TESTDIR/filtercr.py
97 145
98 146
99 147 test delay time estimates
100 148
101 149 $ cat > mocktime.py <<EOF
102 150 > import os
103 151 > import time
104 152 >
105 153 > class mocktime(object):
106 154 > def __init__(self, increment):
107 155 > self.time = 0
108 156 > self.increment = increment
109 157 > def __call__(self):
110 158 > self.time += self.increment
111 159 > return self.time
112 160 >
113 161 > def uisetup(ui):
114 162 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
115 163 > EOF
116 164
117 165 $ echo "[extensions]" > $HGRCPATH
118 166 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
119 167 $ echo "progress=" >> $HGRCPATH
120 168 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
121 169 $ echo "[progress]" >> $HGRCPATH
122 170 $ echo "assume-tty=1" >> $HGRCPATH
123 171 $ echo "delay=25" >> $HGRCPATH
124 172 $ echo "width=60" >> $HGRCPATH
125 173
126 174 $ hg -y loop 8 2>&1 | python $TESTDIR/filtercr.py
127 175
128 176 loop [=========> ] 2/8 1m07s
129 177 loop [===============> ] 3/8 56s
130 178 loop [=====================> ] 4/8 45s
131 179 loop [==========================> ] 5/8 34s
132 180 loop [================================> ] 6/8 23s
133 181 loop [=====================================> ] 7/8 12s
134 182 \r (esc)
135 183
136 184 $ MOCKTIME=10000 hg -y loop 4 2>&1 | python $TESTDIR/filtercr.py
137 185
138 186 loop [ ] 0/4
139 187 loop [=========> ] 1/4 8h21m
140 188 loop [====================> ] 2/4 5h34m
141 189 loop [==============================> ] 3/4 2h47m
142 190 \r (esc)
143 191
144 192 $ MOCKTIME=1000000 hg -y loop 4 2>&1 | python $TESTDIR/filtercr.py
145 193
146 194 loop [ ] 0/4
147 195 loop [=========> ] 1/4 5w00d
148 196 loop [====================> ] 2/4 3w03d
149 197 loop [=============================> ] 3/4 11d14h
150 198 \r (esc)
151 199
152 200
153 201 $ MOCKTIME=14000000 hg -y loop 4 2>&1 | python $TESTDIR/filtercr.py
154 202
155 203 loop [ ] 0/4
156 204 loop [=========> ] 1/4 1y18w
157 205 loop [===================> ] 2/4 46w03d
158 206 loop [=============================> ] 3/4 23w02d
159 207 \r (esc)
160 208
161 209 Time estimates should not fail when there's no end point:
162 210 $ hg -y loop -- -4 2>&1 | python $TESTDIR/filtercr.py
163 211
164 212 loop [ <=> ] 2
165 213 loop [ <=> ] 3
166 214 \r (esc)
General Comments 0
You need to be logged in to leave comments. Login now