dispatch: move command dispatching into its own module
- move command dispatching functions from commands and cmdutil to dispatch
- change findcmd to take a table argument
- remove circular import of commands in cmdutil
- privatize helper functions in dispatch
--- a/hg Wed Aug 15 16:10:36 2007 -0500
+++ b/hg Wed Aug 15 16:55:13 2007 -0500
@@ -7,5 +7,5 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import mercurial.commands
-mercurial.commands.run()
+import mercurial.dispatch
+mercurial.dispatch.run()
--- a/hgext/alias.py Wed Aug 15 16:10:36 2007 -0500
+++ b/hgext/alias.py Wed Aug 15 16:55:13 2007 -0500
@@ -42,7 +42,7 @@
return
try:
- self._cmd = findcmd(self._ui, self._target)[1]
+ self._cmd = findcmd(self._ui, self._target, commands.table)[1]
if self._cmd == self:
raise RecursiveCommand()
if self._target in commands.norepo.split(' '):
--- a/mercurial/cmdutil.py Wed Aug 15 16:10:36 2007 -0500
+++ b/mercurial/cmdutil.py Wed Aug 15 16:55:13 2007 -0500
@@ -7,10 +7,8 @@
from node import *
from i18n import _
-import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex
-import bisect, stat
-import mdiff, bdiff, util, templater, patch, commands, hg, lock, time
-import fancyopts, revlog, version, extensions, hook
+import os, sys, bisect, stat
+import mdiff, bdiff, util, templater, patch
revrangesep = ':'
@@ -18,130 +16,8 @@
"""Exception raised if command is not in the command table."""
class AmbiguousCommand(Exception):
"""Exception raised if command shortcut matches more than one command."""
-class ParseError(Exception):
- """Exception raised on errors in parsing the command line."""
-def runcatch(ui, args):
- def catchterm(*args):
- raise util.SignalInterrupt
-
- for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
- num = getattr(signal, name, None)
- if num: signal.signal(num, catchterm)
-
- try:
- try:
- # enter the debugger before command execution
- if '--debugger' in args:
- pdb.set_trace()
- try:
- return dispatch(ui, args)
- finally:
- ui.flush()
- except:
- # enter the debugger when we hit an exception
- if '--debugger' in args:
- pdb.post_mortem(sys.exc_info()[2])
- ui.print_exc()
- raise
-
- except ParseError, inst:
- if inst.args[0]:
- ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
- commands.help_(ui, inst.args[0])
- else:
- ui.warn(_("hg: %s\n") % inst.args[1])
- commands.help_(ui, 'shortlist')
- except AmbiguousCommand, inst:
- ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
- (inst.args[0], " ".join(inst.args[1])))
- except UnknownCommand, inst:
- ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
- commands.help_(ui, 'shortlist')
- except hg.RepoError, inst:
- ui.warn(_("abort: %s!\n") % inst)
- except lock.LockHeld, inst:
- if inst.errno == errno.ETIMEDOUT:
- reason = _('timed out waiting for lock held by %s') % inst.locker
- else:
- reason = _('lock held by %s') % inst.locker
- ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
- except lock.LockUnavailable, inst:
- ui.warn(_("abort: could not lock %s: %s\n") %
- (inst.desc or inst.filename, inst.strerror))
- except revlog.RevlogError, inst:
- ui.warn(_("abort: %s!\n") % inst)
- except util.SignalInterrupt:
- ui.warn(_("killed!\n"))
- except KeyboardInterrupt:
- try:
- ui.warn(_("interrupted!\n"))
- except IOError, inst:
- if inst.errno == errno.EPIPE:
- if ui.debugflag:
- ui.warn(_("\nbroken pipe\n"))
- else:
- raise
- except socket.error, inst:
- ui.warn(_("abort: %s\n") % inst[1])
- except IOError, inst:
- if hasattr(inst, "code"):
- ui.warn(_("abort: %s\n") % inst)
- elif hasattr(inst, "reason"):
- try: # usually it is in the form (errno, strerror)
- reason = inst.reason.args[1]
- except: # it might be anything, for example a string
- reason = inst.reason
- ui.warn(_("abort: error: %s\n") % reason)
- elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
- if ui.debugflag:
- ui.warn(_("broken pipe\n"))
- elif getattr(inst, "strerror", None):
- if getattr(inst, "filename", None):
- ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
- else:
- ui.warn(_("abort: %s\n") % inst.strerror)
- else:
- raise
- except OSError, inst:
- if getattr(inst, "filename", None):
- ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
- else:
- ui.warn(_("abort: %s\n") % inst.strerror)
- except util.UnexpectedOutput, inst:
- ui.warn(_("abort: %s") % inst[0])
- if not isinstance(inst[1], basestring):
- ui.warn(" %r\n" % (inst[1],))
- elif not inst[1]:
- ui.warn(_(" empty string\n"))
- else:
- ui.warn("\n%r\n" % util.ellipsis(inst[1]))
- except ImportError, inst:
- m = str(inst).split()[-1]
- ui.warn(_("abort: could not import module %s!\n" % m))
- if m in "mpatch bdiff".split():
- ui.warn(_("(did you forget to compile extensions?)\n"))
- elif m in "zlib".split():
- ui.warn(_("(is your Python install correct?)\n"))
-
- except util.Abort, inst:
- ui.warn(_("abort: %s\n") % inst)
- except SystemExit, inst:
- # Commands shouldn't sys.exit directly, but give a return code.
- # Just in case catch this and and pass exit code to caller.
- return inst.code
- except:
- ui.warn(_("** unknown exception encountered, details follow\n"))
- ui.warn(_("** report bug details to "
- "http://www.selenic.com/mercurial/bts\n"))
- ui.warn(_("** or mercurial@selenic.com\n"))
- ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
- % version.get_version())
- raise
-
- return -1
-
-def findpossible(ui, cmd):
+def findpossible(ui, cmd, table):
"""
Return cmd -> (aliases, command table entry)
for each matching command.
@@ -149,7 +25,7 @@
"""
choice = {}
debugchoice = {}
- for e in commands.table.keys():
+ for e in table.keys():
aliases = e.lstrip("^").split("|")
found = None
if cmd in aliases:
@@ -161,18 +37,18 @@
break
if found is not None:
if aliases[0].startswith("debug") or found.startswith("debug"):
- debugchoice[found] = (aliases, commands.table[e])
+ debugchoice[found] = (aliases, table[e])
else:
- choice[found] = (aliases, commands.table[e])
+ choice[found] = (aliases, table[e])
if not choice and debugchoice:
choice = debugchoice
return choice
-def findcmd(ui, cmd):
+def findcmd(ui, cmd, table):
"""Return (aliases, command table entry) for command string."""
- choice = findpossible(ui, cmd)
+ choice = findpossible(ui, cmd, table)
if choice.has_key(cmd):
return choice[cmd]
@@ -187,247 +63,6 @@
raise UnknownCommand(cmd)
-def findrepo():
- p = os.getcwd()
- while not os.path.isdir(os.path.join(p, ".hg")):
- oldp, p = p, os.path.dirname(p)
- if p == oldp:
- return None
-
- return p
-
-def parse(ui, args):
- options = {}
- cmdoptions = {}
-
- try:
- args = fancyopts.fancyopts(args, commands.globalopts, options)
- except fancyopts.getopt.GetoptError, inst:
- raise ParseError(None, inst)
-
- if args:
- cmd, args = args[0], args[1:]
- aliases, i = findcmd(ui, cmd)
- cmd = aliases[0]
- defaults = ui.config("defaults", cmd)
- if defaults:
- args = shlex.split(defaults) + args
- c = list(i[1])
- else:
- cmd = None
- c = []
-
- # combine global options into local
- for o in commands.globalopts:
- c.append((o[0], o[1], options[o[1]], o[3]))
-
- try:
- args = fancyopts.fancyopts(args, c, cmdoptions)
- except fancyopts.getopt.GetoptError, inst:
- raise ParseError(cmd, inst)
-
- # separate global options back out
- for o in commands.globalopts:
- n = o[1]
- options[n] = cmdoptions[n]
- del cmdoptions[n]
-
- return (cmd, cmd and i[0] or None, args, options, cmdoptions)
-
-def parseconfig(config):
- """parse the --config options from the command line"""
- parsed = []
- for cfg in config:
- try:
- name, value = cfg.split('=', 1)
- section, name = name.split('.', 1)
- if not section or not name:
- raise IndexError
- parsed.append((section, name, value))
- except (IndexError, ValueError):
- raise util.Abort(_('malformed --config option: %s') % cfg)
- return parsed
-
-def earlygetopt(aliases, args):
- """Return list of values for an option (or aliases).
-
- The values are listed in the order they appear in args.
- The options and values are removed from args.
- """
- try:
- argcount = args.index("--")
- except ValueError:
- argcount = len(args)
- shortopts = [opt for opt in aliases if len(opt) == 2]
- values = []
- pos = 0
- while pos < argcount:
- if args[pos] in aliases:
- if pos + 1 >= argcount:
- # ignore and let getopt report an error if there is no value
- break
- del args[pos]
- values.append(args.pop(pos))
- argcount -= 2
- elif args[pos][:2] in shortopts:
- # short option can have no following space, e.g. hg log -Rfoo
- values.append(args.pop(pos)[2:])
- argcount -= 1
- else:
- pos += 1
- return values
-
-def dispatch(ui, args):
- # read --config before doing anything else
- # (e.g. to change trust settings for reading .hg/hgrc)
- config = earlygetopt(['--config'], args)
- if config:
- ui.updateopts(config=parseconfig(config))
-
- # check for cwd
- cwd = earlygetopt(['--cwd'], args)
- if cwd:
- os.chdir(cwd[-1])
-
- # read the local repository .hgrc into a local ui object
- path = findrepo() or ""
- if not path:
- lui = ui
- if path:
- try:
- lui = commands.ui.ui(parentui=ui)
- lui.readconfig(os.path.join(path, ".hg", "hgrc"))
- except IOError:
- pass
-
- # now we can expand paths, even ones in .hg/hgrc
- rpath = earlygetopt(["-R", "--repository", "--repo"], args)
- if rpath:
- path = lui.expandpath(rpath[-1])
- lui = commands.ui.ui(parentui=ui)
- lui.readconfig(os.path.join(path, ".hg", "hgrc"))
-
- extensions.loadall(lui)
- # check for fallback encoding
- fallback = lui.config('ui', 'fallbackencoding')
- if fallback:
- util._fallbackencoding = fallback
-
- fullargs = args
- cmd, func, args, options, cmdoptions = parse(lui, args)
-
- if options["config"]:
- raise util.Abort(_("Option --config may not be abbreviated!"))
- if options["cwd"]:
- raise util.Abort(_("Option --cwd may not be abbreviated!"))
- if options["repository"]:
- raise util.Abort(_(
- "Option -R has to be separated from other options (i.e. not -qR) "
- "and --repository may only be abbreviated as --repo!"))
-
- if options["encoding"]:
- util._encoding = options["encoding"]
- if options["encodingmode"]:
- util._encodingmode = options["encodingmode"]
- if options["time"]:
- def get_times():
- t = os.times()
- if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
- t = (t[0], t[1], t[2], t[3], time.clock())
- return t
- s = get_times()
- def print_time():
- t = get_times()
- ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
- (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
- atexit.register(print_time)
-
- ui.updateopts(options["verbose"], options["debug"], options["quiet"],
- not options["noninteractive"], options["traceback"])
-
- if options['help']:
- return commands.help_(ui, cmd, options['version'])
- elif options['version']:
- return commands.version_(ui)
- elif not cmd:
- return commands.help_(ui, 'shortlist')
-
- repo = None
- if cmd not in commands.norepo.split():
- try:
- repo = hg.repository(ui, path=path)
- ui = repo.ui
- if not repo.local():
- raise util.Abort(_("repository '%s' is not local") % path)
- except hg.RepoError:
- if cmd not in commands.optionalrepo.split():
- if not path:
- raise hg.RepoError(_("There is no Mercurial repository here"
- " (.hg not found)"))
- raise
- d = lambda: func(ui, repo, *args, **cmdoptions)
- else:
- d = lambda: func(ui, *args, **cmdoptions)
-
- # run pre-hook, and abort if it fails
- ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
- if ret:
- return ret
- ret = runcommand(ui, options, cmd, d)
- # run post-hook, passing command result
- hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
- result = ret)
- return ret
-
-def runcommand(ui, options, cmd, cmdfunc):
- def checkargs():
- try:
- return cmdfunc()
- except TypeError, inst:
- # was this an argument error?
- tb = traceback.extract_tb(sys.exc_info()[2])
- if len(tb) != 2: # no
- raise
- raise ParseError(cmd, _("invalid arguments"))
-
- if options['profile']:
- import hotshot, hotshot.stats
- prof = hotshot.Profile("hg.prof")
- try:
- try:
- return prof.runcall(checkargs)
- except:
- try:
- ui.warn(_('exception raised - generating '
- 'profile anyway\n'))
- except:
- pass
- raise
- finally:
- prof.close()
- stats = hotshot.stats.load("hg.prof")
- stats.strip_dirs()
- stats.sort_stats('time', 'calls')
- stats.print_stats(40)
- elif options['lsprof']:
- try:
- from mercurial import lsprof
- except ImportError:
- raise util.Abort(_(
- 'lsprof not available - install from '
- 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
- p = lsprof.Profiler()
- p.enable(subcalls=True)
- try:
- return checkargs()
- finally:
- p.disable()
- stats = lsprof.Stats(p.getstats())
- stats.sort()
- stats.pprint(top=10, file=sys.stderr, climit=5)
- else:
- return checkargs()
-
def bail_if_changed(repo):
modified, added, removed, deleted = repo.status()[:4]
if modified or added or removed or deleted:
--- a/mercurial/commands.py Wed Aug 15 16:10:36 2007 -0500
+++ b/mercurial/commands.py Wed Aug 15 16:55:13 2007 -0500
@@ -9,7 +9,7 @@
from node import *
from i18n import _
import os, re, sys, urllib
-import ui, hg, util, revlog, bundlerepo, extensions
+import hg, util, revlog, bundlerepo, extensions
import difflib, patch, time, help, mdiff, tempfile
import errno, version, socket
import archival, changegroup, cmdutil, hgweb.server, sshserver
@@ -662,7 +662,7 @@
options = []
otables = [globalopts]
if cmd:
- aliases, entry = cmdutil.findcmd(ui, cmd)
+ aliases, entry = cmdutil.findcmd(ui, cmd, table)
otables.append(entry[1])
for t in otables:
for o in t:
@@ -672,7 +672,7 @@
ui.write("%s\n" % "\n".join(options))
return
- clist = cmdutil.findpossible(ui, cmd).keys()
+ clist = cmdutil.findpossible(ui, cmd, table).keys()
clist.sort()
ui.write("%s\n" % "\n".join(clist))
@@ -1307,7 +1307,7 @@
if with_version:
version_(ui)
ui.write('\n')
- aliases, i = cmdutil.findcmd(ui, name)
+ aliases, i = cmdutil.findcmd(ui, name, table)
# synopsis
ui.write("%s\n\n" % i[2])
@@ -3134,14 +3134,3 @@
norepo = ("clone init version help debugancestor debugcomplete debugdata"
" debugindex debugindexdot debugdate debuginstall")
optionalrepo = ("paths serve showconfig")
-
-def dispatch(args):
- try:
- u = ui.ui(traceback='--traceback' in args)
- except util.Abort, inst:
- sys.stderr.write(_("abort: %s\n") % inst)
- return -1
- return cmdutil.runcatch(u, args)
-
-def run():
- sys.exit(dispatch(sys.argv[1:]))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/dispatch.py Wed Aug 15 16:55:13 2007 -0500
@@ -0,0 +1,390 @@
+# dispatch.py - command dispatching for mercurial
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from node import *
+from i18n import _
+import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex, time
+import util, commands, hg, lock, fancyopts, revlog, version, extensions, hook
+import cmdutil
+import ui as _ui
+
+class ParseError(Exception):
+ """Exception raised on errors in parsing the command line."""
+
+def run():
+ "run the command in sys.argv"
+ sys.exit(dispatch(sys.argv[1:]))
+
+def dispatch(args):
+ "run the command specified in args"
+ try:
+ u = _ui.ui(traceback='--traceback' in args)
+ except util.Abort, inst:
+ sys.stderr.write(_("abort: %s\n") % inst)
+ return -1
+ return _runcatch(u, args)
+
+def _runcatch(ui, args):
+ def catchterm(*args):
+ raise util.SignalInterrupt
+
+ for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
+ num = getattr(signal, name, None)
+ if num: signal.signal(num, catchterm)
+
+ try:
+ try:
+ # enter the debugger before command execution
+ if '--debugger' in args:
+ pdb.set_trace()
+ try:
+ return _dispatch(ui, args)
+ finally:
+ ui.flush()
+ except:
+ # enter the debugger when we hit an exception
+ if '--debugger' in args:
+ pdb.post_mortem(sys.exc_info()[2])
+ ui.print_exc()
+ raise
+
+ except ParseError, inst:
+ if inst.args[0]:
+ ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
+ commands.help_(ui, inst.args[0])
+ else:
+ ui.warn(_("hg: %s\n") % inst.args[1])
+ commands.help_(ui, 'shortlist')
+ except cmdutil.AmbiguousCommand, inst:
+ ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
+ (inst.args[0], " ".join(inst.args[1])))
+ except cmdutil.UnknownCommand, inst:
+ ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
+ commands.help_(ui, 'shortlist')
+ except hg.RepoError, inst:
+ ui.warn(_("abort: %s!\n") % inst)
+ except lock.LockHeld, inst:
+ if inst.errno == errno.ETIMEDOUT:
+ reason = _('timed out waiting for lock held by %s') % inst.locker
+ else:
+ reason = _('lock held by %s') % inst.locker
+ ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
+ except lock.LockUnavailable, inst:
+ ui.warn(_("abort: could not lock %s: %s\n") %
+ (inst.desc or inst.filename, inst.strerror))
+ except revlog.RevlogError, inst:
+ ui.warn(_("abort: %s!\n") % inst)
+ except util.SignalInterrupt:
+ ui.warn(_("killed!\n"))
+ except KeyboardInterrupt:
+ try:
+ ui.warn(_("interrupted!\n"))
+ except IOError, inst:
+ if inst.errno == errno.EPIPE:
+ if ui.debugflag:
+ ui.warn(_("\nbroken pipe\n"))
+ else:
+ raise
+ except socket.error, inst:
+ ui.warn(_("abort: %s\n") % inst[1])
+ except IOError, inst:
+ if hasattr(inst, "code"):
+ ui.warn(_("abort: %s\n") % inst)
+ elif hasattr(inst, "reason"):
+ try: # usually it is in the form (errno, strerror)
+ reason = inst.reason.args[1]
+ except: # it might be anything, for example a string
+ reason = inst.reason
+ ui.warn(_("abort: error: %s\n") % reason)
+ elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
+ if ui.debugflag:
+ ui.warn(_("broken pipe\n"))
+ elif getattr(inst, "strerror", None):
+ if getattr(inst, "filename", None):
+ ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
+ else:
+ ui.warn(_("abort: %s\n") % inst.strerror)
+ else:
+ raise
+ except OSError, inst:
+ if getattr(inst, "filename", None):
+ ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
+ else:
+ ui.warn(_("abort: %s\n") % inst.strerror)
+ except util.UnexpectedOutput, inst:
+ ui.warn(_("abort: %s") % inst[0])
+ if not isinstance(inst[1], basestring):
+ ui.warn(" %r\n" % (inst[1],))
+ elif not inst[1]:
+ ui.warn(_(" empty string\n"))
+ else:
+ ui.warn("\n%r\n" % util.ellipsis(inst[1]))
+ except ImportError, inst:
+ m = str(inst).split()[-1]
+ ui.warn(_("abort: could not import module %s!\n" % m))
+ if m in "mpatch bdiff".split():
+ ui.warn(_("(did you forget to compile extensions?)\n"))
+ elif m in "zlib".split():
+ ui.warn(_("(is your Python install correct?)\n"))
+
+ except util.Abort, inst:
+ ui.warn(_("abort: %s\n") % inst)
+ except SystemExit, inst:
+ # Commands shouldn't sys.exit directly, but give a return code.
+ # Just in case catch this and and pass exit code to caller.
+ return inst.code
+ except:
+ ui.warn(_("** unknown exception encountered, details follow\n"))
+ ui.warn(_("** report bug details to "
+ "http://www.selenic.com/mercurial/bts\n"))
+ ui.warn(_("** or mercurial@selenic.com\n"))
+ ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
+ % version.get_version())
+ raise
+
+ return -1
+
+def _findrepo():
+ p = os.getcwd()
+ while not os.path.isdir(os.path.join(p, ".hg")):
+ oldp, p = p, os.path.dirname(p)
+ if p == oldp:
+ return None
+
+ return p
+
+def _parse(ui, args):
+ options = {}
+ cmdoptions = {}
+
+ try:
+ args = fancyopts.fancyopts(args, commands.globalopts, options)
+ except fancyopts.getopt.GetoptError, inst:
+ raise ParseError(None, inst)
+
+ if args:
+ cmd, args = args[0], args[1:]
+ aliases, i = cmdutil.findcmd(ui, cmd, commands.table)
+ cmd = aliases[0]
+ defaults = ui.config("defaults", cmd)
+ if defaults:
+ args = shlex.split(defaults) + args
+ c = list(i[1])
+ else:
+ cmd = None
+ c = []
+
+ # combine global options into local
+ for o in commands.globalopts:
+ c.append((o[0], o[1], options[o[1]], o[3]))
+
+ try:
+ args = fancyopts.fancyopts(args, c, cmdoptions)
+ except fancyopts.getopt.GetoptError, inst:
+ raise ParseError(cmd, inst)
+
+ # separate global options back out
+ for o in commands.globalopts:
+ n = o[1]
+ options[n] = cmdoptions[n]
+ del cmdoptions[n]
+
+ return (cmd, cmd and i[0] or None, args, options, cmdoptions)
+
+def _parseconfig(config):
+ """parse the --config options from the command line"""
+ parsed = []
+ for cfg in config:
+ try:
+ name, value = cfg.split('=', 1)
+ section, name = name.split('.', 1)
+ if not section or not name:
+ raise IndexError
+ parsed.append((section, name, value))
+ except (IndexError, ValueError):
+ raise util.Abort(_('malformed --config option: %s') % cfg)
+ return parsed
+
+def _earlygetopt(aliases, args):
+ """Return list of values for an option (or aliases).
+
+ The values are listed in the order they appear in args.
+ The options and values are removed from args.
+ """
+ try:
+ argcount = args.index("--")
+ except ValueError:
+ argcount = len(args)
+ shortopts = [opt for opt in aliases if len(opt) == 2]
+ values = []
+ pos = 0
+ while pos < argcount:
+ if args[pos] in aliases:
+ if pos + 1 >= argcount:
+ # ignore and let getopt report an error if there is no value
+ break
+ del args[pos]
+ values.append(args.pop(pos))
+ argcount -= 2
+ elif args[pos][:2] in shortopts:
+ # short option can have no following space, e.g. hg log -Rfoo
+ values.append(args.pop(pos)[2:])
+ argcount -= 1
+ else:
+ pos += 1
+ return values
+
+def _dispatch(ui, args):
+ # read --config before doing anything else
+ # (e.g. to change trust settings for reading .hg/hgrc)
+ config = _earlygetopt(['--config'], args)
+ if config:
+ ui.updateopts(config=_parseconfig(config))
+
+ # check for cwd
+ cwd = _earlygetopt(['--cwd'], args)
+ if cwd:
+ os.chdir(cwd[-1])
+
+ # read the local repository .hgrc into a local ui object
+ path = _findrepo() or ""
+ if not path:
+ lui = ui
+ if path:
+ try:
+ lui = _ui.ui(parentui=ui)
+ lui.readconfig(os.path.join(path, ".hg", "hgrc"))
+ except IOError:
+ pass
+
+ # now we can expand paths, even ones in .hg/hgrc
+ rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
+ if rpath:
+ path = lui.expandpath(rpath[-1])
+ lui = _ui.ui(parentui=ui)
+ lui.readconfig(os.path.join(path, ".hg", "hgrc"))
+
+ extensions.loadall(lui)
+ # check for fallback encoding
+ fallback = lui.config('ui', 'fallbackencoding')
+ if fallback:
+ util._fallbackencoding = fallback
+
+ fullargs = args
+ cmd, func, args, options, cmdoptions = _parse(lui, args)
+
+ if options["config"]:
+ raise util.Abort(_("Option --config may not be abbreviated!"))
+ if options["cwd"]:
+ raise util.Abort(_("Option --cwd may not be abbreviated!"))
+ if options["repository"]:
+ raise util.Abort(_(
+ "Option -R has to be separated from other options (i.e. not -qR) "
+ "and --repository may only be abbreviated as --repo!"))
+
+ if options["encoding"]:
+ util._encoding = options["encoding"]
+ if options["encodingmode"]:
+ util._encodingmode = options["encodingmode"]
+ if options["time"]:
+ def get_times():
+ t = os.times()
+ if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
+ t = (t[0], t[1], t[2], t[3], time.clock())
+ return t
+ s = get_times()
+ def print_time():
+ t = get_times()
+ ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
+ (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
+ atexit.register(print_time)
+
+ ui.updateopts(options["verbose"], options["debug"], options["quiet"],
+ not options["noninteractive"], options["traceback"])
+
+ if options['help']:
+ return commands.help_(ui, cmd, options['version'])
+ elif options['version']:
+ return commands.version_(ui)
+ elif not cmd:
+ return commands.help_(ui, 'shortlist')
+
+ repo = None
+ if cmd not in commands.norepo.split():
+ try:
+ repo = hg.repository(ui, path=path)
+ ui = repo.ui
+ if not repo.local():
+ raise util.Abort(_("repository '%s' is not local") % path)
+ except hg.RepoError:
+ if cmd not in commands.optionalrepo.split():
+ if not path:
+ raise hg.RepoError(_("There is no Mercurial repository here"
+ " (.hg not found)"))
+ raise
+ d = lambda: func(ui, repo, *args, **cmdoptions)
+ else:
+ d = lambda: func(ui, *args, **cmdoptions)
+
+ # run pre-hook, and abort if it fails
+ ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
+ if ret:
+ return ret
+ ret = _runcommand(ui, options, cmd, d)
+ # run post-hook, passing command result
+ hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
+ result = ret)
+ return ret
+
+def _runcommand(ui, options, cmd, cmdfunc):
+ def checkargs():
+ try:
+ return cmdfunc()
+ except TypeError, inst:
+ # was this an argument error?
+ tb = traceback.extract_tb(sys.exc_info()[2])
+ if len(tb) != 2: # no
+ raise
+ raise ParseError(cmd, _("invalid arguments"))
+
+ if options['profile']:
+ import hotshot, hotshot.stats
+ prof = hotshot.Profile("hg.prof")
+ try:
+ try:
+ return prof.runcall(checkargs)
+ except:
+ try:
+ ui.warn(_('exception raised - generating '
+ 'profile anyway\n'))
+ except:
+ pass
+ raise
+ finally:
+ prof.close()
+ stats = hotshot.stats.load("hg.prof")
+ stats.strip_dirs()
+ stats.sort_stats('time', 'calls')
+ stats.print_stats(40)
+ elif options['lsprof']:
+ try:
+ from mercurial import lsprof
+ except ImportError:
+ raise util.Abort(_(
+ 'lsprof not available - install from '
+ 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
+ p = lsprof.Profiler()
+ p.enable(subcalls=True)
+ try:
+ return checkargs()
+ finally:
+ p.disable()
+ stats = lsprof.Stats(p.getstats())
+ stats.sort()
+ stats.pprint(top=10, file=sys.stderr, climit=5)
+ else:
+ return checkargs()
--- a/tests/test-dispatch.py Wed Aug 15 16:10:36 2007 -0500
+++ b/tests/test-dispatch.py Wed Aug 15 16:55:13 2007 -0500
@@ -1,32 +1,32 @@
import os
-from mercurial import commands
+from mercurial import dispatch
-def dispatch(cmd):
- """Simple wrapper around commands.dispatch()
+def testdispatch(cmd):
+ """Simple wrapper around dispatch.dispatch()
Prints command and result value, but does not handle quoting.
"""
print "running: %s" % (cmd,)
- result = commands.dispatch(cmd.split())
+ result = dispatch.dispatch(cmd.split())
print "result: %r" % (result,)
-dispatch("init test1")
+testdispatch("init test1")
os.chdir('test1')
# create file 'foo', add and commit
f = file('foo', 'wb')
f.write('foo\n')
f.close()
-dispatch("add foo")
-dispatch("commit -m commit1 -d 2000-01-01 foo")
+testdispatch("add foo")
+testdispatch("commit -m commit1 -d 2000-01-01 foo")
# append to file 'foo' and commit
f = file('foo', 'ab')
f.write('bar\n')
f.close()
-dispatch("commit -m commit2 -d 2000-01-02 foo")
+testdispatch("commit -m commit2 -d 2000-01-02 foo")
# check 88803a69b24 (fancyopts modified command table)
-dispatch("log -r 0")
-dispatch("log -r tip")
+testdispatch("log -r 0")
+testdispatch("log -r tip")
--- a/tests/test-ui-config Wed Aug 15 16:10:36 2007 -0500
+++ b/tests/test-ui-config Wed Aug 15 16:55:13 2007 -0500
@@ -1,10 +1,10 @@
#!/usr/bin/env python
import ConfigParser
-from mercurial import ui, util, cmdutil
+from mercurial import ui, util, dispatch
testui = ui.ui()
-parsed = cmdutil.parseconfig([
+parsed = dispatch._parseconfig([
'values.string=string value',
'values.bool1=true',
'values.bool2=false',