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