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