##// END OF EJS Templates
alias: abort on missing positional args (issue3331)
Matt Mackall -
r16294:795d591b stable
parent child Browse files
Show More
@@ -1,739 +1,739 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, ferr=None):
16 16 self.args = args
17 17 self.ui = ui
18 18 self.repo = repo
19 19
20 20 # input/output/error streams
21 21 self.fin = fin
22 22 self.fout = fout
23 23 self.ferr = ferr
24 24
25 25 def run():
26 26 "run the command in sys.argv"
27 27 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
28 28
29 29 def dispatch(req):
30 30 "run the command specified in req.args"
31 31 if req.ferr:
32 32 ferr = req.ferr
33 33 elif req.ui:
34 34 ferr = req.ui.ferr
35 35 else:
36 36 ferr = sys.stderr
37 37
38 38 try:
39 39 if not req.ui:
40 40 req.ui = uimod.ui()
41 41 if '--traceback' in req.args:
42 42 req.ui.setconfig('ui', 'traceback', 'on')
43 43
44 44 # set ui streams from the request
45 45 if req.fin:
46 46 req.ui.fin = req.fin
47 47 if req.fout:
48 48 req.ui.fout = req.fout
49 49 if req.ferr:
50 50 req.ui.ferr = req.ferr
51 51 except util.Abort, inst:
52 52 ferr.write(_("abort: %s\n") % inst)
53 53 if inst.hint:
54 54 ferr.write(_("(%s)\n") % inst.hint)
55 55 return -1
56 56 except error.ParseError, inst:
57 57 if len(inst.args) > 1:
58 58 ferr.write(_("hg: parse error at %s: %s\n") %
59 59 (inst.args[1], inst.args[0]))
60 60 else:
61 61 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 62 return -1
63 63
64 64 return _runcatch(req)
65 65
66 66 def _runcatch(req):
67 67 def catchterm(*args):
68 68 raise error.SignalInterrupt
69 69
70 70 ui = req.ui
71 71 try:
72 72 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
73 73 num = getattr(signal, name, None)
74 74 if num:
75 75 signal.signal(num, catchterm)
76 76 except ValueError:
77 77 pass # happens if called in a thread
78 78
79 79 try:
80 80 try:
81 81 # enter the debugger before command execution
82 82 if '--debugger' in req.args:
83 83 ui.warn(_("entering debugger - "
84 84 "type c to continue starting hg or h for help\n"))
85 85 pdb.set_trace()
86 86 try:
87 87 return _dispatch(req)
88 88 finally:
89 89 ui.flush()
90 90 except:
91 91 # enter the debugger when we hit an exception
92 92 if '--debugger' in req.args:
93 93 traceback.print_exc()
94 94 pdb.post_mortem(sys.exc_info()[2])
95 95 ui.traceback()
96 96 raise
97 97
98 98 # Global exception handling, alphabetically
99 99 # Mercurial-specific first, followed by built-in and library exceptions
100 100 except error.AmbiguousCommand, inst:
101 101 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
102 102 (inst.args[0], " ".join(inst.args[1])))
103 103 except error.ParseError, inst:
104 104 if len(inst.args) > 1:
105 105 ui.warn(_("hg: parse error at %s: %s\n") %
106 106 (inst.args[1], inst.args[0]))
107 107 else:
108 108 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
109 109 return -1
110 110 except error.LockHeld, inst:
111 111 if inst.errno == errno.ETIMEDOUT:
112 112 reason = _('timed out waiting for lock held by %s') % inst.locker
113 113 else:
114 114 reason = _('lock held by %s') % inst.locker
115 115 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
116 116 except error.LockUnavailable, inst:
117 117 ui.warn(_("abort: could not lock %s: %s\n") %
118 118 (inst.desc or inst.filename, inst.strerror))
119 119 except error.CommandError, inst:
120 120 if inst.args[0]:
121 121 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
122 122 commands.help_(ui, inst.args[0], full=False, command=True)
123 123 else:
124 124 ui.warn(_("hg: %s\n") % inst.args[1])
125 125 commands.help_(ui, 'shortlist')
126 126 except error.OutOfBandError, inst:
127 127 ui.warn(_("abort: remote error:\n"))
128 128 ui.warn(''.join(inst.args))
129 129 except error.RepoError, inst:
130 130 ui.warn(_("abort: %s!\n") % inst)
131 131 if inst.hint:
132 132 ui.warn(_("(%s)\n") % inst.hint)
133 133 except error.ResponseError, inst:
134 134 ui.warn(_("abort: %s") % inst.args[0])
135 135 if not isinstance(inst.args[1], basestring):
136 136 ui.warn(" %r\n" % (inst.args[1],))
137 137 elif not inst.args[1]:
138 138 ui.warn(_(" empty string\n"))
139 139 else:
140 140 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
141 141 except error.RevlogError, inst:
142 142 ui.warn(_("abort: %s!\n") % inst)
143 143 except error.SignalInterrupt:
144 144 ui.warn(_("killed!\n"))
145 145 except error.UnknownCommand, inst:
146 146 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
147 147 try:
148 148 # check if the command is in a disabled extension
149 149 # (but don't check for extensions themselves)
150 150 commands.help_(ui, inst.args[0], unknowncmd=True)
151 151 except error.UnknownCommand:
152 152 commands.help_(ui, 'shortlist')
153 153 except util.Abort, inst:
154 154 ui.warn(_("abort: %s\n") % inst)
155 155 if inst.hint:
156 156 ui.warn(_("(%s)\n") % inst.hint)
157 157 except ImportError, inst:
158 158 ui.warn(_("abort: %s!\n") % inst)
159 159 m = str(inst).split()[-1]
160 160 if m in "mpatch bdiff".split():
161 161 ui.warn(_("(did you forget to compile extensions?)\n"))
162 162 elif m in "zlib".split():
163 163 ui.warn(_("(is your Python install correct?)\n"))
164 164 except IOError, inst:
165 165 if util.safehasattr(inst, "code"):
166 166 ui.warn(_("abort: %s\n") % inst)
167 167 elif util.safehasattr(inst, "reason"):
168 168 try: # usually it is in the form (errno, strerror)
169 169 reason = inst.reason.args[1]
170 170 except (AttributeError, IndexError):
171 171 # it might be anything, for example a string
172 172 reason = inst.reason
173 173 ui.warn(_("abort: error: %s\n") % reason)
174 174 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
175 175 if ui.debugflag:
176 176 ui.warn(_("broken pipe\n"))
177 177 elif getattr(inst, "strerror", None):
178 178 if getattr(inst, "filename", None):
179 179 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
180 180 else:
181 181 ui.warn(_("abort: %s\n") % inst.strerror)
182 182 else:
183 183 raise
184 184 except OSError, inst:
185 185 if getattr(inst, "filename", None):
186 186 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
187 187 else:
188 188 ui.warn(_("abort: %s\n") % inst.strerror)
189 189 except KeyboardInterrupt:
190 190 try:
191 191 ui.warn(_("interrupted!\n"))
192 192 except IOError, inst:
193 193 if inst.errno == errno.EPIPE:
194 194 if ui.debugflag:
195 195 ui.warn(_("\nbroken pipe\n"))
196 196 else:
197 197 raise
198 198 except MemoryError:
199 199 ui.warn(_("abort: out of memory\n"))
200 200 except SystemExit, inst:
201 201 # Commands shouldn't sys.exit directly, but give a return code.
202 202 # Just in case catch this and and pass exit code to caller.
203 203 return inst.code
204 204 except socket.error, inst:
205 205 ui.warn(_("abort: %s\n") % inst.args[-1])
206 206 except:
207 207 ui.warn(_("** unknown exception encountered,"
208 208 " please report by visiting\n"))
209 209 ui.warn(_("** http://mercurial.selenic.com/wiki/BugTracker\n"))
210 210 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
211 211 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
212 212 % util.version())
213 213 ui.warn(_("** Extensions loaded: %s\n")
214 214 % ", ".join([x[0] for x in extensions.extensions()]))
215 215 raise
216 216
217 217 return -1
218 218
219 219 def aliasargs(fn, givenargs):
220 220 args = getattr(fn, 'args', [])
221 if args and givenargs:
221 if args:
222 222 cmd = ' '.join(map(util.shellquote, args))
223 223
224 224 nums = []
225 225 def replacer(m):
226 226 num = int(m.group(1)) - 1
227 227 nums.append(num)
228 228 if num < len(givenargs):
229 229 return givenargs[num]
230 return ''
230 raise util.Abort(_('too few arguments for command alias'))
231 231 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
232 232 givenargs = [x for i, x in enumerate(givenargs)
233 233 if i not in nums]
234 234 args = shlex.split(cmd)
235 235 return args + givenargs
236 236
237 237 class cmdalias(object):
238 238 def __init__(self, name, definition, cmdtable):
239 239 self.name = self.cmd = name
240 240 self.cmdname = ''
241 241 self.definition = definition
242 242 self.args = []
243 243 self.opts = []
244 244 self.help = ''
245 245 self.norepo = True
246 246 self.badalias = False
247 247
248 248 try:
249 249 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
250 250 for alias, e in cmdtable.iteritems():
251 251 if e is entry:
252 252 self.cmd = alias
253 253 break
254 254 self.shadows = True
255 255 except error.UnknownCommand:
256 256 self.shadows = False
257 257
258 258 if not self.definition:
259 259 def fn(ui, *args):
260 260 ui.warn(_("no definition for alias '%s'\n") % self.name)
261 261 return 1
262 262 self.fn = fn
263 263 self.badalias = True
264 264 return
265 265
266 266 if self.definition.startswith('!'):
267 267 self.shell = True
268 268 def fn(ui, *args):
269 269 env = {'HG_ARGS': ' '.join((self.name,) + args)}
270 270 def _checkvar(m):
271 271 if m.groups()[0] == '$':
272 272 return m.group()
273 273 elif int(m.groups()[0]) <= len(args):
274 274 return m.group()
275 275 else:
276 276 ui.debug("No argument found for substitution "
277 277 "of %i variable in alias '%s' definition."
278 278 % (int(m.groups()[0]), self.name))
279 279 return ''
280 280 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
281 281 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
282 282 replace['0'] = self.name
283 283 replace['@'] = ' '.join(args)
284 284 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
285 285 return util.system(cmd, environ=env, out=ui.fout)
286 286 self.fn = fn
287 287 return
288 288
289 289 args = shlex.split(self.definition)
290 290 self.cmdname = cmd = args.pop(0)
291 291 args = map(util.expandpath, args)
292 292
293 293 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
294 294 if _earlygetopt([invalidarg], args):
295 295 def fn(ui, *args):
296 296 ui.warn(_("error in definition for alias '%s': %s may only "
297 297 "be given on the command line\n")
298 298 % (self.name, invalidarg))
299 299 return 1
300 300
301 301 self.fn = fn
302 302 self.badalias = True
303 303 return
304 304
305 305 try:
306 306 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
307 307 if len(tableentry) > 2:
308 308 self.fn, self.opts, self.help = tableentry
309 309 else:
310 310 self.fn, self.opts = tableentry
311 311
312 312 self.args = aliasargs(self.fn, args)
313 313 if cmd not in commands.norepo.split(' '):
314 314 self.norepo = False
315 315 if self.help.startswith("hg " + cmd):
316 316 # drop prefix in old-style help lines so hg shows the alias
317 317 self.help = self.help[4 + len(cmd):]
318 318 self.__doc__ = self.fn.__doc__
319 319
320 320 except error.UnknownCommand:
321 321 def fn(ui, *args):
322 322 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
323 323 % (self.name, cmd))
324 324 try:
325 325 # check if the command is in a disabled extension
326 326 commands.help_(ui, cmd, unknowncmd=True)
327 327 except error.UnknownCommand:
328 328 pass
329 329 return 1
330 330 self.fn = fn
331 331 self.badalias = True
332 332 except error.AmbiguousCommand:
333 333 def fn(ui, *args):
334 334 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
335 335 % (self.name, cmd))
336 336 return 1
337 337 self.fn = fn
338 338 self.badalias = True
339 339
340 340 def __call__(self, ui, *args, **opts):
341 341 if self.shadows:
342 342 ui.debug("alias '%s' shadows command '%s'\n" %
343 343 (self.name, self.cmdname))
344 344
345 345 if util.safehasattr(self, 'shell'):
346 346 return self.fn(ui, *args, **opts)
347 347 else:
348 348 try:
349 349 util.checksignature(self.fn)(ui, *args, **opts)
350 350 except error.SignatureError:
351 351 args = ' '.join([self.cmdname] + self.args)
352 352 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
353 353 raise
354 354
355 355 def addaliases(ui, cmdtable):
356 356 # aliases are processed after extensions have been loaded, so they
357 357 # may use extension commands. Aliases can also use other alias definitions,
358 358 # but only if they have been defined prior to the current definition.
359 359 for alias, definition in ui.configitems('alias'):
360 360 aliasdef = cmdalias(alias, definition, cmdtable)
361 361
362 362 try:
363 363 olddef = cmdtable[aliasdef.cmd][0]
364 364 if olddef.definition == aliasdef.definition:
365 365 continue
366 366 except (KeyError, AttributeError):
367 367 # definition might not exist or it might not be a cmdalias
368 368 pass
369 369
370 370 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
371 371 if aliasdef.norepo:
372 372 commands.norepo += ' %s' % alias
373 373
374 374 def _parse(ui, args):
375 375 options = {}
376 376 cmdoptions = {}
377 377
378 378 try:
379 379 args = fancyopts.fancyopts(args, commands.globalopts, options)
380 380 except fancyopts.getopt.GetoptError, inst:
381 381 raise error.CommandError(None, inst)
382 382
383 383 if args:
384 384 cmd, args = args[0], args[1:]
385 385 aliases, entry = cmdutil.findcmd(cmd, commands.table,
386 386 ui.config("ui", "strict"))
387 387 cmd = aliases[0]
388 388 args = aliasargs(entry[0], args)
389 389 defaults = ui.config("defaults", cmd)
390 390 if defaults:
391 391 args = map(util.expandpath, shlex.split(defaults)) + args
392 392 c = list(entry[1])
393 393 else:
394 394 cmd = None
395 395 c = []
396 396
397 397 # combine global options into local
398 398 for o in commands.globalopts:
399 399 c.append((o[0], o[1], options[o[1]], o[3]))
400 400
401 401 try:
402 402 args = fancyopts.fancyopts(args, c, cmdoptions, True)
403 403 except fancyopts.getopt.GetoptError, inst:
404 404 raise error.CommandError(cmd, inst)
405 405
406 406 # separate global options back out
407 407 for o in commands.globalopts:
408 408 n = o[1]
409 409 options[n] = cmdoptions[n]
410 410 del cmdoptions[n]
411 411
412 412 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
413 413
414 414 def _parseconfig(ui, config):
415 415 """parse the --config options from the command line"""
416 416 configs = []
417 417
418 418 for cfg in config:
419 419 try:
420 420 name, value = cfg.split('=', 1)
421 421 section, name = name.split('.', 1)
422 422 if not section or not name:
423 423 raise IndexError
424 424 ui.setconfig(section, name, value)
425 425 configs.append((section, name, value))
426 426 except (IndexError, ValueError):
427 427 raise util.Abort(_('malformed --config option: %r '
428 428 '(use --config section.name=value)') % cfg)
429 429
430 430 return configs
431 431
432 432 def _earlygetopt(aliases, args):
433 433 """Return list of values for an option (or aliases).
434 434
435 435 The values are listed in the order they appear in args.
436 436 The options and values are removed from args.
437 437 """
438 438 try:
439 439 argcount = args.index("--")
440 440 except ValueError:
441 441 argcount = len(args)
442 442 shortopts = [opt for opt in aliases if len(opt) == 2]
443 443 values = []
444 444 pos = 0
445 445 while pos < argcount:
446 446 if args[pos] in aliases:
447 447 if pos + 1 >= argcount:
448 448 # ignore and let getopt report an error if there is no value
449 449 break
450 450 del args[pos]
451 451 values.append(args.pop(pos))
452 452 argcount -= 2
453 453 elif args[pos][:2] in shortopts:
454 454 # short option can have no following space, e.g. hg log -Rfoo
455 455 values.append(args.pop(pos)[2:])
456 456 argcount -= 1
457 457 else:
458 458 pos += 1
459 459 return values
460 460
461 461 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
462 462 # run pre-hook, and abort if it fails
463 463 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
464 464 pats=cmdpats, opts=cmdoptions)
465 465 if ret:
466 466 return ret
467 467 ret = _runcommand(ui, options, cmd, d)
468 468 # run post-hook, passing command result
469 469 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
470 470 result=ret, pats=cmdpats, opts=cmdoptions)
471 471 return ret
472 472
473 473 def _getlocal(ui, rpath):
474 474 """Return (path, local ui object) for the given target path.
475 475
476 476 Takes paths in [cwd]/.hg/hgrc into account."
477 477 """
478 478 try:
479 479 wd = os.getcwd()
480 480 except OSError, e:
481 481 raise util.Abort(_("error getting current working directory: %s") %
482 482 e.strerror)
483 483 path = cmdutil.findrepo(wd) or ""
484 484 if not path:
485 485 lui = ui
486 486 else:
487 487 lui = ui.copy()
488 488 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
489 489
490 490 if rpath and rpath[-1]:
491 491 path = lui.expandpath(rpath[-1])
492 492 lui = ui.copy()
493 493 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
494 494
495 495 return path, lui
496 496
497 497 def _checkshellalias(lui, ui, args):
498 498 norepo = commands.norepo
499 499 options = {}
500 500
501 501 try:
502 502 args = fancyopts.fancyopts(args, commands.globalopts, options)
503 503 except fancyopts.getopt.GetoptError:
504 504 return
505 505
506 506 if not args:
507 507 return
508 508
509 509 cmdtable = commands.table.copy()
510 510 addaliases(lui, cmdtable)
511 511
512 512 cmd = args[0]
513 513 try:
514 514 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
515 515 except (error.AmbiguousCommand, error.UnknownCommand):
516 516 commands.norepo = norepo
517 517 return
518 518
519 519 cmd = aliases[0]
520 520 fn = entry[0]
521 521
522 522 if cmd and util.safehasattr(fn, 'shell'):
523 523 d = lambda: fn(ui, *args[1:])
524 524 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
525 525
526 526 commands.norepo = norepo
527 527
528 528 _loaded = set()
529 529 def _dispatch(req):
530 530 args = req.args
531 531 ui = req.ui
532 532
533 533 # read --config before doing anything else
534 534 # (e.g. to change trust settings for reading .hg/hgrc)
535 535 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
536 536
537 537 # check for cwd
538 538 cwd = _earlygetopt(['--cwd'], args)
539 539 if cwd:
540 540 os.chdir(cwd[-1])
541 541
542 542 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
543 543 path, lui = _getlocal(ui, rpath)
544 544
545 545 # Now that we're operating in the right directory/repository with
546 546 # the right config settings, check for shell aliases
547 547 shellaliasfn = _checkshellalias(lui, ui, args)
548 548 if shellaliasfn:
549 549 return shellaliasfn()
550 550
551 551 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
552 552 # reposetup. Programs like TortoiseHg will call _dispatch several
553 553 # times so we keep track of configured extensions in _loaded.
554 554 extensions.loadall(lui)
555 555 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
556 556 # Propagate any changes to lui.__class__ by extensions
557 557 ui.__class__ = lui.__class__
558 558
559 559 # (uisetup and extsetup are handled in extensions.loadall)
560 560
561 561 for name, module in exts:
562 562 cmdtable = getattr(module, 'cmdtable', {})
563 563 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
564 564 if overrides:
565 565 ui.warn(_("extension '%s' overrides commands: %s\n")
566 566 % (name, " ".join(overrides)))
567 567 commands.table.update(cmdtable)
568 568 _loaded.add(name)
569 569
570 570 # (reposetup is handled in hg.repository)
571 571
572 572 addaliases(lui, commands.table)
573 573
574 574 # check for fallback encoding
575 575 fallback = lui.config('ui', 'fallbackencoding')
576 576 if fallback:
577 577 encoding.fallbackencoding = fallback
578 578
579 579 fullargs = args
580 580 cmd, func, args, options, cmdoptions = _parse(lui, args)
581 581
582 582 if options["config"]:
583 583 raise util.Abort(_("option --config may not be abbreviated!"))
584 584 if options["cwd"]:
585 585 raise util.Abort(_("option --cwd may not be abbreviated!"))
586 586 if options["repository"]:
587 587 raise util.Abort(_(
588 588 "option -R has to be separated from other options (e.g. not -qR) "
589 589 "and --repository may only be abbreviated as --repo!"))
590 590
591 591 if options["encoding"]:
592 592 encoding.encoding = options["encoding"]
593 593 if options["encodingmode"]:
594 594 encoding.encodingmode = options["encodingmode"]
595 595 if options["time"]:
596 596 def get_times():
597 597 t = os.times()
598 598 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
599 599 t = (t[0], t[1], t[2], t[3], time.clock())
600 600 return t
601 601 s = get_times()
602 602 def print_time():
603 603 t = get_times()
604 604 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
605 605 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
606 606 atexit.register(print_time)
607 607
608 608 uis = set([ui, lui])
609 609
610 610 if req.repo:
611 611 uis.add(req.repo.ui)
612 612
613 613 # copy configs that were passed on the cmdline (--config) to the repo ui
614 614 for cfg in cfgs:
615 615 req.repo.ui.setconfig(*cfg)
616 616
617 617 if options['verbose'] or options['debug'] or options['quiet']:
618 618 for opt in ('verbose', 'debug', 'quiet'):
619 619 val = str(bool(options[opt]))
620 620 for ui_ in uis:
621 621 ui_.setconfig('ui', opt, val)
622 622
623 623 if options['traceback']:
624 624 for ui_ in uis:
625 625 ui_.setconfig('ui', 'traceback', 'on')
626 626
627 627 if options['noninteractive']:
628 628 for ui_ in uis:
629 629 ui_.setconfig('ui', 'interactive', 'off')
630 630
631 631 if cmdoptions.get('insecure', False):
632 632 for ui_ in uis:
633 633 ui_.setconfig('web', 'cacerts', '')
634 634
635 635 if options['version']:
636 636 return commands.version_(ui)
637 637 if options['help']:
638 638 return commands.help_(ui, cmd)
639 639 elif not cmd:
640 640 return commands.help_(ui, 'shortlist')
641 641
642 642 repo = None
643 643 cmdpats = args[:]
644 644 if cmd not in commands.norepo.split():
645 645 # use the repo from the request only if we don't have -R
646 646 if not rpath and not cwd:
647 647 repo = req.repo
648 648
649 649 if repo:
650 650 # set the descriptors of the repo ui to those of ui
651 651 repo.ui.fin = ui.fin
652 652 repo.ui.fout = ui.fout
653 653 repo.ui.ferr = ui.ferr
654 654 else:
655 655 try:
656 656 repo = hg.repository(ui, path=path)
657 657 if not repo.local():
658 658 raise util.Abort(_("repository '%s' is not local") % path)
659 659 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
660 660 except error.RequirementError:
661 661 raise
662 662 except error.RepoError:
663 663 if cmd not in commands.optionalrepo.split():
664 664 if args and not path: # try to infer -R from command args
665 665 repos = map(cmdutil.findrepo, args)
666 666 guess = repos[0]
667 667 if guess and repos.count(guess) == len(repos):
668 668 req.args = ['--repository', guess] + fullargs
669 669 return _dispatch(req)
670 670 if not path:
671 671 raise error.RepoError(_("no repository found in '%s'"
672 672 " (.hg not found)") % os.getcwd())
673 673 raise
674 674 if repo:
675 675 ui = repo.ui
676 676 args.insert(0, repo)
677 677 elif rpath:
678 678 ui.warn(_("warning: --repository ignored\n"))
679 679
680 680 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
681 681 ui.log("command", msg + "\n")
682 682 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
683 683 try:
684 684 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
685 685 cmdpats, cmdoptions)
686 686 finally:
687 687 if repo and repo != req.repo:
688 688 repo.close()
689 689
690 690 def _runcommand(ui, options, cmd, cmdfunc):
691 691 def checkargs():
692 692 try:
693 693 return cmdfunc()
694 694 except error.SignatureError:
695 695 raise error.CommandError(cmd, _("invalid arguments"))
696 696
697 697 if options['profile']:
698 698 format = ui.config('profiling', 'format', default='text')
699 699
700 700 if not format in ['text', 'kcachegrind']:
701 701 ui.warn(_("unrecognized profiling format '%s'"
702 702 " - Ignored\n") % format)
703 703 format = 'text'
704 704
705 705 output = ui.config('profiling', 'output')
706 706
707 707 if output:
708 708 path = ui.expandpath(output)
709 709 ostream = open(path, 'wb')
710 710 else:
711 711 ostream = sys.stderr
712 712
713 713 try:
714 714 from mercurial import lsprof
715 715 except ImportError:
716 716 raise util.Abort(_(
717 717 'lsprof not available - install from '
718 718 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
719 719 p = lsprof.Profiler()
720 720 p.enable(subcalls=True)
721 721 try:
722 722 return checkargs()
723 723 finally:
724 724 p.disable()
725 725
726 726 if format == 'kcachegrind':
727 727 import lsprofcalltree
728 728 calltree = lsprofcalltree.KCacheGrind(p)
729 729 calltree.output(ostream)
730 730 else:
731 731 # format == 'text'
732 732 stats = lsprof.Stats(p.getstats())
733 733 stats.sort()
734 734 stats.pprint(top=10, file=ostream, climit=5)
735 735
736 736 if output:
737 737 ostream.close()
738 738 else:
739 739 return checkargs()
@@ -1,410 +1,416 b''
1 1 $ "$TESTDIR/hghave" system-sh || exit 80
2 2
3 3 $ HGFOO=BAR; export HGFOO
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > graphlog=
7 7 >
8 8 > [alias]
9 9 > # should clobber ci but not commit (issue2993)
10 10 > ci = version
11 11 > myinit = init
12 12 > cleanstatus = status -c
13 13 > unknown = bargle
14 14 > ambiguous = s
15 15 > recursive = recursive
16 16 > nodefinition =
17 17 > no--cwd = status --cwd elsewhere
18 18 > no-R = status -R elsewhere
19 19 > no--repo = status --repo elsewhere
20 20 > no--repository = status --repository elsewhere
21 21 > mylog = log
22 22 > lognull = log -r null
23 23 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
24 24 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
25 25 > dln = lognull --debug
26 26 > nousage = rollback
27 27 > put = export -r 0 -o "\$FOO/%R.diff"
28 28 > blank = !echo
29 29 > self = !echo '\$0'
30 30 > echo = !echo '\$@'
31 31 > echo1 = !echo '\$1'
32 32 > echo2 = !echo '\$2'
33 33 > echo13 = !echo '\$1' '\$3'
34 34 > count = !hg log -r '\$@' --template='.' | wc -c | sed -e 's/ //g'
35 35 > mcount = !hg log \$@ --template='.' | wc -c | sed -e 's/ //g'
36 36 > rt = root
37 37 > tglog = glog --template "{rev}:{node|short}: '{desc}' {branches}\n"
38 38 > idalias = id
39 39 > idaliaslong = id
40 40 > idaliasshell = !echo test
41 41 > parentsshell1 = !echo one
42 42 > parentsshell2 = !echo two
43 43 > escaped1 = !echo 'test\$\$test'
44 44 > escaped2 = !echo "HGFOO is \$\$HGFOO"
45 45 > escaped3 = !echo "\$1 is \$\$\$1"
46 46 > escaped4 = !echo '\$\$0' '\$\$@'
47 47 >
48 48 > [defaults]
49 49 > mylog = -q
50 50 > lognull = -q
51 51 > log = -v
52 52 > EOF
53 53
54 54
55 55 basic
56 56
57 57 $ hg myinit alias
58 58
59 59
60 60 unknown
61 61
62 62 $ hg unknown
63 63 alias 'unknown' resolves to unknown command 'bargle'
64 64 $ hg help unknown
65 65 alias 'unknown' resolves to unknown command 'bargle'
66 66
67 67
68 68 ambiguous
69 69
70 70 $ hg ambiguous
71 71 alias 'ambiguous' resolves to ambiguous command 's'
72 72 $ hg help ambiguous
73 73 alias 'ambiguous' resolves to ambiguous command 's'
74 74
75 75
76 76 recursive
77 77
78 78 $ hg recursive
79 79 alias 'recursive' resolves to unknown command 'recursive'
80 80 $ hg help recursive
81 81 alias 'recursive' resolves to unknown command 'recursive'
82 82
83 83
84 84 no definition
85 85
86 86 $ hg nodef
87 87 no definition for alias 'nodefinition'
88 88 $ hg help nodef
89 89 no definition for alias 'nodefinition'
90 90
91 91
92 92 invalid options
93 93
94 94 $ hg no--cwd
95 95 error in definition for alias 'no--cwd': --cwd may only be given on the command line
96 96 $ hg help no--cwd
97 97 error in definition for alias 'no--cwd': --cwd may only be given on the command line
98 98 $ hg no-R
99 99 error in definition for alias 'no-R': -R may only be given on the command line
100 100 $ hg help no-R
101 101 error in definition for alias 'no-R': -R may only be given on the command line
102 102 $ hg no--repo
103 103 error in definition for alias 'no--repo': --repo may only be given on the command line
104 104 $ hg help no--repo
105 105 error in definition for alias 'no--repo': --repo may only be given on the command line
106 106 $ hg no--repository
107 107 error in definition for alias 'no--repository': --repository may only be given on the command line
108 108 $ hg help no--repository
109 109 error in definition for alias 'no--repository': --repository may only be given on the command line
110 110
111 111 $ cd alias
112 112
113 113
114 114 no usage
115 115
116 116 $ hg nousage
117 117 no rollback information available
118 118
119 119 $ echo foo > foo
120 120 $ hg commit -Amfoo
121 121 adding foo
122 122
123 123
124 124 with opts
125 125
126 126 $ hg cleanst
127 127 C foo
128 128
129 129
130 130 with opts and whitespace
131 131
132 132 $ hg shortlog
133 133 0 e63c23eaa88a | 1970-01-01 00:00 +0000
134 134
135 135 positional arguments
136 136
137 $ hg positional
138 abort: too few arguments for command alias
139 [255]
140 $ hg positional a
141 abort: too few arguments for command alias
142 [255]
137 143 $ hg positional 'node|short' rev
138 144 0 e63c23eaa88a | 1970-01-01 00:00 +0000
139 145
140 146 interaction with defaults
141 147
142 148 $ hg mylog
143 149 0:e63c23eaa88a
144 150 $ hg lognull
145 151 -1:000000000000
146 152
147 153
148 154 properly recursive
149 155
150 156 $ hg dln
151 157 changeset: -1:0000000000000000000000000000000000000000
152 158 parent: -1:0000000000000000000000000000000000000000
153 159 parent: -1:0000000000000000000000000000000000000000
154 160 manifest: -1:0000000000000000000000000000000000000000
155 161 user:
156 162 date: Thu Jan 01 00:00:00 1970 +0000
157 163 extra: branch=default
158 164
159 165
160 166
161 167 path expanding
162 168
163 169 $ FOO=`pwd` hg put
164 170 $ cat 0.diff
165 171 # HG changeset patch
166 172 # User test
167 173 # Date 0 0
168 174 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
169 175 # Parent 0000000000000000000000000000000000000000
170 176 foo
171 177
172 178 diff -r 000000000000 -r e63c23eaa88a foo
173 179 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
174 180 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
175 181 @@ -0,0 +1,1 @@
176 182 +foo
177 183
178 184
179 185 simple shell aliases
180 186
181 187 $ hg blank
182 188
183 189 $ hg blank foo
184 190
185 191 $ hg self
186 192 self
187 193 $ hg echo
188 194
189 195 $ hg echo foo
190 196 foo
191 197 $ hg echo 'test $2' foo
192 198 test $2 foo
193 199 $ hg echo1 foo bar baz
194 200 foo
195 201 $ hg echo2 foo bar baz
196 202 bar
197 203 $ hg echo13 foo bar baz test
198 204 foo baz
199 205 $ hg echo2 foo
200 206
201 207 $ echo bar > bar
202 208 $ hg commit -qA -m bar
203 209 $ hg count .
204 210 1
205 211 $ hg count 'branch(default)'
206 212 2
207 213 $ hg mcount -r '"branch(default)"'
208 214 2
209 215
210 216 $ hg tglog
211 217 @ 1:7e7f92de180e: 'bar'
212 218 |
213 219 o 0:e63c23eaa88a: 'foo'
214 220
215 221
216 222
217 223 shadowing
218 224
219 225 $ hg i
220 226 hg: command 'i' is ambiguous:
221 227 idalias idaliaslong idaliasshell identify import incoming init
222 228 [255]
223 229 $ hg id
224 230 7e7f92de180e tip
225 231 $ hg ida
226 232 hg: command 'ida' is ambiguous:
227 233 idalias idaliaslong idaliasshell
228 234 [255]
229 235 $ hg idalias
230 236 7e7f92de180e tip
231 237 $ hg idaliasl
232 238 7e7f92de180e tip
233 239 $ hg idaliass
234 240 test
235 241 $ hg parentsshell
236 242 hg: command 'parentsshell' is ambiguous:
237 243 parentsshell1 parentsshell2
238 244 [255]
239 245 $ hg parentsshell1
240 246 one
241 247 $ hg parentsshell2
242 248 two
243 249
244 250
245 251 shell aliases with global options
246 252
247 253 $ hg init sub
248 254 $ cd sub
249 255 $ hg count 'branch(default)'
250 256 0
251 257 $ hg -v count 'branch(default)'
252 258 0
253 259 $ hg -R .. count 'branch(default)'
254 260 0
255 261 $ hg --cwd .. count 'branch(default)'
256 262 2
257 263 $ hg echo --cwd ..
258 264
259 265
260 266
261 267 repo specific shell aliases
262 268
263 269 $ cat >> .hg/hgrc <<EOF
264 270 > [alias]
265 271 > subalias = !echo sub \$@
266 272 > EOF
267 273 $ cat >> ../.hg/hgrc <<EOF
268 274 > [alias]
269 275 > mainalias = !echo main \$@
270 276 > EOF
271 277
272 278
273 279 shell alias defined in current repo
274 280
275 281 $ hg subalias
276 282 sub
277 283 $ hg --cwd .. subalias > /dev/null
278 284 hg: unknown command 'subalias'
279 285 [255]
280 286 $ hg -R .. subalias > /dev/null
281 287 hg: unknown command 'subalias'
282 288 [255]
283 289
284 290
285 291 shell alias defined in other repo
286 292
287 293 $ hg mainalias > /dev/null
288 294 hg: unknown command 'mainalias'
289 295 [255]
290 296 $ hg -R .. mainalias
291 297 main
292 298 $ hg --cwd .. mainalias
293 299 main
294 300
295 301
296 302 shell aliases with escaped $ chars
297 303
298 304 $ hg escaped1
299 305 test$test
300 306 $ hg escaped2
301 307 HGFOO is BAR
302 308 $ hg escaped3 HGFOO
303 309 HGFOO is BAR
304 310 $ hg escaped4 test
305 311 $0 $@
306 312
307 313
308 314 invalid arguments
309 315
310 316 $ hg rt foo
311 317 hg rt: invalid arguments
312 318 hg rt
313 319
314 320 alias for: hg root
315 321
316 322 use "hg help rt" to show the full help text
317 323 [255]
318 324
319 325 invalid global arguments for normal commands, aliases, and shell aliases
320 326
321 327 $ hg --invalid root
322 328 hg: option --invalid not recognized
323 329 Mercurial Distributed SCM
324 330
325 331 basic commands:
326 332
327 333 add add the specified files on the next commit
328 334 annotate show changeset information by line for each file
329 335 clone make a copy of an existing repository
330 336 commit commit the specified files or all outstanding changes
331 337 diff diff repository (or selected files)
332 338 export dump the header and diffs for one or more changesets
333 339 forget forget the specified files on the next commit
334 340 init create a new repository in the given directory
335 341 log show revision history of entire repository or files
336 342 merge merge working directory with another revision
337 343 phase set or show the current phase name
338 344 pull pull changes from the specified source
339 345 push push changes to the specified destination
340 346 remove remove the specified files on the next commit
341 347 serve start stand-alone webserver
342 348 status show changed files in the working directory
343 349 summary summarize working directory state
344 350 update update working directory (or switch revisions)
345 351
346 352 use "hg help" for the full list of commands or "hg -v" for details
347 353 [255]
348 354 $ hg --invalid mylog
349 355 hg: option --invalid not recognized
350 356 Mercurial Distributed SCM
351 357
352 358 basic commands:
353 359
354 360 add add the specified files on the next commit
355 361 annotate show changeset information by line for each file
356 362 clone make a copy of an existing repository
357 363 commit commit the specified files or all outstanding changes
358 364 diff diff repository (or selected files)
359 365 export dump the header and diffs for one or more changesets
360 366 forget forget the specified files on the next commit
361 367 init create a new repository in the given directory
362 368 log show revision history of entire repository or files
363 369 merge merge working directory with another revision
364 370 phase set or show the current phase name
365 371 pull pull changes from the specified source
366 372 push push changes to the specified destination
367 373 remove remove the specified files on the next commit
368 374 serve start stand-alone webserver
369 375 status show changed files in the working directory
370 376 summary summarize working directory state
371 377 update update working directory (or switch revisions)
372 378
373 379 use "hg help" for the full list of commands or "hg -v" for details
374 380 [255]
375 381 $ hg --invalid blank
376 382 hg: option --invalid not recognized
377 383 Mercurial Distributed SCM
378 384
379 385 basic commands:
380 386
381 387 add add the specified files on the next commit
382 388 annotate show changeset information by line for each file
383 389 clone make a copy of an existing repository
384 390 commit commit the specified files or all outstanding changes
385 391 diff diff repository (or selected files)
386 392 export dump the header and diffs for one or more changesets
387 393 forget forget the specified files on the next commit
388 394 init create a new repository in the given directory
389 395 log show revision history of entire repository or files
390 396 merge merge working directory with another revision
391 397 phase set or show the current phase name
392 398 pull pull changes from the specified source
393 399 push push changes to the specified destination
394 400 remove remove the specified files on the next commit
395 401 serve start stand-alone webserver
396 402 status show changed files in the working directory
397 403 summary summarize working directory state
398 404 update update working directory (or switch revisions)
399 405
400 406 use "hg help" for the full list of commands or "hg -v" for details
401 407 [255]
402 408
403 409 This should show id:
404 410
405 411 $ hg --config alias.log='id' log
406 412 000000000000 tip
407 413
408 414 This shouldn't:
409 415
410 416 $ hg --config alias.log='id' history
General Comments 0
You need to be logged in to leave comments. Login now