##// END OF EJS Templates
dispatch: replace _earlyreq*() with new fancyopts-based parser
dispatch: replace _earlyreq*() with new fancyopts-based parser

File last commit:

r35224:6e6d0a5b default
r35224:6e6d0a5b default
Show More
dispatch.py
1075 lines | 37.6 KiB | text/x-python | PythonLexer
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 # dispatch.py - command dispatching for mercurial
#
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Gregory Szorc
dispatch: use print function...
r27615 from __future__ import absolute_import, print_function
Gregory Szorc
dispatch: use absolute_import...
r25932
Augie Fackler
dispatch: offer near-edit-distance suggestions for {file,rev}set functions...
r24221 import difflib
Gregory Szorc
dispatch: use absolute_import...
r25932 import errno
Pulkit Goyal
fancyopts: switch from fancyopts.getopt.* to getopt.*...
r30576 import getopt
Gregory Szorc
dispatch: use absolute_import...
r25932 import os
import pdb
import re
import signal
import sys
import time
import traceback
from .i18n import _
from . import (
cmdutil,
Pierre-Yves David
color: load 'colortable' from extension using an 'extraloader'...
r30653 color,
Gregory Szorc
dispatch: use absolute_import...
r25932 commands,
demandimport,
encoding,
error,
extensions,
fancyopts,
Augie Fackler
dispatch: rearrange 'unknown command' code to better employ pager...
r31060 help,
Gregory Szorc
dispatch: use absolute_import...
r25932 hg,
hook,
Gregory Szorc
profiling: move profiling code from dispatch.py (API)...
r29781 profiling,
Pulkit Goyal
py3: use pycompat.sysargv in dispatch.run()...
r30468 pycompat,
Pulkit Goyal
registrar: add support for storing the type of command in func object...
r34782 registrar,
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 scmutil,
Gregory Szorc
dispatch: use absolute_import...
r25932 ui as uimod,
util,
)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Pulkit Goyal
registrar: add support for storing the type of command in func object...
r34782 unrecoverablewrite = registrar.command.unrecoverablewrite
Idan Kamara
dispatch: wrap dispatch related information in a request class...
r14438 class request(object):
Brodie Rao
cleanup: eradicate long lines
r16683 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
Jun Wu
dispatch: make request accept additional reposetups...
r32379 ferr=None, prereposetups=None):
Idan Kamara
dispatch: wrap dispatch related information in a request class...
r14438 self.args = args
Idan Kamara
dispatch: use the request to store the ui object...
r14439 self.ui = ui
Idan Kamara
dispatch: add repo to the request...
r14510 self.repo = repo
Idan Kamara
dispatch: wrap dispatch related information in a request class...
r14438
Idan Kamara
dispatch: add I/O descriptors to the request
r14613 # input/output/error streams
self.fin = fin
self.fout = fout
self.ferr = ferr
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 # remember options pre-parsed by _earlyparseopts()
Yuya Nishihara
dispatch: abort if early boolean options can't be parsed...
r35059 self.earlyoptions = {}
Jun Wu
dispatch: make request accept additional reposetups...
r32379 # reposetups which run before extensions, useful for chg to pre-fill
# low-level repo state (for example, changelog) before extensions.
self.prereposetups = prereposetups or []
Bryan O'Sullivan
ui: add special-purpose atexit functionality...
r31956 def _runexithandlers(self):
exc = None
handlers = self.ui._exithandlers
try:
while handlers:
func, args, kwargs = handlers.pop()
try:
func(*args, **kwargs)
except: # re-raises below
if exc is None:
exc = sys.exc_info()[1]
self.ui.warn(('error in exit handlers:\n'))
self.ui.traceback(force=True)
finally:
if exc is not None:
raise exc
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 def run():
"run the command in sys.argv"
Yuya Nishihara
dispatch: move initialization of sys.std* files...
r34534 _initstdio()
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 req = request(pycompat.sysargv[1:])
err = None
try:
status = (dispatch(req) or 0) & 255
Yuya Nishihara
py3: work around the scope of exception variable in dispatch.run()...
r34533 except error.StdioError as e:
err = e
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 status = -1
if util.safehasattr(req.ui, 'fout'):
try:
Yuya Nishihara
dispatch: do not close stdout and stderr, just flush() instead...
r32687 req.ui.fout.flush()
Yuya Nishihara
py3: work around the scope of exception variable in dispatch.run()...
r34533 except IOError as e:
err = e
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 status = -1
if util.safehasattr(req.ui, 'ferr'):
if err is not None and err.errno != errno.EPIPE:
Augie Fackler
python3: wrap all uses of <exception>.strerror with strtolocal...
r34024 req.ui.ferr.write('abort: %s\n' %
encoding.strtolocal(err.strerror))
Yuya Nishihara
dispatch: do not close stdout and stderr, just flush() instead...
r32687 req.ui.ferr.flush()
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 sys.exit(status & 255)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Yuya Nishihara
dispatch: move initialization of sys.std* files...
r34534 def _initstdio():
for fp in (sys.stdin, sys.stdout, sys.stderr):
util.setbinary(fp)
Augie Fackler
dispatch: offer near-edit-distance suggestions for {file,rev}set functions...
r24221 def _getsimilar(symbols, value):
sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
# The cutoff for similarity here is pretty arbitrary. It should
# probably be investigated and tweaked.
return [s for s in symbols if sim(s) > 0.6]
Bryan O'Sullivan
dispatch: report similar names consistently
r27623 def _reportsimilar(write, similar):
if len(similar) == 1:
write(_("(did you mean %s?)\n") % similar[0])
elif similar:
ss = ", ".join(sorted(similar))
write(_("(did you mean one of %s?)\n") % ss)
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039 def _formatparse(write, inst):
Augie Fackler
dispatch: offer near-edit-distance suggestions for {file,rev}set functions...
r24221 similar = []
if isinstance(inst, error.UnknownIdentifier):
# make sure to check fileset first, as revset can invoke fileset
similar = _getsimilar(inst.symbols, inst.function)
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039 if len(inst.args) > 1:
write(_("hg: parse error at %s: %s\n") %
(inst.args[1], inst.args[0]))
if (inst.args[0][0] == ' '):
write(_("unexpected leading whitespace\n"))
else:
write(_("hg: parse error: %s\n") % inst.args[0])
Bryan O'Sullivan
dispatch: report similar names consistently
r27623 _reportsimilar(write, similar)
Jun Wu
dispatch: extract common logic for handling ParseError...
r28515 if inst.hint:
write(_("(%s)\n") % inst.hint)
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039
Augie Fackler
dispatch: consolidate formatting of arguments...
r31492 def _formatargs(args):
Augie Fackler
dispatch: replace mayberepr with shellquote...
r31500 return ' '.join(util.shellquote(a) for a in args)
Augie Fackler
dispatch: consolidate formatting of arguments...
r31492
Idan Kamara
dispatch: wrap dispatch related information in a request class...
r14438 def dispatch(req):
"run the command specified in req.args"
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615 if req.ferr:
ferr = req.ferr
elif req.ui:
ferr = req.ui.ferr
else:
Yuya Nishihara
py3: bulk replace sys.stdin/out/err by util's...
r30473 ferr = util.stderr
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 try:
Idan Kamara
dispatch: use the request to store the ui object...
r14439 if not req.ui:
Yuya Nishihara
ui: factor out ui.load() to create a ui without loading configs (API)...
r30559 req.ui = uimod.ui.load()
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
if req.earlyoptions['traceback']:
Mads Kiilerich
config: give a useful hint of source for the most common command line settings...
r20788 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615
# set ui streams from the request
if req.fin:
req.ui.fin = req.fin
if req.fout:
req.ui.fout = req.fout
if req.ferr:
req.ui.ferr = req.ferr
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 except error.Abort as inst:
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615 ferr.write(_("abort: %s\n") % inst)
Benoit Boissinot
Abort: add a hint argument, printed in the next line inside parenthesis...
r11574 if inst.hint:
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615 ferr.write(_("(%s)\n") % inst.hint)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 return -1
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.ParseError as inst:
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039 _formatparse(ferr.write, inst)
Martin Geisler
dispatch: catch ConfigError while constructing ui
r9470 return -1
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615
Augie Fackler
dispatch: consolidate formatting of arguments...
r31492 msg = _formatargs(req.args)
Simon Farnsworth
mercurial: switch to util.timer for all interval timings...
r30975 starttime = util.timer()
Durham Goode
blackbox: fix recording exit codes (issue3938)...
r19229 ret = None
try:
ret = _runcatch(req)
Yuya Nishihara
error: add hint to ProgrammingError...
r32340 except error.ProgrammingError as inst:
req.ui.warn(_('** ProgrammingError: %s\n') % inst)
if inst.hint:
req.ui.warn(_('** (%s)\n') % inst.hint)
raise
Jun Wu
dispatch: take over SignalInterrupt handling from scmutil...
r32111 except KeyboardInterrupt as inst:
Yuya Nishihara
dispatch: catch KeyboardInterrupt more broadly...
r28520 try:
Jun Wu
dispatch: take over SignalInterrupt handling from scmutil...
r32111 if isinstance(inst, error.SignalInterrupt):
msg = _("killed!\n")
else:
msg = _("interrupted!\n")
req.ui.warn(msg)
Yuya Nishihara
dispatch: ignore further SIGPIPE while handling KeyboardInterrupt...
r32044 except error.SignalInterrupt:
# maybe pager would quit without consuming all the output, and
# SIGPIPE was raised. we cannot print anything in this case.
pass
Yuya Nishihara
dispatch: catch KeyboardInterrupt more broadly...
r28520 except IOError as inst:
if inst.errno != errno.EPIPE:
raise
ret = -1
Durham Goode
blackbox: fix recording exit codes (issue3938)...
r19229 finally:
Simon Farnsworth
mercurial: switch to util.timer for all interval timings...
r30975 duration = util.timer() - starttime
Jun Wu
dispatch: flush ui before returning from dispatch...
r28534 req.ui.flush()
Simon Farnsworth
ui: provide a mechanism to track and log blocked time...
r30976 if req.ui.logblockedtimes:
req.ui._blockedtimes['command_duration'] = duration * 1000
req.ui.log('uiblocked', 'ui blocked ms', **req.ui._blockedtimes)
Pulkit Goyal
py3: use %d instead of %s for integers...
r32130 req.ui.log("commandfinish", "%s exited %d after %0.2f seconds\n",
Durham Goode
blackbox: fix recording exit codes (issue3938)...
r19229 msg, ret or 0, duration)
Bryan O'Sullivan
ui: add special-purpose atexit functionality...
r31956 try:
req._runexithandlers()
except: # exiting, so no re-raises
ret = ret or -1
Yuya Nishihara
dispatch: catch KeyboardInterrupt more broadly...
r28520 return ret
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Idan Kamara
dispatch: use the request to store the ui object...
r14439 def _runcatch(req):
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 def catchterm(*args):
Matt Mackall
error: move SignalInterrupt...
r7644 raise error.SignalInterrupt
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Idan Kamara
dispatch: use the request to store the ui object...
r14439 ui = req.ui
Simon Heimberg
dispatch: ignore if signals can not be set...
r10952 try:
for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
num = getattr(signal, name, None)
if num:
signal.signal(num, catchterm)
except ValueError:
pass # happens if called in a thread
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Jun Wu
dispatch: split global error handling out so it can be reused...
r29761 def _runcatchfunc():
Augie Fackler
dispatch: protect against malicious 'hg serve --stdio' invocations (sec)...
r32050 realcmd = None
try:
cmdargs = fancyopts.fancyopts(req.args[:], commands.globalopts, {})
cmd = cmdargs[0]
aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
realcmd = aliases[0]
except (error.UnknownCommand, error.AmbiguousCommand,
IndexError, getopt.GetoptError):
# Don't handle this here. We know the command is
# invalid, but all we're worried about for now is that
# it's not a command that server operators expect to
# be safe to offer to users in a sandbox.
pass
if realcmd == 'serve' and '--stdio' in cmdargs:
# We want to constrain 'hg serve --stdio' instances pretty
# closely, as many shared-ssh access tools want to grant
# access to run *only* 'hg -R $repo serve --stdio'. We
# restrict to exactly that set of arguments, and prohibit
# any repo name that starts with '--' to prevent
# shenanigans wherein a user does something like pass
# --debugger or --config=ui.debugger=1 as a repo
# name. This used to actually run the debugger.
if (len(req.args) != 4 or
req.args[0] != '-R' or
req.args[1].startswith('--') or
req.args[2] != 'serve' or
req.args[3] != '--stdio'):
raise error.Abort(
_('potentially unsafe serve --stdio invocation: %r') %
(req.args,))
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 try:
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640 debugger = 'pdb'
debugtrace = {
Alex Gaynor
style: never use a space before a colon or comma...
r34487 'pdb': pdb.set_trace
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640 }
debugmortem = {
Alex Gaynor
style: never use a space before a colon or comma...
r34487 'pdb': pdb.post_mortem
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640 }
Sean Farley
dispatch: move command line --config argument parsing to _runcatch()...
r19639
# read --config before doing anything else
# (e.g. to change trust settings for reading .hg/hgrc)
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 cfgs = _parseconfig(req.ui, req.earlyoptions['config'])
Sean Farley
dispatch: move command line --config argument parsing to _runcatch()...
r19639
if req.repo:
# copy configs that were passed on the cmdline (--config) to
# the repo ui
Matt Mackall
check-code: check for argument passing py2.6ism
r20796 for sec, name, val in cfgs:
req.repo.ui.setconfig(sec, name, val, source='--config')
Sean Farley
dispatch: move command line --config argument parsing to _runcatch()...
r19639
Matt Mackall
debugger: mark developer-only option...
r25833 # developer config: ui.debugger
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640 debugger = ui.config("ui", "debugger")
Jordi Gutiérrez Hermoso
dispatch: only do __import__(debugger) when a debugger is requested...
r20826 debugmod = pdb
Sean Farley
dispatch: turn off custom debugger for HGPLAIN mode...
r20122 if not debugger or ui.plain():
Matt Mackall
debugger: mark developer-only option...
r25833 # if we are in HGPLAIN mode, then disable custom debugging
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640 debugger = 'pdb'
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 elif req.earlyoptions['debugger']:
Jordi Gutiérrez Hermoso
dispatch: only do __import__(debugger) when a debugger is requested...
r20826 # This import can be slow for fancy debuggers, so only
# do it when absolutely necessary, i.e. when actual
# debugging has been requested
Jordi Gutiérrez Hermoso
dispatch: disable demandimport for the --debugger option...
r25329 with demandimport.deactivated():
try:
debugmod = __import__(debugger)
except ImportError:
pass # Leave debugmod = pdb
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640
debugtrace[debugger] = debugmod.set_trace
debugmortem[debugger] = debugmod.post_mortem
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 # enter the debugger before command execution
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 if req.earlyoptions['debugger']:
Mads Kiilerich
debugger: give a little intro before entering pdb
r11495 ui.warn(_("entering debugger - "
"type c to continue starting hg or h for help\n"))
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640
if (debugger != 'pdb' and
debugtrace[debugger] == debugtrace['pdb']):
ui.warn(_("%s debugger specified "
"but its module was not found\n") % debugger)
Jordi Gutiérrez Hermoso
dispatch: use the right context manager to deactivate demandimport...
r26236 with demandimport.deactivated():
Jordi Gutiérrez Hermoso
dispatch: disable demandimport when invoking the debugger...
r26216 debugtrace[debugger]()
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 try:
Idan Kamara
dispatch: use the request to store the ui object...
r14439 return _dispatch(req)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 finally:
ui.flush()
Brodie Rao
check-code: ignore naked excepts with a "re-raise" comment...
r16705 except: # re-raises
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 # enter the debugger when we hit an exception
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 if req.earlyoptions['debugger']:
Mads Kiilerich
debugger: show traceback before entering pdb post-mortem
r11494 traceback.print_exc()
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640 debugmortem[debugger](sys.exc_info()[2])
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 raise
Yuya Nishihara
dispatch: mark callcatch() as a private function
r32040 return _callcatch(ui, _runcatchfunc)
Jun Wu
dispatch: split global error handling out so it can be reused...
r29761
Yuya Nishihara
dispatch: mark callcatch() as a private function
r32040 def _callcatch(ui, func):
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 """like scmutil.callcatch but handles more high-level exceptions about
config parsing and commands. besides, use handlecommandexception to handle
uncaught exceptions.
Jun Wu
dispatch: split global error handling out so it can be reused...
r29761 """
try:
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 return scmutil.callcatch(ui, func)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.AmbiguousCommand as inst:
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
(inst.args[0], " ".join(inst.args[1])))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.CommandError as inst:
Matt Mackall
dispatch: sort exception handlers
r7645 if inst.args[0]:
Augie Fackler
dispatch: add pagination of two more help cases...
r31266 ui.pager('help')
Augie Fackler
dispatch: convert exception payload to bytes more carefully...
r32620 msgbytes = pycompat.bytestr(inst.args[1])
ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes))
Martin Geisler
help: add -c/--command flag to only show command help (issue2799)
r14286 commands.help_(ui, inst.args[0], full=False, command=True)
Matt Mackall
dispatch: sort exception handlers
r7645 else:
Augie Fackler
dispatch: add pagination of two more help cases...
r31266 ui.pager('help')
Matt Mackall
dispatch: sort exception handlers
r7645 ui.warn(_("hg: %s\n") % inst.args[1])
commands.help_(ui, 'shortlist')
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except error.ParseError as inst:
_formatparse(ui.warn, inst)
return -1
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.UnknownCommand as inst:
Augie Fackler
dispatch: rearrange 'unknown command' code to better employ pager...
r31060 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0]
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 try:
# check if the command is in a disabled extension
# (but don't check for extensions themselves)
Yuya Nishihara
help: pass commands module by argument...
r32567 formatted = help.formattedhelp(ui, commands, inst.args[0],
unknowncmd=True)
Augie Fackler
dispatch: rearrange 'unknown command' code to better employ pager...
r31060 ui.warn(nocmdmsg)
ui.write(formatted)
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 except (error.UnknownCommand, error.Abort):
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 suggested = False
if len(inst.args) == 2:
sim = _getsimilar(inst.args[1], inst.args[0])
if sim:
Augie Fackler
dispatch: rearrange 'unknown command' code to better employ pager...
r31060 ui.warn(nocmdmsg)
Bryan O'Sullivan
dispatch: report similar names consistently
r27623 _reportsimilar(ui.warn, sim)
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 suggested = True
if not suggested:
Augie Fackler
dispatch: rearrange 'unknown command' code to better employ pager...
r31060 ui.pager('help')
ui.warn(nocmdmsg)
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 commands.help_(ui, 'shortlist')
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except IOError:
raise
Matt Mackall
dispatch: sort exception handlers
r7645 except KeyboardInterrupt:
Yuya Nishihara
dispatch: catch KeyboardInterrupt more broadly...
r28520 raise
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except: # probably re-raises
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 if not handlecommandexception(ui):
raise
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
return -1
Alexander Solovyov
add positional arguments to non-shell aliases
r14265 def aliasargs(fn, givenargs):
Jun Wu
wrapfunction: use functools.partial if possible...
r34089 args = []
# only care about alias 'args', ignore 'args' set by extensions.wrapfunction
if not util.safehasattr(fn, '_origfunc'):
args = getattr(fn, 'args', args)
Matt Mackall
alias: abort on missing positional args (issue3331)
r16294 if args:
Alexander Solovyov
add positional arguments to non-shell aliases
r14265 cmd = ' '.join(map(util.shellquote, args))
nums = []
def replacer(m):
num = int(m.group(1)) - 1
nums.append(num)
Matt Mackall
aliases: use empty string for missing position parameters (issue3331)
r16277 if num < len(givenargs):
return givenargs[num]
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('too few arguments for command alias'))
Pulkit Goyal
py3: make the regular expression bytes to prevent TypeError
r31491 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
Alexander Solovyov
add positional arguments to non-shell aliases
r14265 givenargs = [x for i, x in enumerate(givenargs)
if i not in nums]
Pulkit Goyal
py3: have a bytes version of shlex.split()...
r30678 args = pycompat.shlexsplit(cmd)
Alexander Solovyov
add positional arguments to non-shell aliases
r14265 return args + givenargs
Brendan Cully
Move alias into core
r8655
Siddharth Agarwal
alias: expand "$@" as list of parameters quoted individually (BC) (issue4200)...
r22158 def aliasinterpolate(name, args, cmd):
'''interpolate args into cmd for shell aliases
This also handles $0, $@ and "$@".
'''
# util.interpolate can't deal with "$@" (with quotes) because it's only
# built to match prefix + patterns.
replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
replacemap['$0'] = name
replacemap['$$'] = '$'
replacemap['$@'] = ' '.join(args)
# Typical Unix shells interpolate "$@" (with quotes) as all the positional
# parameters, separated out into words. Emulate the same behavior here by
# quoting the arguments individually. POSIX shells will then typically
# tokenize each argument into exactly one word.
replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
# escape '\$' for regex
Pulkit Goyal
py3: add b'' to regular expressions which are raw strings...
r35145 regex = '|'.join(replacemap.keys()).replace('$', br'\$')
Siddharth Agarwal
alias: expand "$@" as list of parameters quoted individually (BC) (issue4200)...
r22158 r = re.compile(regex)
return r.sub(lambda x: replacemap[x.group()], cmd)
Brendan Cully
Move alias into core
r8655 class cmdalias(object):
timeless
help: report source of aliases
r28828 def __init__(self, name, definition, cmdtable, source):
Brodie Rao
alias: make shadowing behavior more consistent (issue2054)...
r12039 self.name = self.cmd = name
Brodie Rao
alias: print what command is being shadowed in debug message
r12092 self.cmdname = ''
Brendan Cully
Move alias into core
r8655 self.definition = definition
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.fn = None
Jun Wu
dispatch: defer environment variable resolution in alias commands (BC)...
r29087 self.givenargs = []
Brendan Cully
Move alias into core
r8655 self.opts = []
self.help = ''
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.badalias = None
Yuya Nishihara
alias: provide "unknowncmd" flag to tell help to look for disabled command...
r22161 self.unknowncmd = False
timeless
help: report source of aliases
r28828 self.source = source
Brendan Cully
Move alias into core
r8655
try:
Brodie Rao
alias: make shadowing behavior more consistent (issue2054)...
r12039 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
for alias, e in cmdtable.iteritems():
if e is entry:
self.cmd = alias
break
Brendan Cully
Move alias into core
r8655 self.shadows = True
except error.UnknownCommand:
self.shadows = False
if not self.definition:
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.badalias = _("no definition for alias '%s'") % self.name
Brendan Cully
Move alias into core
r8655 return
Steve Losh
dispatch: add shell aliases...
r11524 if self.definition.startswith('!'):
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 self.shell = True
Steve Losh
dispatch: add shell aliases...
r11524 def fn(ui, *args):
Steve Losh
aliases: provide more flexible ways to work with shell alias arguments...
r11989 env = {'HG_ARGS': ' '.join((self.name,) + args)}
def _checkvar(m):
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 if m.groups()[0] == '$':
return m.group()
elif int(m.groups()[0]) <= len(args):
Steve Losh
aliases: provide more flexible ways to work with shell alias arguments...
r11989 return m.group()
else:
David Soria Parra
i18n: remove translation of debug messages
r14708 ui.debug("No argument found for substitution "
"of %i variable in alias '%s' definition."
Roman Sokolov
dispatch: debug message for missing arguments in shell alias...
r13393 % (int(m.groups()[0]), self.name))
Steve Losh
aliases: provide more flexible ways to work with shell alias arguments...
r11989 return ''
Pulkit Goyal
py3: add b'' to regular expressions which are raw strings...
r35145 cmd = re.sub(br'\$(\d+|\$)', _checkvar, self.definition[1:])
Siddharth Agarwal
alias: expand "$@" as list of parameters quoted individually (BC) (issue4200)...
r22158 cmd = aliasinterpolate(self.name, args, cmd)
Simon Farnsworth
dispatch: set a blockedtag when running an external alias
r31199 return ui.system(cmd, environ=env,
blockedtag='alias_%s' % self.name)
Steve Losh
dispatch: add shell aliases...
r11524 self.fn = fn
return
Yuya Nishihara
alias: handle shlex error in command aliases...
r21569 try:
Pulkit Goyal
py3: have a bytes version of shlex.split()...
r30678 args = pycompat.shlexsplit(self.definition)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except ValueError as inst:
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.badalias = (_("error in definition for alias '%s': %s")
% (self.name, inst))
Yuya Nishihara
alias: handle shlex error in command aliases...
r21569 return
Brodie Rao
alias: print what command is being shadowed in debug message
r12092 self.cmdname = cmd = args.pop(0)
Jun Wu
dispatch: defer environment variable resolution in alias commands (BC)...
r29087 self.givenargs = args
Brendan Cully
Move alias into core
r8655
Yuya Nishihara
dispatch: verify result of early command parsing...
r35063 for invalidarg in commands.earlyoptflags:
Dan Villiom Podlaski Christiansen
alias: improved diagnostic when arguments include --cwd, etc....
r11695 if _earlygetopt([invalidarg], args):
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.badalias = (_("error in definition for alias '%s': %s may "
"only be given on the command line")
% (self.name, invalidarg))
Dan Villiom Podlaski Christiansen
alias: improved diagnostic when arguments include --cwd, etc....
r11695 return
Brendan Cully
Move alias into core
r8655 try:
Nicolas Dumazet
alias: do not crash when aliased command has no usage help text
r9993 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
if len(tableentry) > 2:
self.fn, self.opts, self.help = tableentry
else:
self.fn, self.opts = tableentry
Peter Arrenbrecht
alias: improve help text for command aliases...
r9876 if self.help.startswith("hg " + cmd):
# drop prefix in old-style help lines so hg shows the alias
self.help = self.help[4 + len(cmd):]
Yuya Nishihara
alias: fixes exception when displaying translated help text...
r10564 self.__doc__ = self.fn.__doc__
Peter Arrenbrecht
alias: improve help text for command aliases...
r9876
Brendan Cully
Move alias into core
r8655 except error.UnknownCommand:
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
% (self.name, cmd))
Yuya Nishihara
alias: provide "unknowncmd" flag to tell help to look for disabled command...
r22161 self.unknowncmd = True
Brendan Cully
Move alias into core
r8655 except error.AmbiguousCommand:
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
% (self.name, cmd))
Brendan Cully
Move alias into core
r8655
Jun Wu
dispatch: defer environment variable resolution in alias commands (BC)...
r29087 @property
def args(self):
Pulkit Goyal
dispatch: use pycompat.maplist() instead of map() to get a list
r31629 args = pycompat.maplist(util.expandpath, self.givenargs)
Jun Wu
dispatch: defer environment variable resolution in alias commands (BC)...
r29087 return aliasargs(self.fn, args)
Yuya Nishihara
dispatch: make cmdalias forward command attributes to function...
r28621 def __getattr__(self, name):
Pulkit Goyal
registrar: add support for storing the type of command in func object...
r34782 adefaults = {r'norepo': True, r'cmdtype': unrecoverablewrite,
Pulkit Goyal
py3: make adefaults keys str to be compatible with getattr...
r32158 r'optionalrepo': False, r'inferrepo': False}
Yuya Nishihara
dispatch: make cmdalias forward command attributes to function...
r28621 if name not in adefaults:
raise AttributeError(name)
if self.badalias or util.safehasattr(self, 'shell'):
return adefaults[name]
return getattr(self.fn, name)
Brendan Cully
Move alias into core
r8655 def __call__(self, ui, *args, **opts):
Yuya Nishihara
alias: keep error message in "badalias" so that help can see it...
r22160 if self.badalias:
Yuya Nishihara
alias: exit from bad definition by Abort
r22164 hint = None
Yuya Nishihara
alias: provide "unknowncmd" flag to tell help to look for disabled command...
r22161 if self.unknowncmd:
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 try:
# check if the command is in a disabled extension
Yuya Nishihara
alias: show one-line hint for command provided by disabled extension...
r22163 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
Yuya Nishihara
alias: exit from bad definition by Abort
r22164 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 except error.UnknownCommand:
pass
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(self.badalias, hint=hint)
Brendan Cully
Move alias into core
r8655 if self.shadows:
Martin Geisler
Backed out changeset 1ec8bd909ac3...
r14704 ui.debug("alias '%s' shadows command '%s'\n" %
Brodie Rao
alias: print what command is being shadowed in debug message
r12092 (self.name, self.cmdname))
Brendan Cully
Move alias into core
r8655
Augie Fackler
blackbox: also log alias expansions...
r29846 ui.log('commandalias', "alias '%s' expands to '%s'\n",
self.name, self.definition)
Augie Fackler
dispatch: use safehasattr instead of hasattr
r14950 if util.safehasattr(self, 'shell'):
Steve Losh
aliases: provide more flexible ways to work with shell alias arguments...
r11989 return self.fn(ui, *args, **opts)
else:
Brodie Rao
alias: on --debug, print expansion when it has invalid arguments
r12093 try:
Yuya Nishihara
alias: fix loss of non-zero return code in command aliases...
r21556 return util.checksignature(self.fn)(ui, *args, **opts)
Brodie Rao
alias: on --debug, print expansion when it has invalid arguments
r12093 except error.SignatureError:
args = ' '.join([self.cmdname] + self.args)
Martin Geisler
Backed out changeset 1ec8bd909ac3...
r14704 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
Brodie Rao
alias: on --debug, print expansion when it has invalid arguments
r12093 raise
Brendan Cully
Move alias into core
r8655
Jun Wu
alias: make alias command lazily resolved...
r34307 class lazyaliasentry(object):
"""like a typical command entry (func, opts, help), but is lazy"""
def __init__(self, name, definition, cmdtable, source):
self.name = name
self.definition = definition
self.cmdtable = cmdtable.copy()
self.source = source
@util.propertycache
def _aliasdef(self):
return cmdalias(self.name, self.definition, self.cmdtable, self.source)
def __getitem__(self, n):
aliasdef = self._aliasdef
if n == 0:
return aliasdef
elif n == 1:
return aliasdef.opts
elif n == 2:
return aliasdef.help
else:
raise IndexError
def __iter__(self):
for i in range(3):
yield self[i]
def __len__(self):
return 3
Brendan Cully
Move alias into core
r8655 def addaliases(ui, cmdtable):
# aliases are processed after extensions have been loaded, so they
# may use extension commands. Aliases can also use other alias definitions,
# but only if they have been defined prior to the current definition.
for alias, definition in ui.configitems('alias'):
Idan Kamara
dispatch: don't rewrap aliases that have the same definition...
r15019 try:
Jun Wu
alias: make alias command lazily resolved...
r34307 if cmdtable[alias].definition == definition:
Idan Kamara
dispatch: don't rewrap aliases that have the same definition...
r15019 continue
except (KeyError, AttributeError):
# definition might not exist or it might not be a cmdalias
pass
Jun Wu
alias: test duplicated definition earlier...
r34306 source = ui.configsource('alias', alias)
Jun Wu
alias: make alias command lazily resolved...
r34307 entry = lazyaliasentry(alias, definition, cmdtable, source)
cmdtable[alias] = entry
Brendan Cully
Move alias into core
r8655
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 def _parse(ui, args):
options = {}
cmdoptions = {}
try:
args = fancyopts.fancyopts(args, commands.globalopts, options)
Pulkit Goyal
fancyopts: switch from fancyopts.getopt.* to getopt.*...
r30576 except getopt.GetoptError as inst:
Matt Mackall
error: change ParseError to CommandError
r11287 raise error.CommandError(None, inst)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
if args:
cmd, args = args[0], args[1:]
Henri Wiechers
dispatch: minor refactoring...
r9875 aliases, entry = cmdutil.findcmd(cmd, commands.table,
Yuya Nishihara
commands: parse ui.strict config item as bool
r16591 ui.configbool("ui", "strict"))
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 cmd = aliases[0]
Alexander Solovyov
add positional arguments to non-shell aliases
r14265 args = aliasargs(entry[0], args)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 defaults = ui.config("defaults", cmd)
if defaults:
Augie Fackler
dispatch: use pycompat.maplist to allow summing with args
r31502 args = pycompat.maplist(
util.expandpath, pycompat.shlexsplit(defaults)) + args
Henri Wiechers
dispatch: minor refactoring...
r9875 c = list(entry[1])
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 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:
Augie Fackler
dispatch: explicitly pass fancyopts optional arg as a keyword...
r29822 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
Pulkit Goyal
fancyopts: switch from fancyopts.getopt.* to getopt.*...
r30576 except getopt.GetoptError as inst:
Matt Mackall
error: change ParseError to CommandError
r11287 raise error.CommandError(cmd, inst)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
# separate global options back out
for o in commands.globalopts:
n = o[1]
options[n] = cmdoptions[n]
del cmdoptions[n]
Henri Wiechers
dispatch: minor refactoring...
r9875 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Matt Mackall
ui: kill updateopts...
r8137 def _parseconfig(ui, config):
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 """parse the --config options from the command line"""
Idan Kamara
dispatch: return read config options
r14753 configs = []
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 for cfg in config:
try:
Tony Tung
dispatch: strip command line options like config file options...
r28081 name, value = [cfgelem.strip()
for cfgelem in cfg.split('=', 1)]
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 section, name = name.split('.', 1)
if not section or not name:
raise IndexError
Mads Kiilerich
config: give a useful hint of source for the most common command line settings...
r20788 ui.setconfig(section, name, value, '--config')
Idan Kamara
dispatch: return read config options
r14753 configs.append((section, name, value))
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 except (IndexError, ValueError):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('malformed --config option: %r '
Bill Schroeder
dispatch: better error message for --config option
r9825 '(use --config section.name=value)') % cfg)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Idan Kamara
dispatch: return read config options
r14753 return configs
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 def _earlyparseopts(ui, args):
Yuya Nishihara
dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options...
r35180 options = {}
fancyopts.fancyopts(args, commands.globalopts, options,
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 gnu=not ui.plain('strictflags'), early=True,
Yuya Nishihara
dispatch: alias --repo to --repository while parsing early options...
r35223 optaliases={'repository': ['repo']})
Yuya Nishihara
dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options...
r35180 return options
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 def _earlygetopt(aliases, args, strip=True):
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 """Return list of values for an option (or aliases).
The values are listed in the order they appear in args.
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 The options and values are removed from args if strip=True.
Bryan O'Sullivan
dispatch: add doctests for _earlygetopt
r19098
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> args = [b'x', b'--cwd', b'foo', b'y']
>>> _earlygetopt([b'--cwd'], args), args
Bryan O'Sullivan
dispatch: add doctests for _earlygetopt
r19098 (['foo'], ['x', 'y'])
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> args = [b'x', b'--cwd=bar', b'y']
>>> _earlygetopt([b'--cwd'], args), args
Bryan O'Sullivan
dispatch: add support for --option=value to _earlygetopt...
r19099 (['bar'], ['x', 'y'])
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 >>> args = [b'x', b'--cwd=bar', b'y']
>>> _earlygetopt([b'--cwd'], args, strip=False), args
(['bar'], ['x', '--cwd=bar', 'y'])
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> args = [b'x', b'-R', b'foo', b'y']
>>> _earlygetopt([b'-R'], args), args
Bryan O'Sullivan
dispatch: add doctests for _earlygetopt
r19098 (['foo'], ['x', 'y'])
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 >>> args = [b'x', b'-R', b'foo', b'y']
>>> _earlygetopt([b'-R'], args, strip=False), args
(['foo'], ['x', '-R', 'foo', 'y'])
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> args = [b'x', b'-Rbar', b'y']
>>> _earlygetopt([b'-R'], args), args
Bryan O'Sullivan
dispatch: add doctests for _earlygetopt
r19098 (['bar'], ['x', 'y'])
Yuya Nishihara
dispatch: do not drop unpaired argument at _earlygetopt()...
r35056
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 >>> args = [b'x', b'-Rbar', b'y']
>>> _earlygetopt([b'-R'], args, strip=False), args
(['bar'], ['x', '-Rbar', 'y'])
Yuya Nishihara
dispatch: fix early parsing of short option with value like -R=foo...
r35060 >>> args = [b'x', b'-R=bar', b'y']
>>> _earlygetopt([b'-R'], args), args
(['=bar'], ['x', 'y'])
Yuya Nishihara
dispatch: do not drop unpaired argument at _earlygetopt()...
r35056 >>> args = [b'x', b'-R', b'--', b'y']
>>> _earlygetopt([b'-R'], args), args
([], ['x', '-R', '--', 'y'])
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 """
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:
Bryan O'Sullivan
dispatch: add support for --option=value to _earlygetopt...
r19099 fullarg = arg = args[pos]
Yuya Nishihara
dispatch: fix early parsing of short option with value like -R=foo...
r35060 equals = -1
if arg.startswith('--'):
equals = arg.find('=')
Bryan O'Sullivan
dispatch: add support for --option=value to _earlygetopt...
r19099 if equals > -1:
arg = arg[:equals]
if arg in aliases:
if equals > -1:
values.append(fullarg[equals + 1:])
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 if strip:
del args[pos]
argcount -= 1
else:
pos += 1
Bryan O'Sullivan
dispatch: add support for --option=value to _earlygetopt...
r19099 else:
if pos + 1 >= argcount:
# ignore and let getopt report an error if there is no value
break
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 values.append(args[pos + 1])
if strip:
del args[pos:pos + 2]
argcount -= 2
else:
pos += 2
Bryan O'Sullivan
dispatch: add support for --option=value to _earlygetopt...
r19099 elif arg[:2] in shortopts:
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 # short option can have no following space, e.g. hg log -Rfoo
Yuya Nishihara
dispatch: add option to not strip command args parsed by _earlygetopt()...
r35061 values.append(args[pos][2:])
if strip:
del args[pos]
argcount -= 1
else:
pos += 1
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 else:
pos += 1
return values
Chad Dombrova
provide pre- and post- hooks with parsed command line arguments....
r11330 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
Bill Barry
dispatch: extract command execution block into method...
r7819 # run pre-hook, and abort if it fails
Siddharth Agarwal
dispatch: print 'abort:' when a pre-command hook fails (BC)...
r19011 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
pats=cmdpats, opts=cmdoptions)
Jordi Gutiérrez Hermoso
dispatch: add fail-* family of hooks...
r29129 try:
ret = _runcommand(ui, options, cmd, d)
# run post-hook, passing command result
hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
result=ret, pats=cmdpats, opts=cmdoptions)
except Exception:
# run failure hook and re-raise
hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),
pats=cmdpats, opts=cmdoptions)
raise
Bill Barry
dispatch: extract command execution block into method...
r7819 return ret
Jun Wu
dispatch: add wd parameter to _getlocal...
r28263 def _getlocal(ui, rpath, wd=None):
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 """Return (path, local ui object) for the given target path.
Martin Geisler
check-code: find trailing whitespace
r12770
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 Takes paths in [cwd]/.hg/hgrc into account."
"""
Jun Wu
dispatch: add wd parameter to _getlocal...
r28263 if wd is None:
try:
Pulkit Goyal
py3: add os.getcwdb() to have bytes path...
r30500 wd = pycompat.getcwd()
Jun Wu
dispatch: add wd parameter to _getlocal...
r28263 except OSError as e:
raise error.Abort(_("error getting current working directory: %s") %
Augie Fackler
python3: wrap all uses of <exception>.strerror with strtolocal...
r34024 encoding.strtolocal(e.strerror))
Mads Kiilerich
dispatch: give better error message when cwd doesn't exist (issue2293)...
r11675 path = cmdutil.findrepo(wd) or ""
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 if not path:
lui = ui
Andrey Somov
improve code readability
r9436 else:
Brodie Rao
dispatch: remove superfluous try/except when reading local ui config...
r12636 lui = ui.copy()
Brodie Rao
dispatch: properly handle relative path aliases used with -R (issue2376)...
r12637 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Yuya Nishihara
dispatch: convert non-list option parsed by _earlygetopt() to string...
r35062 if rpath:
path = lui.expandpath(rpath)
Matt Mackall
ui: kill most users of parentui name and arg, replace with .copy()
r8190 lui = ui.copy()
Brodie Rao
dispatch: properly handle relative path aliases used with -R (issue2376)...
r12637 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 return path, lui
Jun Wu
dispatch: always load extensions before running shell aliases (issue5230)...
r29132 def _checkshellalias(lui, ui, args):
"""Return the function to run the shell alias, if it is required"""
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 options = {}
Steve Losh
alias: fail gracefully when invalid global options are given (issue2442)...
r12748
try:
args = fancyopts.fancyopts(args, commands.globalopts, options)
Pulkit Goyal
fancyopts: switch from fancyopts.getopt.* to getopt.*...
r30576 except getopt.GetoptError:
Steve Losh
alias: fail gracefully when invalid global options are given (issue2442)...
r12748 return
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536
if not args:
return
Jun Wu
dispatch: always load extensions before running shell aliases (issue5230)...
r29132 cmdtable = commands.table
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536
cmd = args[0]
try:
Jun Wu
dispatch: always load extensions before running shell aliases (issue5230)...
r29132 strict = ui.configbool("ui", "strict")
FUJIWARA Katsunori
dispatch: check shell alias again after loading extensions (issue4355)...
r22377 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
Steve Losh
alias: fall back to normal error handling for ambigious commands (fixes issue2475)
r12932 except (error.AmbiguousCommand, error.UnknownCommand):
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 return
cmd = aliases[0]
fn = entry[0]
Augie Fackler
dispatch: use safehasattr instead of hasattr
r14950 if cmd and util.safehasattr(fn, 'shell'):
Yuya Nishihara
dispatch: verify result of early command parsing...
r35063 # shell alias shouldn't receive early options which are consumed by hg
args = args[:]
_earlygetopt(commands.earlyoptflags, args, strip=True)
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 d = lambda: fn(ui, *args[1:])
Brodie Rao
cleanup: eradicate long lines
r16683 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
[], {})
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536
Idan Kamara
dispatch: use the request to store the ui object...
r14439 def _dispatch(req):
Idan Kamara
dispatch: wrap dispatch related information in a request class...
r14438 args = req.args
Idan Kamara
dispatch: use the request to store the ui object...
r14439 ui = req.ui
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 # check for cwd
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 cwd = req.earlyoptions['cwd']
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 if cwd:
Yuya Nishihara
dispatch: convert non-list option parsed by _earlygetopt() to string...
r35062 os.chdir(cwd)
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 rpath = req.earlyoptions['repository']
Steve Losh
alias: only allow global options before a shell alias, pass later ones through...
r12536 path, lui = _getlocal(ui, rpath)
Martin von Zweigbergk
cleanup: use set literals...
r32291 uis = {ui, lui}
Bryan O'Sullivan
dispatch: move detection of profiling earlier during startup
r30933
if req.repo:
uis.add(req.repo.ui)
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 if req.earlyoptions['profile']:
Bryan O'Sullivan
dispatch: move detection of profiling earlier during startup
r30933 for ui_ in uis:
ui_.setconfig('profiling', 'enabled', 'true', '--profile')
profile: drop maybeprofile...
r32788 profile = lui.configbool('profiling', 'enabled')
with profiling.profile(lui, enabled=profile) as profiler:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
FUJIWARA Katsunori
dispatch: remove unused _loaded...
r33053 # reposetup
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 extensions.loadall(lui)
# Propagate any changes to lui.__class__ by extensions
ui.__class__ = lui.__class__
Kirill Smelkov
dispatch: allow extensions to provide setup code...
r5828
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 # (uisetup and extsetup are handled in extensions.loadall)
Kirill Smelkov
dispatch: allow extensions to provide setup code...
r5828
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 # (reposetup is handled in hg.repository)
Martin Geisler
extensions: load and configure extensions in well-defined phases...
r9410
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 addaliases(lui, commands.table)
Brendan Cully
Move alias into core
r8655
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 # All aliases and commands are completely defined, now.
# Check abbreviation/ambiguity of shell alias.
shellaliasfn = _checkshellalias(lui, ui, args)
if shellaliasfn:
Arun Kulshreshtha
dispatch: make hg --profile wrap reposetup...
r30006 return shellaliasfn()
FUJIWARA Katsunori
dispatch: check shell alias again after loading extensions (issue4355)...
r22377
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 # check for fallback encoding
fallback = lui.config('ui', 'fallbackencoding')
if fallback:
encoding.fallbackencoding = fallback
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 fullargs = args
cmd, func, args, options, cmdoptions = _parse(lui, args)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Yuya Nishihara
dispatch: verify result of early command parsing...
r35063 if options["config"] != req.earlyoptions["config"]:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 raise error.Abort(_("option --config may not be abbreviated!"))
Yuya Nishihara
dispatch: verify result of early command parsing...
r35063 if options["cwd"] != req.earlyoptions["cwd"]:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 raise error.Abort(_("option --cwd may not be abbreviated!"))
Yuya Nishihara
dispatch: verify result of early command parsing...
r35063 if options["repository"] != req.earlyoptions["repository"]:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 raise error.Abort(_(
"option -R has to be separated from other options (e.g. not "
"-qR) and --repository may only be abbreviated as --repo!"))
Yuya Nishihara
dispatch: abort if early boolean options can't be parsed...
r35059 if options["debugger"] != req.earlyoptions["debugger"]:
raise error.Abort(_("option --debugger may not be abbreviated!"))
# don't validate --profile/--traceback, which can be enabled from now
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 if options["encoding"]:
encoding.encoding = options["encoding"]
if options["encodingmode"]:
encoding.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]))
Bryan O'Sullivan
atexit: switch to home-grown implementation
r31958 ui.atexit(print_time)
profile: support --profile in alias and abbreviated version (--prof)...
r32787 if options["profile"]:
profiler.start()
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 if options['verbose'] or options['debug'] or options['quiet']:
for opt in ('verbose', 'debug', 'quiet'):
val = str(bool(options[opt]))
Augie Fackler
dispatch: enforce bytes when converting boolean flags to config items...
r31305 if pycompat.ispy3:
val = val.encode('ascii')
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 for ui_ in uis:
ui_.setconfig('ui', opt, val, '--' + opt)
if options['traceback']:
Idan Kamara
dispatch: set global options on the request repo.ui...
r14752 for ui_ in uis:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
Idan Kamara
dispatch: make sure global options on the command line take precedence...
r14992
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 if options['noninteractive']:
for ui_ in uis:
ui_.setconfig('ui', 'interactive', 'off', '-y')
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 if cmdoptions.get('insecure', False):
for ui_ in uis:
ui_.insecureconnections = True
Yuya Nishihara
url: add --insecure option to bypass verification of ssl certificates...
r13328
FUJIWARA Katsunori
dispatch: setup color before pager for correct console information on windows...
r32404 # setup color handling before pager, because setting up pager
# might cause incorrect console information
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 coloropt = options['color']
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105 for ui_ in uis:
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 if coloropt:
ui_.setconfig('ui', 'color', coloropt, '--color')
color.setup(ui_)
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105
FUJIWARA Katsunori
dispatch: setup color before pager for correct console information on windows...
r32404 if util.parsebool(options['pager']):
FUJIWARA Katsunori
ui: enable pager always for explicit --pager=on (issue5580)...
r33622 # ui.pager() expects 'internal-always-' prefix in this case
FUJIWARA Katsunori
dispatch: setup color before pager for correct console information on windows...
r32404 ui.pager('internal-always-' + cmd)
elif options['pager'] != 'auto':
Jun Wu
dispatch: when --pager=no is passed, also disable pager on req.repo.ui...
r34639 for ui_ in uis:
ui_.disablepager()
FUJIWARA Katsunori
dispatch: setup color before pager for correct console information on windows...
r32404
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 if options['version']:
return commands.version_(ui)
if options['help']:
return commands.help_(ui, cmd, command=cmd is not None)
elif not cmd:
return commands.help_(ui, 'shortlist')
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 repo = None
cmdpats = args[:]
Augie Fackler
dispatch: stop supporting non-use of @command...
r30485 if not func.norepo:
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 # use the repo from the request only if we don't have -R
if not rpath and not cwd:
repo = req.repo
Idan Kamara
dispatch: add repo to the request...
r14510
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 if repo:
# set the descriptors of the repo ui to those of ui
repo.ui.fin = ui.fin
repo.ui.fout = ui.fout
repo.ui.ferr = ui.ferr
else:
try:
Jun Wu
dispatch: make request accept additional reposetups...
r32379 repo = hg.repository(ui, path=path,
presetupfuncs=req.prereposetups)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 if not repo.local():
raise error.Abort(_("repository '%s' is not local")
% path)
repo.ui.setconfig("bundle", "mainreporoot", repo.root,
'repo')
except error.RequirementError:
Yuya Nishihara
dispatch: error out on invalid -R path even if optionalrepo (issue4805) (BC)...
r26142 raise
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 except error.RepoError:
Yuya Nishihara
dispatch: convert non-list option parsed by _earlygetopt() to string...
r35062 if rpath: # invalid -R path
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 raise
Augie Fackler
dispatch: stop supporting non-use of @command...
r30485 if not func.optionalrepo:
if func.inferrepo and args and not path:
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 # try to infer -R from command args
Pulkit Goyal
py3: use pycompat.maplist() instead of map()...
r35150 repos = pycompat.maplist(cmdutil.findrepo, args)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 guess = repos[0]
if guess and repos.count(guess) == len(repos):
req.args = ['--repository', guess] + fullargs
Yuya Nishihara
dispatch: replace _earlyreq*() with new fancyopts-based parser
r35224 req.earlyoptions['repository'] = guess
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 return _dispatch(req)
if not path:
raise error.RepoError(_("no repository found in"
" '%s' (.hg not found)")
Pulkit Goyal
py3: use pycompat.getcwd() instead of os.getcwd()...
r30519 % pycompat.getcwd())
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 raise
if repo:
ui = repo.ui
if options['hidden']:
repo = repo.unfiltered()
args.insert(0, repo)
elif rpath:
ui.warn(_("warning: --repository ignored\n"))
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388
Augie Fackler
dispatch: consolidate formatting of arguments...
r31492 msg = _formatargs(fullargs)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 ui.log("command", '%s\n', msg)
Pulkit Goyal
py3: make keys of keyword arguments strings...
r30586 strcmdopt = pycompat.strkwargs(cmdoptions)
d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 try:
return runcommand(lui, repo, cmd, fullargs, ui, options, d,
cmdpats, cmdoptions)
finally:
if repo and repo != req.repo:
repo.close()
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
def _runcommand(ui, options, cmd, cmdfunc):
Gregory Szorc
profiling: add a context manager that no-ops if profiling isn't enabled...
r29784 """Run a command function, possibly with profiling enabled."""
Arun Kulshreshtha
dispatch: make hg --profile wrap reposetup...
r30006 try:
return cmdfunc()
except error.SignatureError:
raise error.CommandError(cmd, _('invalid arguments'))
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784
Martijn Pieters
dispatch: split out warning message generation to separate function...
r28821 def _exceptionwarning(ui):
"""Produce a warning message for the current active exception"""
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784
# For compatibility checking, we discard the portion of the hg
# version after the + on the assumption that if a "normal
# user" is running a build with a + in it the packager
# probably built from fairly close to a tag and anyone with a
# 'make local' copy of hg (where the version number can be out
# of date) will be clueful enough to notice the implausible
# version number and try updating.
ct = util.versiontuple(n=2)
worst = None, ct, ''
Jun Wu
codemod: register core configitems using a script...
r33499 if ui.config('ui', 'supportcontact') is None:
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 for name, mod in extensions.extensions():
testedwith = getattr(mod, 'testedwith', '')
Augie Fackler
dispatch: allow testedwith to be bytes or str
r31179 if pycompat.ispy3 and isinstance(testedwith, str):
testedwith = testedwith.encode(u'utf-8')
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 report = getattr(mod, 'buglink', _('the extension author.'))
if not testedwith.strip():
# We found an untested extension. It's likely the culprit.
worst = name, 'unknown', report
break
# Never blame on extensions bundled with Mercurial.
Yuya Nishihara
extensions: use ismoduleinternal() thoroughly...
r29884 if extensions.ismoduleinternal(mod):
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 continue
tested = [util.versiontuple(t, 2) for t in testedwith.split()]
if ct in tested:
continue
lower = [t for t in tested if t < ct]
nearest = max(lower or tested)
if worst[0] is None or nearest < worst[1]:
worst = name, nearest, report
if worst[0] is not None:
name, testedwith, report = worst
Augie Fackler
dispatch: allow testedwith to be bytes or str
r31179 if not isinstance(testedwith, (bytes, str)):
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 testedwith = '.'.join([str(c) for c in testedwith])
warning = (_('** Unknown exception encountered with '
'possibly-broken third-party extension %s\n'
'** which supports versions %s of Mercurial.\n'
'** Please disable %s and try your action again.\n'
'** If that fixes the bug please report it to %s\n')
% (name, testedwith, name, report))
else:
Jun Wu
codemod: register core configitems using a script...
r33499 bugtracker = ui.config('ui', 'supportcontact')
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 if bugtracker is None:
bugtracker = _("https://mercurial-scm.org/wiki/BugTracker")
warning = (_("** unknown exception encountered, "
"please report by visiting\n** ") + bugtracker + '\n')
Augie Fackler
dispatch: cope with sys.version being unicode on Python 3
r31180 if pycompat.ispy3:
sysversion = sys.version.encode(u'utf-8')
else:
sysversion = sys.version
sysversion = sysversion.replace('\n', '')
warning += ((_("** Python %s\n") % sysversion) +
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 (_("** Mercurial Distributed SCM (version %s)\n") %
util.version()) +
(_("** Extensions loaded: %s\n") %
", ".join([x[0] for x in extensions.extensions()])))
Martijn Pieters
dispatch: split out warning message generation to separate function...
r28821 return warning
def handlecommandexception(ui):
"""Produce a warning message for broken commands
Called when handling an exception; the exception is reraised if
this function returns False, ignored otherwise.
"""
warning = _exceptionwarning(ui)
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
ui.warn(warning)
return False # re-raise the exception