# HG changeset patch # User Matt Mackall # Date 1187214913 18000 # Node ID 18a9fbb5cd78d821c2956f1d47329b5f8e48490a # Parent 92236732d5a126e8200b1f42ecffca167f94797a 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 diff --git a/hg b/hg --- a/hg +++ b/hg @@ -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() diff --git a/hgext/alias.py b/hgext/alias.py --- a/hgext/alias.py +++ b/hgext/alias.py @@ -42,7 +42,7 @@ class lazycommand(object): 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(' '): diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -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 @@ class UnknownCommand(Exception): """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 @@ def findpossible(ui, cmd): """ 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 @@ def findpossible(ui, cmd): 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 @@ def findcmd(ui, cmd): 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: diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -9,7 +9,7 @@ import demandimport; demandimport.enable 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 @@ def debugcomplete(ui, cmd='', **opts): 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 @@ def debugcomplete(ui, cmd='', **opts): 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 @@ def help_(ui, name=None, with_version=Fa 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 @@ extensions.commandtable = table 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:])) diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py new file mode 100644 --- /dev/null +++ b/mercurial/dispatch.py @@ -0,0 +1,390 @@ +# dispatch.py - command dispatching for mercurial +# +# Copyright 2005-2007 Matt Mackall +# +# 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() diff --git a/tests/test-dispatch.py b/tests/test-dispatch.py --- a/tests/test-dispatch.py +++ b/tests/test-dispatch.py @@ -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") diff --git a/tests/test-ui-config b/tests/test-ui-config --- a/tests/test-ui-config +++ b/tests/test-ui-config @@ -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',