##// END OF EJS Templates
blackbox: log the commands that are run...
Durham Goode -
r18670:ddc7268d default
parent child Browse files
Show More
@@ -1,834 +1,841
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.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 from i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 class request(object):
14 class request(object):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 ferr=None):
16 ferr=None):
17 self.args = args
17 self.args = args
18 self.ui = ui
18 self.ui = ui
19 self.repo = repo
19 self.repo = repo
20
20
21 # input/output/error streams
21 # input/output/error streams
22 self.fin = fin
22 self.fin = fin
23 self.fout = fout
23 self.fout = fout
24 self.ferr = ferr
24 self.ferr = ferr
25
25
26 def run():
26 def run():
27 "run the command in sys.argv"
27 "run the command in sys.argv"
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29
29
30 def dispatch(req):
30 def dispatch(req):
31 "run the command specified in req.args"
31 "run the command specified in req.args"
32 if req.ferr:
32 if req.ferr:
33 ferr = req.ferr
33 ferr = req.ferr
34 elif req.ui:
34 elif req.ui:
35 ferr = req.ui.ferr
35 ferr = req.ui.ferr
36 else:
36 else:
37 ferr = sys.stderr
37 ferr = sys.stderr
38
38
39 try:
39 try:
40 if not req.ui:
40 if not req.ui:
41 req.ui = uimod.ui()
41 req.ui = uimod.ui()
42 if '--traceback' in req.args:
42 if '--traceback' in req.args:
43 req.ui.setconfig('ui', 'traceback', 'on')
43 req.ui.setconfig('ui', 'traceback', 'on')
44
44
45 # set ui streams from the request
45 # set ui streams from the request
46 if req.fin:
46 if req.fin:
47 req.ui.fin = req.fin
47 req.ui.fin = req.fin
48 if req.fout:
48 if req.fout:
49 req.ui.fout = req.fout
49 req.ui.fout = req.fout
50 if req.ferr:
50 if req.ferr:
51 req.ui.ferr = req.ferr
51 req.ui.ferr = req.ferr
52 except util.Abort, inst:
52 except util.Abort, inst:
53 ferr.write(_("abort: %s\n") % inst)
53 ferr.write(_("abort: %s\n") % inst)
54 if inst.hint:
54 if inst.hint:
55 ferr.write(_("(%s)\n") % inst.hint)
55 ferr.write(_("(%s)\n") % inst.hint)
56 return -1
56 return -1
57 except error.ParseError, inst:
57 except error.ParseError, inst:
58 if len(inst.args) > 1:
58 if len(inst.args) > 1:
59 ferr.write(_("hg: parse error at %s: %s\n") %
59 ferr.write(_("hg: parse error at %s: %s\n") %
60 (inst.args[1], inst.args[0]))
60 (inst.args[1], inst.args[0]))
61 else:
61 else:
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
63 return -1
63 return -1
64
64
65 return _runcatch(req)
65 return _runcatch(req)
66
66
67 def _runcatch(req):
67 def _runcatch(req):
68 def catchterm(*args):
68 def catchterm(*args):
69 raise error.SignalInterrupt
69 raise error.SignalInterrupt
70
70
71 ui = req.ui
71 ui = req.ui
72 try:
72 try:
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
74 num = getattr(signal, name, None)
74 num = getattr(signal, name, None)
75 if num:
75 if num:
76 signal.signal(num, catchterm)
76 signal.signal(num, catchterm)
77 except ValueError:
77 except ValueError:
78 pass # happens if called in a thread
78 pass # happens if called in a thread
79
79
80 try:
80 try:
81 try:
81 try:
82 # enter the debugger before command execution
82 # enter the debugger before command execution
83 if '--debugger' in req.args:
83 if '--debugger' in req.args:
84 ui.warn(_("entering debugger - "
84 ui.warn(_("entering debugger - "
85 "type c to continue starting hg or h for help\n"))
85 "type c to continue starting hg or h for help\n"))
86 pdb.set_trace()
86 pdb.set_trace()
87 try:
87 try:
88 return _dispatch(req)
88 return _dispatch(req)
89 finally:
89 finally:
90 ui.flush()
90 ui.flush()
91 except: # re-raises
91 except: # re-raises
92 # enter the debugger when we hit an exception
92 # enter the debugger when we hit an exception
93 if '--debugger' in req.args:
93 if '--debugger' in req.args:
94 traceback.print_exc()
94 traceback.print_exc()
95 pdb.post_mortem(sys.exc_info()[2])
95 pdb.post_mortem(sys.exc_info()[2])
96 ui.traceback()
96 ui.traceback()
97 raise
97 raise
98
98
99 # Global exception handling, alphabetically
99 # Global exception handling, alphabetically
100 # Mercurial-specific first, followed by built-in and library exceptions
100 # Mercurial-specific first, followed by built-in and library exceptions
101 except error.AmbiguousCommand, inst:
101 except error.AmbiguousCommand, inst:
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
103 (inst.args[0], " ".join(inst.args[1])))
103 (inst.args[0], " ".join(inst.args[1])))
104 except error.ParseError, inst:
104 except error.ParseError, inst:
105 if len(inst.args) > 1:
105 if len(inst.args) > 1:
106 ui.warn(_("hg: parse error at %s: %s\n") %
106 ui.warn(_("hg: parse error at %s: %s\n") %
107 (inst.args[1], inst.args[0]))
107 (inst.args[1], inst.args[0]))
108 else:
108 else:
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
110 return -1
110 return -1
111 except error.LockHeld, inst:
111 except error.LockHeld, inst:
112 if inst.errno == errno.ETIMEDOUT:
112 if inst.errno == errno.ETIMEDOUT:
113 reason = _('timed out waiting for lock held by %s') % inst.locker
113 reason = _('timed out waiting for lock held by %s') % inst.locker
114 else:
114 else:
115 reason = _('lock held by %s') % inst.locker
115 reason = _('lock held by %s') % inst.locker
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
117 except error.LockUnavailable, inst:
117 except error.LockUnavailable, inst:
118 ui.warn(_("abort: could not lock %s: %s\n") %
118 ui.warn(_("abort: could not lock %s: %s\n") %
119 (inst.desc or inst.filename, inst.strerror))
119 (inst.desc or inst.filename, inst.strerror))
120 except error.CommandError, inst:
120 except error.CommandError, inst:
121 if inst.args[0]:
121 if inst.args[0]:
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
123 commands.help_(ui, inst.args[0], full=False, command=True)
123 commands.help_(ui, inst.args[0], full=False, command=True)
124 else:
124 else:
125 ui.warn(_("hg: %s\n") % inst.args[1])
125 ui.warn(_("hg: %s\n") % inst.args[1])
126 commands.help_(ui, 'shortlist')
126 commands.help_(ui, 'shortlist')
127 except error.OutOfBandError, inst:
127 except error.OutOfBandError, inst:
128 ui.warn(_("abort: remote error:\n"))
128 ui.warn(_("abort: remote error:\n"))
129 ui.warn(''.join(inst.args))
129 ui.warn(''.join(inst.args))
130 except error.RepoError, inst:
130 except error.RepoError, inst:
131 ui.warn(_("abort: %s!\n") % inst)
131 ui.warn(_("abort: %s!\n") % inst)
132 if inst.hint:
132 if inst.hint:
133 ui.warn(_("(%s)\n") % inst.hint)
133 ui.warn(_("(%s)\n") % inst.hint)
134 except error.ResponseError, inst:
134 except error.ResponseError, inst:
135 ui.warn(_("abort: %s") % inst.args[0])
135 ui.warn(_("abort: %s") % inst.args[0])
136 if not isinstance(inst.args[1], basestring):
136 if not isinstance(inst.args[1], basestring):
137 ui.warn(" %r\n" % (inst.args[1],))
137 ui.warn(" %r\n" % (inst.args[1],))
138 elif not inst.args[1]:
138 elif not inst.args[1]:
139 ui.warn(_(" empty string\n"))
139 ui.warn(_(" empty string\n"))
140 else:
140 else:
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
142 except error.RevlogError, inst:
142 except error.RevlogError, inst:
143 ui.warn(_("abort: %s!\n") % inst)
143 ui.warn(_("abort: %s!\n") % inst)
144 except error.SignalInterrupt:
144 except error.SignalInterrupt:
145 ui.warn(_("killed!\n"))
145 ui.warn(_("killed!\n"))
146 except error.UnknownCommand, inst:
146 except error.UnknownCommand, inst:
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
148 try:
148 try:
149 # check if the command is in a disabled extension
149 # check if the command is in a disabled extension
150 # (but don't check for extensions themselves)
150 # (but don't check for extensions themselves)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
152 except error.UnknownCommand:
152 except error.UnknownCommand:
153 commands.help_(ui, 'shortlist')
153 commands.help_(ui, 'shortlist')
154 except util.Abort, inst:
154 except util.Abort, inst:
155 ui.warn(_("abort: %s\n") % inst)
155 ui.warn(_("abort: %s\n") % inst)
156 if inst.hint:
156 if inst.hint:
157 ui.warn(_("(%s)\n") % inst.hint)
157 ui.warn(_("(%s)\n") % inst.hint)
158 except ImportError, inst:
158 except ImportError, inst:
159 ui.warn(_("abort: %s!\n") % inst)
159 ui.warn(_("abort: %s!\n") % inst)
160 m = str(inst).split()[-1]
160 m = str(inst).split()[-1]
161 if m in "mpatch bdiff".split():
161 if m in "mpatch bdiff".split():
162 ui.warn(_("(did you forget to compile extensions?)\n"))
162 ui.warn(_("(did you forget to compile extensions?)\n"))
163 elif m in "zlib".split():
163 elif m in "zlib".split():
164 ui.warn(_("(is your Python install correct?)\n"))
164 ui.warn(_("(is your Python install correct?)\n"))
165 except IOError, inst:
165 except IOError, inst:
166 if util.safehasattr(inst, "code"):
166 if util.safehasattr(inst, "code"):
167 ui.warn(_("abort: %s\n") % inst)
167 ui.warn(_("abort: %s\n") % inst)
168 elif util.safehasattr(inst, "reason"):
168 elif util.safehasattr(inst, "reason"):
169 try: # usually it is in the form (errno, strerror)
169 try: # usually it is in the form (errno, strerror)
170 reason = inst.reason.args[1]
170 reason = inst.reason.args[1]
171 except (AttributeError, IndexError):
171 except (AttributeError, IndexError):
172 # it might be anything, for example a string
172 # it might be anything, for example a string
173 reason = inst.reason
173 reason = inst.reason
174 ui.warn(_("abort: error: %s\n") % reason)
174 ui.warn(_("abort: error: %s\n") % reason)
175 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
175 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
176 if ui.debugflag:
176 if ui.debugflag:
177 ui.warn(_("broken pipe\n"))
177 ui.warn(_("broken pipe\n"))
178 elif getattr(inst, "strerror", None):
178 elif getattr(inst, "strerror", None):
179 if getattr(inst, "filename", None):
179 if getattr(inst, "filename", None):
180 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
180 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
181 else:
181 else:
182 ui.warn(_("abort: %s\n") % inst.strerror)
182 ui.warn(_("abort: %s\n") % inst.strerror)
183 else:
183 else:
184 raise
184 raise
185 except OSError, inst:
185 except OSError, inst:
186 if getattr(inst, "filename", None) is not None:
186 if getattr(inst, "filename", None) is not None:
187 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
187 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
188 else:
188 else:
189 ui.warn(_("abort: %s\n") % inst.strerror)
189 ui.warn(_("abort: %s\n") % inst.strerror)
190 except KeyboardInterrupt:
190 except KeyboardInterrupt:
191 try:
191 try:
192 ui.warn(_("interrupted!\n"))
192 ui.warn(_("interrupted!\n"))
193 except IOError, inst:
193 except IOError, inst:
194 if inst.errno == errno.EPIPE:
194 if inst.errno == errno.EPIPE:
195 if ui.debugflag:
195 if ui.debugflag:
196 ui.warn(_("\nbroken pipe\n"))
196 ui.warn(_("\nbroken pipe\n"))
197 else:
197 else:
198 raise
198 raise
199 except MemoryError:
199 except MemoryError:
200 ui.warn(_("abort: out of memory\n"))
200 ui.warn(_("abort: out of memory\n"))
201 except SystemExit, inst:
201 except SystemExit, inst:
202 # Commands shouldn't sys.exit directly, but give a return code.
202 # Commands shouldn't sys.exit directly, but give a return code.
203 # Just in case catch this and and pass exit code to caller.
203 # Just in case catch this and and pass exit code to caller.
204 return inst.code
204 return inst.code
205 except socket.error, inst:
205 except socket.error, inst:
206 ui.warn(_("abort: %s\n") % inst.args[-1])
206 ui.warn(_("abort: %s\n") % inst.args[-1])
207 except: # re-raises
207 except: # re-raises
208 myver = util.version()
208 myver = util.version()
209 # For compatibility checking, we discard the portion of the hg
209 # For compatibility checking, we discard the portion of the hg
210 # version after the + on the assumption that if a "normal
210 # version after the + on the assumption that if a "normal
211 # user" is running a build with a + in it the packager
211 # user" is running a build with a + in it the packager
212 # probably built from fairly close to a tag and anyone with a
212 # probably built from fairly close to a tag and anyone with a
213 # 'make local' copy of hg (where the version number can be out
213 # 'make local' copy of hg (where the version number can be out
214 # of date) will be clueful enough to notice the implausible
214 # of date) will be clueful enough to notice the implausible
215 # version number and try updating.
215 # version number and try updating.
216 compare = myver.split('+')[0]
216 compare = myver.split('+')[0]
217 ct = tuplever(compare)
217 ct = tuplever(compare)
218 worst = None, ct, ''
218 worst = None, ct, ''
219 for name, mod in extensions.extensions():
219 for name, mod in extensions.extensions():
220 testedwith = getattr(mod, 'testedwith', '')
220 testedwith = getattr(mod, 'testedwith', '')
221 report = getattr(mod, 'buglink', _('the extension author.'))
221 report = getattr(mod, 'buglink', _('the extension author.'))
222 if not testedwith.strip():
222 if not testedwith.strip():
223 # We found an untested extension. It's likely the culprit.
223 # We found an untested extension. It's likely the culprit.
224 worst = name, 'unknown', report
224 worst = name, 'unknown', report
225 break
225 break
226 if compare not in testedwith.split() and testedwith != 'internal':
226 if compare not in testedwith.split() and testedwith != 'internal':
227 tested = [tuplever(v) for v in testedwith.split()]
227 tested = [tuplever(v) for v in testedwith.split()]
228 lower = [t for t in tested if t < ct]
228 lower = [t for t in tested if t < ct]
229 nearest = max(lower or tested)
229 nearest = max(lower or tested)
230 if worst[0] is None or nearest < worst[1]:
230 if worst[0] is None or nearest < worst[1]:
231 worst = name, nearest, report
231 worst = name, nearest, report
232 if worst[0] is not None:
232 if worst[0] is not None:
233 name, testedwith, report = worst
233 name, testedwith, report = worst
234 if not isinstance(testedwith, str):
234 if not isinstance(testedwith, str):
235 testedwith = '.'.join([str(c) for c in testedwith])
235 testedwith = '.'.join([str(c) for c in testedwith])
236 warning = (_('** Unknown exception encountered with '
236 warning = (_('** Unknown exception encountered with '
237 'possibly-broken third-party extension %s\n'
237 'possibly-broken third-party extension %s\n'
238 '** which supports versions %s of Mercurial.\n'
238 '** which supports versions %s of Mercurial.\n'
239 '** Please disable %s and try your action again.\n'
239 '** Please disable %s and try your action again.\n'
240 '** If that fixes the bug please report it to %s\n')
240 '** If that fixes the bug please report it to %s\n')
241 % (name, testedwith, name, report))
241 % (name, testedwith, name, report))
242 else:
242 else:
243 warning = (_("** unknown exception encountered, "
243 warning = (_("** unknown exception encountered, "
244 "please report by visiting\n") +
244 "please report by visiting\n") +
245 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
245 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
246 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
246 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
247 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
247 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
248 (_("** Extensions loaded: %s\n") %
248 (_("** Extensions loaded: %s\n") %
249 ", ".join([x[0] for x in extensions.extensions()])))
249 ", ".join([x[0] for x in extensions.extensions()])))
250 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
250 ui.warn(warning)
251 ui.warn(warning)
251 raise
252 raise
252
253
253 return -1
254 return -1
254
255
255 def tuplever(v):
256 def tuplever(v):
256 try:
257 try:
257 return tuple([int(i) for i in v.split('.')])
258 return tuple([int(i) for i in v.split('.')])
258 except ValueError:
259 except ValueError:
259 return tuple()
260 return tuple()
260
261
261 def aliasargs(fn, givenargs):
262 def aliasargs(fn, givenargs):
262 args = getattr(fn, 'args', [])
263 args = getattr(fn, 'args', [])
263 if args:
264 if args:
264 cmd = ' '.join(map(util.shellquote, args))
265 cmd = ' '.join(map(util.shellquote, args))
265
266
266 nums = []
267 nums = []
267 def replacer(m):
268 def replacer(m):
268 num = int(m.group(1)) - 1
269 num = int(m.group(1)) - 1
269 nums.append(num)
270 nums.append(num)
270 if num < len(givenargs):
271 if num < len(givenargs):
271 return givenargs[num]
272 return givenargs[num]
272 raise util.Abort(_('too few arguments for command alias'))
273 raise util.Abort(_('too few arguments for command alias'))
273 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
274 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
274 givenargs = [x for i, x in enumerate(givenargs)
275 givenargs = [x for i, x in enumerate(givenargs)
275 if i not in nums]
276 if i not in nums]
276 args = shlex.split(cmd)
277 args = shlex.split(cmd)
277 return args + givenargs
278 return args + givenargs
278
279
279 class cmdalias(object):
280 class cmdalias(object):
280 def __init__(self, name, definition, cmdtable):
281 def __init__(self, name, definition, cmdtable):
281 self.name = self.cmd = name
282 self.name = self.cmd = name
282 self.cmdname = ''
283 self.cmdname = ''
283 self.definition = definition
284 self.definition = definition
284 self.args = []
285 self.args = []
285 self.opts = []
286 self.opts = []
286 self.help = ''
287 self.help = ''
287 self.norepo = True
288 self.norepo = True
288 self.optionalrepo = False
289 self.optionalrepo = False
289 self.badalias = False
290 self.badalias = False
290
291
291 try:
292 try:
292 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
293 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
293 for alias, e in cmdtable.iteritems():
294 for alias, e in cmdtable.iteritems():
294 if e is entry:
295 if e is entry:
295 self.cmd = alias
296 self.cmd = alias
296 break
297 break
297 self.shadows = True
298 self.shadows = True
298 except error.UnknownCommand:
299 except error.UnknownCommand:
299 self.shadows = False
300 self.shadows = False
300
301
301 if not self.definition:
302 if not self.definition:
302 def fn(ui, *args):
303 def fn(ui, *args):
303 ui.warn(_("no definition for alias '%s'\n") % self.name)
304 ui.warn(_("no definition for alias '%s'\n") % self.name)
304 return 1
305 return 1
305 self.fn = fn
306 self.fn = fn
306 self.badalias = True
307 self.badalias = True
307 return
308 return
308
309
309 if self.definition.startswith('!'):
310 if self.definition.startswith('!'):
310 self.shell = True
311 self.shell = True
311 def fn(ui, *args):
312 def fn(ui, *args):
312 env = {'HG_ARGS': ' '.join((self.name,) + args)}
313 env = {'HG_ARGS': ' '.join((self.name,) + args)}
313 def _checkvar(m):
314 def _checkvar(m):
314 if m.groups()[0] == '$':
315 if m.groups()[0] == '$':
315 return m.group()
316 return m.group()
316 elif int(m.groups()[0]) <= len(args):
317 elif int(m.groups()[0]) <= len(args):
317 return m.group()
318 return m.group()
318 else:
319 else:
319 ui.debug("No argument found for substitution "
320 ui.debug("No argument found for substitution "
320 "of %i variable in alias '%s' definition."
321 "of %i variable in alias '%s' definition."
321 % (int(m.groups()[0]), self.name))
322 % (int(m.groups()[0]), self.name))
322 return ''
323 return ''
323 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
324 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
324 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
325 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
325 replace['0'] = self.name
326 replace['0'] = self.name
326 replace['@'] = ' '.join(args)
327 replace['@'] = ' '.join(args)
327 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
328 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
328 return util.system(cmd, environ=env, out=ui.fout)
329 return util.system(cmd, environ=env, out=ui.fout)
329 self.fn = fn
330 self.fn = fn
330 return
331 return
331
332
332 args = shlex.split(self.definition)
333 args = shlex.split(self.definition)
333 self.cmdname = cmd = args.pop(0)
334 self.cmdname = cmd = args.pop(0)
334 args = map(util.expandpath, args)
335 args = map(util.expandpath, args)
335
336
336 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
337 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
337 if _earlygetopt([invalidarg], args):
338 if _earlygetopt([invalidarg], args):
338 def fn(ui, *args):
339 def fn(ui, *args):
339 ui.warn(_("error in definition for alias '%s': %s may only "
340 ui.warn(_("error in definition for alias '%s': %s may only "
340 "be given on the command line\n")
341 "be given on the command line\n")
341 % (self.name, invalidarg))
342 % (self.name, invalidarg))
342 return 1
343 return 1
343
344
344 self.fn = fn
345 self.fn = fn
345 self.badalias = True
346 self.badalias = True
346 return
347 return
347
348
348 try:
349 try:
349 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
350 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
350 if len(tableentry) > 2:
351 if len(tableentry) > 2:
351 self.fn, self.opts, self.help = tableentry
352 self.fn, self.opts, self.help = tableentry
352 else:
353 else:
353 self.fn, self.opts = tableentry
354 self.fn, self.opts = tableentry
354
355
355 self.args = aliasargs(self.fn, args)
356 self.args = aliasargs(self.fn, args)
356 if cmd not in commands.norepo.split(' '):
357 if cmd not in commands.norepo.split(' '):
357 self.norepo = False
358 self.norepo = False
358 if cmd in commands.optionalrepo.split(' '):
359 if cmd in commands.optionalrepo.split(' '):
359 self.optionalrepo = True
360 self.optionalrepo = True
360 if self.help.startswith("hg " + cmd):
361 if self.help.startswith("hg " + cmd):
361 # drop prefix in old-style help lines so hg shows the alias
362 # drop prefix in old-style help lines so hg shows the alias
362 self.help = self.help[4 + len(cmd):]
363 self.help = self.help[4 + len(cmd):]
363 self.__doc__ = self.fn.__doc__
364 self.__doc__ = self.fn.__doc__
364
365
365 except error.UnknownCommand:
366 except error.UnknownCommand:
366 def fn(ui, *args):
367 def fn(ui, *args):
367 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
368 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
368 % (self.name, cmd))
369 % (self.name, cmd))
369 try:
370 try:
370 # check if the command is in a disabled extension
371 # check if the command is in a disabled extension
371 commands.help_(ui, cmd, unknowncmd=True)
372 commands.help_(ui, cmd, unknowncmd=True)
372 except error.UnknownCommand:
373 except error.UnknownCommand:
373 pass
374 pass
374 return 1
375 return 1
375 self.fn = fn
376 self.fn = fn
376 self.badalias = True
377 self.badalias = True
377 except error.AmbiguousCommand:
378 except error.AmbiguousCommand:
378 def fn(ui, *args):
379 def fn(ui, *args):
379 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
380 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
380 % (self.name, cmd))
381 % (self.name, cmd))
381 return 1
382 return 1
382 self.fn = fn
383 self.fn = fn
383 self.badalias = True
384 self.badalias = True
384
385
385 def __call__(self, ui, *args, **opts):
386 def __call__(self, ui, *args, **opts):
386 if self.shadows:
387 if self.shadows:
387 ui.debug("alias '%s' shadows command '%s'\n" %
388 ui.debug("alias '%s' shadows command '%s'\n" %
388 (self.name, self.cmdname))
389 (self.name, self.cmdname))
389
390
390 if util.safehasattr(self, 'shell'):
391 if util.safehasattr(self, 'shell'):
391 return self.fn(ui, *args, **opts)
392 return self.fn(ui, *args, **opts)
392 else:
393 else:
393 try:
394 try:
394 util.checksignature(self.fn)(ui, *args, **opts)
395 util.checksignature(self.fn)(ui, *args, **opts)
395 except error.SignatureError:
396 except error.SignatureError:
396 args = ' '.join([self.cmdname] + self.args)
397 args = ' '.join([self.cmdname] + self.args)
397 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
398 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
398 raise
399 raise
399
400
400 def addaliases(ui, cmdtable):
401 def addaliases(ui, cmdtable):
401 # aliases are processed after extensions have been loaded, so they
402 # aliases are processed after extensions have been loaded, so they
402 # may use extension commands. Aliases can also use other alias definitions,
403 # may use extension commands. Aliases can also use other alias definitions,
403 # but only if they have been defined prior to the current definition.
404 # but only if they have been defined prior to the current definition.
404 for alias, definition in ui.configitems('alias'):
405 for alias, definition in ui.configitems('alias'):
405 aliasdef = cmdalias(alias, definition, cmdtable)
406 aliasdef = cmdalias(alias, definition, cmdtable)
406
407
407 try:
408 try:
408 olddef = cmdtable[aliasdef.cmd][0]
409 olddef = cmdtable[aliasdef.cmd][0]
409 if olddef.definition == aliasdef.definition:
410 if olddef.definition == aliasdef.definition:
410 continue
411 continue
411 except (KeyError, AttributeError):
412 except (KeyError, AttributeError):
412 # definition might not exist or it might not be a cmdalias
413 # definition might not exist or it might not be a cmdalias
413 pass
414 pass
414
415
415 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
416 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
416 if aliasdef.norepo:
417 if aliasdef.norepo:
417 commands.norepo += ' %s' % alias
418 commands.norepo += ' %s' % alias
418 if aliasdef.optionalrepo:
419 if aliasdef.optionalrepo:
419 commands.optionalrepo += ' %s' % alias
420 commands.optionalrepo += ' %s' % alias
420
421
421 def _parse(ui, args):
422 def _parse(ui, args):
422 options = {}
423 options = {}
423 cmdoptions = {}
424 cmdoptions = {}
424
425
425 try:
426 try:
426 args = fancyopts.fancyopts(args, commands.globalopts, options)
427 args = fancyopts.fancyopts(args, commands.globalopts, options)
427 except fancyopts.getopt.GetoptError, inst:
428 except fancyopts.getopt.GetoptError, inst:
428 raise error.CommandError(None, inst)
429 raise error.CommandError(None, inst)
429
430
430 if args:
431 if args:
431 cmd, args = args[0], args[1:]
432 cmd, args = args[0], args[1:]
432 aliases, entry = cmdutil.findcmd(cmd, commands.table,
433 aliases, entry = cmdutil.findcmd(cmd, commands.table,
433 ui.configbool("ui", "strict"))
434 ui.configbool("ui", "strict"))
434 cmd = aliases[0]
435 cmd = aliases[0]
435 args = aliasargs(entry[0], args)
436 args = aliasargs(entry[0], args)
436 defaults = ui.config("defaults", cmd)
437 defaults = ui.config("defaults", cmd)
437 if defaults:
438 if defaults:
438 args = map(util.expandpath, shlex.split(defaults)) + args
439 args = map(util.expandpath, shlex.split(defaults)) + args
439 c = list(entry[1])
440 c = list(entry[1])
440 else:
441 else:
441 cmd = None
442 cmd = None
442 c = []
443 c = []
443
444
444 # combine global options into local
445 # combine global options into local
445 for o in commands.globalopts:
446 for o in commands.globalopts:
446 c.append((o[0], o[1], options[o[1]], o[3]))
447 c.append((o[0], o[1], options[o[1]], o[3]))
447
448
448 try:
449 try:
449 args = fancyopts.fancyopts(args, c, cmdoptions, True)
450 args = fancyopts.fancyopts(args, c, cmdoptions, True)
450 except fancyopts.getopt.GetoptError, inst:
451 except fancyopts.getopt.GetoptError, inst:
451 raise error.CommandError(cmd, inst)
452 raise error.CommandError(cmd, inst)
452
453
453 # separate global options back out
454 # separate global options back out
454 for o in commands.globalopts:
455 for o in commands.globalopts:
455 n = o[1]
456 n = o[1]
456 options[n] = cmdoptions[n]
457 options[n] = cmdoptions[n]
457 del cmdoptions[n]
458 del cmdoptions[n]
458
459
459 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
460 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
460
461
461 def _parseconfig(ui, config):
462 def _parseconfig(ui, config):
462 """parse the --config options from the command line"""
463 """parse the --config options from the command line"""
463 configs = []
464 configs = []
464
465
465 for cfg in config:
466 for cfg in config:
466 try:
467 try:
467 name, value = cfg.split('=', 1)
468 name, value = cfg.split('=', 1)
468 section, name = name.split('.', 1)
469 section, name = name.split('.', 1)
469 if not section or not name:
470 if not section or not name:
470 raise IndexError
471 raise IndexError
471 ui.setconfig(section, name, value)
472 ui.setconfig(section, name, value)
472 configs.append((section, name, value))
473 configs.append((section, name, value))
473 except (IndexError, ValueError):
474 except (IndexError, ValueError):
474 raise util.Abort(_('malformed --config option: %r '
475 raise util.Abort(_('malformed --config option: %r '
475 '(use --config section.name=value)') % cfg)
476 '(use --config section.name=value)') % cfg)
476
477
477 return configs
478 return configs
478
479
479 def _earlygetopt(aliases, args):
480 def _earlygetopt(aliases, args):
480 """Return list of values for an option (or aliases).
481 """Return list of values for an option (or aliases).
481
482
482 The values are listed in the order they appear in args.
483 The values are listed in the order they appear in args.
483 The options and values are removed from args.
484 The options and values are removed from args.
484 """
485 """
485 try:
486 try:
486 argcount = args.index("--")
487 argcount = args.index("--")
487 except ValueError:
488 except ValueError:
488 argcount = len(args)
489 argcount = len(args)
489 shortopts = [opt for opt in aliases if len(opt) == 2]
490 shortopts = [opt for opt in aliases if len(opt) == 2]
490 values = []
491 values = []
491 pos = 0
492 pos = 0
492 while pos < argcount:
493 while pos < argcount:
493 if args[pos] in aliases:
494 if args[pos] in aliases:
494 if pos + 1 >= argcount:
495 if pos + 1 >= argcount:
495 # ignore and let getopt report an error if there is no value
496 # ignore and let getopt report an error if there is no value
496 break
497 break
497 del args[pos]
498 del args[pos]
498 values.append(args.pop(pos))
499 values.append(args.pop(pos))
499 argcount -= 2
500 argcount -= 2
500 elif args[pos][:2] in shortopts:
501 elif args[pos][:2] in shortopts:
501 # short option can have no following space, e.g. hg log -Rfoo
502 # short option can have no following space, e.g. hg log -Rfoo
502 values.append(args.pop(pos)[2:])
503 values.append(args.pop(pos)[2:])
503 argcount -= 1
504 argcount -= 1
504 else:
505 else:
505 pos += 1
506 pos += 1
506 return values
507 return values
507
508
508 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
509 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
509 # run pre-hook, and abort if it fails
510 # run pre-hook, and abort if it fails
510 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
511 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
511 pats=cmdpats, opts=cmdoptions)
512 pats=cmdpats, opts=cmdoptions)
512 if ret:
513 if ret:
513 return ret
514 return ret
514 ret = _runcommand(ui, options, cmd, d)
515 ret = _runcommand(ui, options, cmd, d)
515 # run post-hook, passing command result
516 # run post-hook, passing command result
516 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
517 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
517 result=ret, pats=cmdpats, opts=cmdoptions)
518 result=ret, pats=cmdpats, opts=cmdoptions)
518 return ret
519 return ret
519
520
520 def _getlocal(ui, rpath):
521 def _getlocal(ui, rpath):
521 """Return (path, local ui object) for the given target path.
522 """Return (path, local ui object) for the given target path.
522
523
523 Takes paths in [cwd]/.hg/hgrc into account."
524 Takes paths in [cwd]/.hg/hgrc into account."
524 """
525 """
525 try:
526 try:
526 wd = os.getcwd()
527 wd = os.getcwd()
527 except OSError, e:
528 except OSError, e:
528 raise util.Abort(_("error getting current working directory: %s") %
529 raise util.Abort(_("error getting current working directory: %s") %
529 e.strerror)
530 e.strerror)
530 path = cmdutil.findrepo(wd) or ""
531 path = cmdutil.findrepo(wd) or ""
531 if not path:
532 if not path:
532 lui = ui
533 lui = ui
533 else:
534 else:
534 lui = ui.copy()
535 lui = ui.copy()
535 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
536 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
536
537
537 if rpath and rpath[-1]:
538 if rpath and rpath[-1]:
538 path = lui.expandpath(rpath[-1])
539 path = lui.expandpath(rpath[-1])
539 lui = ui.copy()
540 lui = ui.copy()
540 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
541 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
541
542
542 return path, lui
543 return path, lui
543
544
544 def _checkshellalias(lui, ui, args):
545 def _checkshellalias(lui, ui, args):
545 options = {}
546 options = {}
546
547
547 try:
548 try:
548 args = fancyopts.fancyopts(args, commands.globalopts, options)
549 args = fancyopts.fancyopts(args, commands.globalopts, options)
549 except fancyopts.getopt.GetoptError:
550 except fancyopts.getopt.GetoptError:
550 return
551 return
551
552
552 if not args:
553 if not args:
553 return
554 return
554
555
555 norepo = commands.norepo
556 norepo = commands.norepo
556 optionalrepo = commands.optionalrepo
557 optionalrepo = commands.optionalrepo
557 def restorecommands():
558 def restorecommands():
558 commands.norepo = norepo
559 commands.norepo = norepo
559 commands.optionalrepo = optionalrepo
560 commands.optionalrepo = optionalrepo
560
561
561 cmdtable = commands.table.copy()
562 cmdtable = commands.table.copy()
562 addaliases(lui, cmdtable)
563 addaliases(lui, cmdtable)
563
564
564 cmd = args[0]
565 cmd = args[0]
565 try:
566 try:
566 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
567 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
567 lui.configbool("ui", "strict"))
568 lui.configbool("ui", "strict"))
568 except (error.AmbiguousCommand, error.UnknownCommand):
569 except (error.AmbiguousCommand, error.UnknownCommand):
569 restorecommands()
570 restorecommands()
570 return
571 return
571
572
572 cmd = aliases[0]
573 cmd = aliases[0]
573 fn = entry[0]
574 fn = entry[0]
574
575
575 if cmd and util.safehasattr(fn, 'shell'):
576 if cmd and util.safehasattr(fn, 'shell'):
576 d = lambda: fn(ui, *args[1:])
577 d = lambda: fn(ui, *args[1:])
577 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
578 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
578 [], {})
579 [], {})
579
580
580 restorecommands()
581 restorecommands()
581
582
582 _loaded = set()
583 _loaded = set()
583 def _dispatch(req):
584 def _dispatch(req):
584 args = req.args
585 args = req.args
585 ui = req.ui
586 ui = req.ui
586
587
587 # read --config before doing anything else
588 # read --config before doing anything else
588 # (e.g. to change trust settings for reading .hg/hgrc)
589 # (e.g. to change trust settings for reading .hg/hgrc)
589 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
590 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
590
591
591 # check for cwd
592 # check for cwd
592 cwd = _earlygetopt(['--cwd'], args)
593 cwd = _earlygetopt(['--cwd'], args)
593 if cwd:
594 if cwd:
594 os.chdir(cwd[-1])
595 os.chdir(cwd[-1])
595
596
596 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
597 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
597 path, lui = _getlocal(ui, rpath)
598 path, lui = _getlocal(ui, rpath)
598
599
599 # Now that we're operating in the right directory/repository with
600 # Now that we're operating in the right directory/repository with
600 # the right config settings, check for shell aliases
601 # the right config settings, check for shell aliases
601 shellaliasfn = _checkshellalias(lui, ui, args)
602 shellaliasfn = _checkshellalias(lui, ui, args)
602 if shellaliasfn:
603 if shellaliasfn:
603 return shellaliasfn()
604 return shellaliasfn()
604
605
605 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
606 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
606 # reposetup. Programs like TortoiseHg will call _dispatch several
607 # reposetup. Programs like TortoiseHg will call _dispatch several
607 # times so we keep track of configured extensions in _loaded.
608 # times so we keep track of configured extensions in _loaded.
608 extensions.loadall(lui)
609 extensions.loadall(lui)
609 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
610 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
610 # Propagate any changes to lui.__class__ by extensions
611 # Propagate any changes to lui.__class__ by extensions
611 ui.__class__ = lui.__class__
612 ui.__class__ = lui.__class__
612
613
613 # (uisetup and extsetup are handled in extensions.loadall)
614 # (uisetup and extsetup are handled in extensions.loadall)
614
615
615 for name, module in exts:
616 for name, module in exts:
616 cmdtable = getattr(module, 'cmdtable', {})
617 cmdtable = getattr(module, 'cmdtable', {})
617 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
618 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
618 if overrides:
619 if overrides:
619 ui.warn(_("extension '%s' overrides commands: %s\n")
620 ui.warn(_("extension '%s' overrides commands: %s\n")
620 % (name, " ".join(overrides)))
621 % (name, " ".join(overrides)))
621 commands.table.update(cmdtable)
622 commands.table.update(cmdtable)
622 _loaded.add(name)
623 _loaded.add(name)
623
624
624 # (reposetup is handled in hg.repository)
625 # (reposetup is handled in hg.repository)
625
626
626 addaliases(lui, commands.table)
627 addaliases(lui, commands.table)
627
628
628 # check for fallback encoding
629 # check for fallback encoding
629 fallback = lui.config('ui', 'fallbackencoding')
630 fallback = lui.config('ui', 'fallbackencoding')
630 if fallback:
631 if fallback:
631 encoding.fallbackencoding = fallback
632 encoding.fallbackencoding = fallback
632
633
633 fullargs = args
634 fullargs = args
634 cmd, func, args, options, cmdoptions = _parse(lui, args)
635 cmd, func, args, options, cmdoptions = _parse(lui, args)
635
636
636 if options["config"]:
637 if options["config"]:
637 raise util.Abort(_("option --config may not be abbreviated!"))
638 raise util.Abort(_("option --config may not be abbreviated!"))
638 if options["cwd"]:
639 if options["cwd"]:
639 raise util.Abort(_("option --cwd may not be abbreviated!"))
640 raise util.Abort(_("option --cwd may not be abbreviated!"))
640 if options["repository"]:
641 if options["repository"]:
641 raise util.Abort(_(
642 raise util.Abort(_(
642 "option -R has to be separated from other options (e.g. not -qR) "
643 "option -R has to be separated from other options (e.g. not -qR) "
643 "and --repository may only be abbreviated as --repo!"))
644 "and --repository may only be abbreviated as --repo!"))
644
645
645 if options["encoding"]:
646 if options["encoding"]:
646 encoding.encoding = options["encoding"]
647 encoding.encoding = options["encoding"]
647 if options["encodingmode"]:
648 if options["encodingmode"]:
648 encoding.encodingmode = options["encodingmode"]
649 encoding.encodingmode = options["encodingmode"]
649 if options["time"]:
650 if options["time"]:
650 def get_times():
651 def get_times():
651 t = os.times()
652 t = os.times()
652 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
653 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
653 t = (t[0], t[1], t[2], t[3], time.clock())
654 t = (t[0], t[1], t[2], t[3], time.clock())
654 return t
655 return t
655 s = get_times()
656 s = get_times()
656 def print_time():
657 def print_time():
657 t = get_times()
658 t = get_times()
658 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
659 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
659 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
660 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
660 atexit.register(print_time)
661 atexit.register(print_time)
661
662
662 uis = set([ui, lui])
663 uis = set([ui, lui])
663
664
664 if req.repo:
665 if req.repo:
665 uis.add(req.repo.ui)
666 uis.add(req.repo.ui)
666
667
667 # copy configs that were passed on the cmdline (--config) to the repo ui
668 # copy configs that were passed on the cmdline (--config) to the repo ui
668 for cfg in cfgs:
669 for cfg in cfgs:
669 req.repo.ui.setconfig(*cfg)
670 req.repo.ui.setconfig(*cfg)
670
671
671 if options['verbose'] or options['debug'] or options['quiet']:
672 if options['verbose'] or options['debug'] or options['quiet']:
672 for opt in ('verbose', 'debug', 'quiet'):
673 for opt in ('verbose', 'debug', 'quiet'):
673 val = str(bool(options[opt]))
674 val = str(bool(options[opt]))
674 for ui_ in uis:
675 for ui_ in uis:
675 ui_.setconfig('ui', opt, val)
676 ui_.setconfig('ui', opt, val)
676
677
677 if options['traceback']:
678 if options['traceback']:
678 for ui_ in uis:
679 for ui_ in uis:
679 ui_.setconfig('ui', 'traceback', 'on')
680 ui_.setconfig('ui', 'traceback', 'on')
680
681
681 if options['noninteractive']:
682 if options['noninteractive']:
682 for ui_ in uis:
683 for ui_ in uis:
683 ui_.setconfig('ui', 'interactive', 'off')
684 ui_.setconfig('ui', 'interactive', 'off')
684
685
685 if cmdoptions.get('insecure', False):
686 if cmdoptions.get('insecure', False):
686 for ui_ in uis:
687 for ui_ in uis:
687 ui_.setconfig('web', 'cacerts', '')
688 ui_.setconfig('web', 'cacerts', '')
688
689
689 if options['version']:
690 if options['version']:
690 return commands.version_(ui)
691 return commands.version_(ui)
691 if options['help']:
692 if options['help']:
692 return commands.help_(ui, cmd)
693 return commands.help_(ui, cmd)
693 elif not cmd:
694 elif not cmd:
694 return commands.help_(ui, 'shortlist')
695 return commands.help_(ui, 'shortlist')
695
696
696 repo = None
697 repo = None
697 cmdpats = args[:]
698 cmdpats = args[:]
698 if cmd not in commands.norepo.split():
699 if cmd not in commands.norepo.split():
699 # use the repo from the request only if we don't have -R
700 # use the repo from the request only if we don't have -R
700 if not rpath and not cwd:
701 if not rpath and not cwd:
701 repo = req.repo
702 repo = req.repo
702
703
703 if repo:
704 if repo:
704 # set the descriptors of the repo ui to those of ui
705 # set the descriptors of the repo ui to those of ui
705 repo.ui.fin = ui.fin
706 repo.ui.fin = ui.fin
706 repo.ui.fout = ui.fout
707 repo.ui.fout = ui.fout
707 repo.ui.ferr = ui.ferr
708 repo.ui.ferr = ui.ferr
708 else:
709 else:
709 try:
710 try:
710 repo = hg.repository(ui, path=path)
711 repo = hg.repository(ui, path=path)
711 if not repo.local():
712 if not repo.local():
712 raise util.Abort(_("repository '%s' is not local") % path)
713 raise util.Abort(_("repository '%s' is not local") % path)
713 if options['hidden']:
714 if options['hidden']:
714 repo = repo.unfiltered()
715 repo = repo.unfiltered()
715 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
716 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
716 except error.RequirementError:
717 except error.RequirementError:
717 raise
718 raise
718 except error.RepoError:
719 except error.RepoError:
719 if cmd not in commands.optionalrepo.split():
720 if cmd not in commands.optionalrepo.split():
720 if (cmd in commands.inferrepo.split() and
721 if (cmd in commands.inferrepo.split() and
721 args and not path): # try to infer -R from command args
722 args and not path): # try to infer -R from command args
722 repos = map(cmdutil.findrepo, args)
723 repos = map(cmdutil.findrepo, args)
723 guess = repos[0]
724 guess = repos[0]
724 if guess and repos.count(guess) == len(repos):
725 if guess and repos.count(guess) == len(repos):
725 req.args = ['--repository', guess] + fullargs
726 req.args = ['--repository', guess] + fullargs
726 return _dispatch(req)
727 return _dispatch(req)
727 if not path:
728 if not path:
728 raise error.RepoError(_("no repository found in '%s'"
729 raise error.RepoError(_("no repository found in '%s'"
729 " (.hg not found)")
730 " (.hg not found)")
730 % os.getcwd())
731 % os.getcwd())
731 raise
732 raise
732 if repo:
733 if repo:
733 ui = repo.ui
734 ui = repo.ui
734 args.insert(0, repo)
735 args.insert(0, repo)
735 elif rpath:
736 elif rpath:
736 ui.warn(_("warning: --repository ignored\n"))
737 ui.warn(_("warning: --repository ignored\n"))
737
738
738 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
739 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
739 ui.log("command", msg + "\n")
740 ui.log("command", msg + "\n")
740 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
741 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
742 starttime = time.time()
743 ret = None
741 try:
744 try:
742 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
745 ret = runcommand(lui, repo, cmd, fullargs, ui, options, d,
743 cmdpats, cmdoptions)
746 cmdpats, cmdoptions)
747 return ret
744 finally:
748 finally:
749 duration = time.time() - starttime
750 ui.log("commandfinish", _("%s exited %s after %0.2f seconds\n"),
751 cmd, ret, duration)
745 if repo and repo != req.repo:
752 if repo and repo != req.repo:
746 repo.close()
753 repo.close()
747
754
748 def lsprofile(ui, func, fp):
755 def lsprofile(ui, func, fp):
749 format = ui.config('profiling', 'format', default='text')
756 format = ui.config('profiling', 'format', default='text')
750 field = ui.config('profiling', 'sort', default='inlinetime')
757 field = ui.config('profiling', 'sort', default='inlinetime')
751 limit = ui.configint('profiling', 'limit', default=30)
758 limit = ui.configint('profiling', 'limit', default=30)
752 climit = ui.configint('profiling', 'nested', default=5)
759 climit = ui.configint('profiling', 'nested', default=5)
753
760
754 if format not in ['text', 'kcachegrind']:
761 if format not in ['text', 'kcachegrind']:
755 ui.warn(_("unrecognized profiling format '%s'"
762 ui.warn(_("unrecognized profiling format '%s'"
756 " - Ignored\n") % format)
763 " - Ignored\n") % format)
757 format = 'text'
764 format = 'text'
758
765
759 try:
766 try:
760 from mercurial import lsprof
767 from mercurial import lsprof
761 except ImportError:
768 except ImportError:
762 raise util.Abort(_(
769 raise util.Abort(_(
763 'lsprof not available - install from '
770 'lsprof not available - install from '
764 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
771 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
765 p = lsprof.Profiler()
772 p = lsprof.Profiler()
766 p.enable(subcalls=True)
773 p.enable(subcalls=True)
767 try:
774 try:
768 return func()
775 return func()
769 finally:
776 finally:
770 p.disable()
777 p.disable()
771
778
772 if format == 'kcachegrind':
779 if format == 'kcachegrind':
773 import lsprofcalltree
780 import lsprofcalltree
774 calltree = lsprofcalltree.KCacheGrind(p)
781 calltree = lsprofcalltree.KCacheGrind(p)
775 calltree.output(fp)
782 calltree.output(fp)
776 else:
783 else:
777 # format == 'text'
784 # format == 'text'
778 stats = lsprof.Stats(p.getstats())
785 stats = lsprof.Stats(p.getstats())
779 stats.sort(field)
786 stats.sort(field)
780 stats.pprint(limit=limit, file=fp, climit=climit)
787 stats.pprint(limit=limit, file=fp, climit=climit)
781
788
782 def statprofile(ui, func, fp):
789 def statprofile(ui, func, fp):
783 try:
790 try:
784 import statprof
791 import statprof
785 except ImportError:
792 except ImportError:
786 raise util.Abort(_(
793 raise util.Abort(_(
787 'statprof not available - install using "easy_install statprof"'))
794 'statprof not available - install using "easy_install statprof"'))
788
795
789 freq = ui.configint('profiling', 'freq', default=1000)
796 freq = ui.configint('profiling', 'freq', default=1000)
790 if freq > 0:
797 if freq > 0:
791 statprof.reset(freq)
798 statprof.reset(freq)
792 else:
799 else:
793 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
800 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
794
801
795 statprof.start()
802 statprof.start()
796 try:
803 try:
797 return func()
804 return func()
798 finally:
805 finally:
799 statprof.stop()
806 statprof.stop()
800 statprof.display(fp)
807 statprof.display(fp)
801
808
802 def _runcommand(ui, options, cmd, cmdfunc):
809 def _runcommand(ui, options, cmd, cmdfunc):
803 def checkargs():
810 def checkargs():
804 try:
811 try:
805 return cmdfunc()
812 return cmdfunc()
806 except error.SignatureError:
813 except error.SignatureError:
807 raise error.CommandError(cmd, _("invalid arguments"))
814 raise error.CommandError(cmd, _("invalid arguments"))
808
815
809 if options['profile']:
816 if options['profile']:
810 profiler = os.getenv('HGPROF')
817 profiler = os.getenv('HGPROF')
811 if profiler is None:
818 if profiler is None:
812 profiler = ui.config('profiling', 'type', default='ls')
819 profiler = ui.config('profiling', 'type', default='ls')
813 if profiler not in ('ls', 'stat'):
820 if profiler not in ('ls', 'stat'):
814 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
821 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
815 profiler = 'ls'
822 profiler = 'ls'
816
823
817 output = ui.config('profiling', 'output')
824 output = ui.config('profiling', 'output')
818
825
819 if output:
826 if output:
820 path = ui.expandpath(output)
827 path = ui.expandpath(output)
821 fp = open(path, 'wb')
828 fp = open(path, 'wb')
822 else:
829 else:
823 fp = sys.stderr
830 fp = sys.stderr
824
831
825 try:
832 try:
826 if profiler == 'ls':
833 if profiler == 'ls':
827 return lsprofile(ui, checkargs, fp)
834 return lsprofile(ui, checkargs, fp)
828 else:
835 else:
829 return statprofile(ui, checkargs, fp)
836 return statprofile(ui, checkargs, fp)
830 finally:
837 finally:
831 if output:
838 if output:
832 fp.close()
839 fp.close()
833 else:
840 else:
834 return checkargs()
841 return checkargs()
@@ -1,208 +1,210
1
1
2 $ cat > loop.py <<EOF
2 $ cat > loop.py <<EOF
3 > from mercurial import commands
3 > from mercurial import commands
4 >
4 >
5 > def loop(ui, loops, **opts):
5 > def loop(ui, loops, **opts):
6 > loops = int(loops)
6 > loops = int(loops)
7 > total = None
7 > total = None
8 > if loops >= 0:
8 > if loops >= 0:
9 > total = loops
9 > total = loops
10 > if opts.get('total', None):
10 > if opts.get('total', None):
11 > total = int(opts.get('total'))
11 > total = int(opts.get('total'))
12 > nested = False
12 > nested = False
13 > if opts.get('nested', None):
13 > if opts.get('nested', None):
14 > nested = True
14 > nested = True
15 > loops = abs(loops)
15 > loops = abs(loops)
16 >
16 >
17 > for i in range(loops):
17 > for i in range(loops):
18 > ui.progress('loop', i, 'loop.%d' % i, 'loopnum', total)
18 > ui.progress('loop', i, 'loop.%d' % i, 'loopnum', total)
19 > if opts.get('parallel'):
19 > if opts.get('parallel'):
20 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
20 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
21 > if nested:
21 > if nested:
22 > for j in range(2):
22 > for j in range(2):
23 > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
23 > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
24 > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
24 > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
25 > ui.progress('loop', None, 'loop.done', 'loopnum', total)
25 > ui.progress('loop', None, 'loop.done', 'loopnum', total)
26 >
26 >
27 > commands.norepo += " loop"
27 > commands.norepo += " loop"
28 >
28 >
29 > cmdtable = {
29 > cmdtable = {
30 > "loop": (loop, [('', 'total', '', 'override for total'),
30 > "loop": (loop, [('', 'total', '', 'override for total'),
31 > ('', 'nested', False, 'show nested results'),
31 > ('', 'nested', False, 'show nested results'),
32 > ('', 'parallel', False, 'show parallel sets of results'),
32 > ('', 'parallel', False, 'show parallel sets of results'),
33 > ],
33 > ],
34 > 'hg loop LOOPS'),
34 > 'hg loop LOOPS'),
35 > }
35 > }
36 > EOF
36 > EOF
37
37
38 $ cp $HGRCPATH $HGRCPATH.orig
38 $ cp $HGRCPATH $HGRCPATH.orig
39 $ echo "[extensions]" >> $HGRCPATH
39 $ echo "[extensions]" >> $HGRCPATH
40 $ echo "progress=" >> $HGRCPATH
40 $ echo "progress=" >> $HGRCPATH
41 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
41 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
42 $ echo "[progress]" >> $HGRCPATH
42 $ echo "[progress]" >> $HGRCPATH
43 $ echo "format = topic bar number" >> $HGRCPATH
43 $ echo "format = topic bar number" >> $HGRCPATH
44 $ echo "assume-tty=1" >> $HGRCPATH
44 $ echo "assume-tty=1" >> $HGRCPATH
45 $ echo "width=60" >> $HGRCPATH
45 $ echo "width=60" >> $HGRCPATH
46
46
47 test default params, display nothing because of delay
47 test default params, display nothing because of delay
48
48
49 $ hg -y loop 3
49 $ hg -y loop 3
50 $ echo "delay=0" >> $HGRCPATH
50 $ echo "delay=0" >> $HGRCPATH
51 $ echo "refresh=0" >> $HGRCPATH
51 $ echo "refresh=0" >> $HGRCPATH
52
52
53 test with delay=0, refresh=0
53 test with delay=0, refresh=0
54
54
55 $ hg -y loop 3
55 $ hg -y loop 3
56 \r (no-eol) (esc)
56 \r (no-eol) (esc)
57 loop [ ] 0/3\r (no-eol) (esc)
57 loop [ ] 0/3\r (no-eol) (esc)
58 loop [===============> ] 1/3\r (no-eol) (esc)
58 loop [===============> ] 1/3\r (no-eol) (esc)
59 loop [===============================> ] 2/3\r (no-eol) (esc)
59 loop [===============================> ] 2/3\r (no-eol) (esc)
60 \r (no-eol) (esc)
60 \r (no-eol) (esc)
61
61
62
62
63 test nested short-lived topics (which shouldn't display with nestdelay):
63 test nested short-lived topics (which shouldn't display with nestdelay):
64
64
65 $ hg -y loop 3 --nested
65 $ hg -y loop 3 --nested
66 \r (no-eol) (esc)
66 \r (no-eol) (esc)
67 loop [ ] 0/3\r (no-eol) (esc)
67 loop [ ] 0/3\r (no-eol) (esc)
68 loop [===============> ] 1/3\r (no-eol) (esc)
68 loop [===============> ] 1/3\r (no-eol) (esc)
69 loop [===============================> ] 2/3\r (no-eol) (esc)
69 loop [===============================> ] 2/3\r (no-eol) (esc)
70 \r (no-eol) (esc)
70 \r (no-eol) (esc)
71
71
72
72
73 $ hg --config progress.changedelay=0 -y loop 3 --nested
73 $ hg --config progress.changedelay=0 -y loop 3 --nested
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 nested [ ] 0/2\r (no-eol) (esc)
76 nested [ ] 0/2\r (no-eol) (esc)
77 nested [======================> ] 1/2\r (no-eol) (esc)
77 nested [======================> ] 1/2\r (no-eol) (esc)
78 loop [===============> ] 1/3\r (no-eol) (esc)
78 loop [===============> ] 1/3\r (no-eol) (esc)
79 nested [ ] 0/2\r (no-eol) (esc)
79 nested [ ] 0/2\r (no-eol) (esc)
80 nested [======================> ] 1/2\r (no-eol) (esc)
80 nested [======================> ] 1/2\r (no-eol) (esc)
81 loop [===============================> ] 2/3\r (no-eol) (esc)
81 loop [===============================> ] 2/3\r (no-eol) (esc)
82 nested [ ] 0/2\r (no-eol) (esc)
82 nested [ ] 0/2\r (no-eol) (esc)
83 nested [======================> ] 1/2\r (no-eol) (esc)
83 nested [======================> ] 1/2\r (no-eol) (esc)
84 \r (no-eol) (esc)
84 \r (no-eol) (esc)
85
85
86
86
87 test two topics being printed in parallel (as when we're doing a local
87 test two topics being printed in parallel (as when we're doing a local
88 --pull clone, where you get the unbundle and bundle progress at the
88 --pull clone, where you get the unbundle and bundle progress at the
89 same time):
89 same time):
90 $ hg loop 3 --parallel
90 $ hg loop 3 --parallel
91 \r (no-eol) (esc)
91 \r (no-eol) (esc)
92 loop [ ] 0/3\r (no-eol) (esc)
92 loop [ ] 0/3\r (no-eol) (esc)
93 loop [===============> ] 1/3\r (no-eol) (esc)
93 loop [===============> ] 1/3\r (no-eol) (esc)
94 loop [===============================> ] 2/3\r (no-eol) (esc)
94 loop [===============================> ] 2/3\r (no-eol) (esc)
95 \r (no-eol) (esc)
95 \r (no-eol) (esc)
96 test refresh is taken in account
96 test refresh is taken in account
97
97
98 $ hg -y --config progress.refresh=100 loop 3
98 $ hg -y --config progress.refresh=100 loop 3
99
99
100 test format options 1
100 test format options 1
101
101
102 $ hg -y --config 'progress.format=number topic item+2' loop 2
102 $ hg -y --config 'progress.format=number topic item+2' loop 2
103 \r (no-eol) (esc)
103 \r (no-eol) (esc)
104 0/2 loop lo\r (no-eol) (esc)
104 0/2 loop lo\r (no-eol) (esc)
105 1/2 loop lo\r (no-eol) (esc)
105 1/2 loop lo\r (no-eol) (esc)
106 \r (no-eol) (esc)
106 \r (no-eol) (esc)
107
107
108 test format options 2
108 test format options 2
109
109
110 $ hg -y --config 'progress.format=number item-3 bar' loop 2
110 $ hg -y --config 'progress.format=number item-3 bar' loop 2
111 \r (no-eol) (esc)
111 \r (no-eol) (esc)
112 0/2 p.0 [ ]\r (no-eol) (esc)
112 0/2 p.0 [ ]\r (no-eol) (esc)
113 1/2 p.1 [=======================> ]\r (no-eol) (esc)
113 1/2 p.1 [=======================> ]\r (no-eol) (esc)
114 \r (no-eol) (esc)
114 \r (no-eol) (esc)
115
115
116 test format options and indeterminate progress
116 test format options and indeterminate progress
117
117
118 $ hg -y --config 'progress.format=number item bar' loop -- -2
118 $ hg -y --config 'progress.format=number item bar' loop -- -2
119 \r (no-eol) (esc)
119 \r (no-eol) (esc)
120 0 loop.0 [ <=> ]\r (no-eol) (esc)
120 0 loop.0 [ <=> ]\r (no-eol) (esc)
121 1 loop.1 [ <=> ]\r (no-eol) (esc)
121 1 loop.1 [ <=> ]\r (no-eol) (esc)
122 \r (no-eol) (esc)
122 \r (no-eol) (esc)
123
123
124 make sure things don't fall over if count > total
124 make sure things don't fall over if count > total
125
125
126 $ hg -y loop --total 4 6
126 $ hg -y loop --total 4 6
127 \r (no-eol) (esc)
127 \r (no-eol) (esc)
128 loop [ ] 0/4\r (no-eol) (esc)
128 loop [ ] 0/4\r (no-eol) (esc)
129 loop [===========> ] 1/4\r (no-eol) (esc)
129 loop [===========> ] 1/4\r (no-eol) (esc)
130 loop [=======================> ] 2/4\r (no-eol) (esc)
130 loop [=======================> ] 2/4\r (no-eol) (esc)
131 loop [===================================> ] 3/4\r (no-eol) (esc)
131 loop [===================================> ] 3/4\r (no-eol) (esc)
132 loop [===============================================>] 4/4\r (no-eol) (esc)
132 loop [===============================================>] 4/4\r (no-eol) (esc)
133 loop [ <=> ] 5/4\r (no-eol) (esc)
133 loop [ <=> ] 5/4\r (no-eol) (esc)
134 \r (no-eol) (esc)
134 \r (no-eol) (esc)
135
135
136 test immediate progress completion
136 test immediate progress completion
137
137
138 $ hg -y loop 0
138 $ hg -y loop 0
139
139
140 test delay time estimates
140 test delay time estimates
141
141
142 $ cat > mocktime.py <<EOF
142 $ cat > mocktime.py <<EOF
143 > import os
143 > import os
144 > import time
144 > import time
145 >
145 >
146 > class mocktime(object):
146 > class mocktime(object):
147 > def __init__(self, increment):
147 > def __init__(self, increment):
148 > self.time = 0
148 > self.time = 0
149 > self.increment = increment
149 > self.increment = increment
150 > def __call__(self):
150 > def __call__(self):
151 > self.time += self.increment
151 > self.time += self.increment
152 > return self.time
152 > return self.time
153 >
153 >
154 > def uisetup(ui):
154 > def uisetup(ui):
155 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
155 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
156 > EOF
156 > EOF
157
157
158 $ cp $HGRCPATH.orig $HGRCPATH
158 $ cp $HGRCPATH.orig $HGRCPATH
159 $ echo "[extensions]" >> $HGRCPATH
159 $ echo "[extensions]" >> $HGRCPATH
160 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
160 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
161 $ echo "progress=" >> $HGRCPATH
161 $ echo "progress=" >> $HGRCPATH
162 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
162 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
163 $ echo "[progress]" >> $HGRCPATH
163 $ echo "[progress]" >> $HGRCPATH
164 $ echo "assume-tty=1" >> $HGRCPATH
164 $ echo "assume-tty=1" >> $HGRCPATH
165 $ echo "delay=25" >> $HGRCPATH
165 $ echo "delay=25" >> $HGRCPATH
166 $ echo "width=60" >> $HGRCPATH
166 $ echo "width=60" >> $HGRCPATH
167
167
168 $ hg -y loop 8
168 $ hg -y loop 8
169 \r (no-eol) (esc)
169 \r (no-eol) (esc)
170 loop [====> ] 1/8 1m18s\r (no-eol) (esc)
170 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
171 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
171 loop [===============> ] 3/8 56s\r (no-eol) (esc)
172 loop [===============> ] 3/8 56s\r (no-eol) (esc)
172 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
173 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
173 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
174 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
174 loop [================================> ] 6/8 23s\r (no-eol) (esc)
175 loop [================================> ] 6/8 23s\r (no-eol) (esc)
175 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
176 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
176 \r (no-eol) (esc)
177 \r (no-eol) (esc)
177
178
178 $ MOCKTIME=10000 hg -y loop 4
179 $ MOCKTIME=10000 hg -y loop 4
179 \r (no-eol) (esc)
180 \r (no-eol) (esc)
180 loop [ ] 0/4\r (no-eol) (esc)
181 loop [ ] 0/4\r (no-eol) (esc)
181 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
182 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
182 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
183 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
183 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
184 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
184 \r (no-eol) (esc)
185 \r (no-eol) (esc)
185
186
186 $ MOCKTIME=1000000 hg -y loop 4
187 $ MOCKTIME=1000000 hg -y loop 4
187 \r (no-eol) (esc)
188 \r (no-eol) (esc)
188 loop [ ] 0/4\r (no-eol) (esc)
189 loop [ ] 0/4\r (no-eol) (esc)
189 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
190 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
190 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
191 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
191 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
192 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
192 \r (no-eol) (esc)
193 \r (no-eol) (esc)
193
194
194
195
195 $ MOCKTIME=14000000 hg -y loop 4
196 $ MOCKTIME=14000000 hg -y loop 4
196 \r (no-eol) (esc)
197 \r (no-eol) (esc)
197 loop [ ] 0/4\r (no-eol) (esc)
198 loop [ ] 0/4\r (no-eol) (esc)
198 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
199 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
199 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
200 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
200 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
201 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
201 \r (no-eol) (esc)
202 \r (no-eol) (esc)
202
203
203 Time estimates should not fail when there's no end point:
204 Time estimates should not fail when there's no end point:
204 $ hg -y loop -- -4
205 $ hg -y loop -- -4
205 \r (no-eol) (esc)
206 \r (no-eol) (esc)
206 loop [ <=> ] 2\r (no-eol) (esc)
207 loop [ <=> ] 1\r (no-eol) (esc)
207 loop [ <=> ] 3\r (no-eol) (esc)
208 loop [ <=> ] 2\r (no-eol) (esc)
209 loop [ <=> ] 3\r (no-eol) (esc)
208 \r (no-eol) (esc)
210 \r (no-eol) (esc)
General Comments 0
You need to be logged in to leave comments. Login now