##// END OF EJS Templates
manifest: proxy to revlog instance instead of inheriting...
manifest: proxy to revlog instance instead of inheriting Previously, manifestrevlog inherited revlog.revlog and therefore exposed all its APIs. This inevitably resulted in consumers calling low-level revlog APIs. As part of abstracting storage, we want to formalize the interface for manifest storage. The revlog API is much too large to define as the interface. Like we did for filelog, this commit divorces the manifest class from revlog so that we can standardize on a smaller API surface. The way I went about this commit was I broke the inheritance, ran tests, and added proxies until all tests passed. Like filelog, there are a handful of attributes that don't belong on the interface. And like filelog, we'll tease these out in the future. As part of this, we formalize an interface for manifest storage and add checks that manifestrevlog conforms to the interface. Adding proxies will introduce some overhead due to extra attribute lookups and function calls. On the mozilla-unified repository: $ hg verify before: real 627.220 secs (user 525.870+0.000 sys 18.800+0.000) after: real 628.930 secs (user 532.050+0.000 sys 18.320+0.000) $ hg serve (for a clone) before: user 223.580+0.000 sys 14.270+0.000 after: user 227.720+0.000 sys 13.920+0.000 $ hg clone before: user 506.390+0.000 sys 29.720+0.000 after: user 513.080+0.000 sys 28.280+0.000 There appears to be some overhead here. But it appears to be 1-2%. I think that is an appropriate price to pay for storage abstraction, which will eventually let us have much nicer things. If the overhead is noticed in other operations (whose CPU time isn't likely dwarfed by fulltext resolution) or if we want to cut down on the overhead, we could dynamically build up a type whose methods are effectively aliased to a revlog instance's. I'm inclined to punt on that problem for now. We may have to do it for the changelog. At which point it could be implemented in a generic way and ported to filelog and manifestrevlog easily enough I would think. .. api:: manifest.manifestrevlog no longer inherits from revlog The manifestrevlog class now wraps a revlog instance instead of inheriting from revlog. Various attributes and methods on instances are no longer available. Differential Revision: https://phab.mercurial-scm.org/D4386

File last commit:

r39291:4019b454 default
r39350:7f5e6d3e default
Show More
dispatch.py
1069 lines | 38.9 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 _
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 from hgdemandimport import tracing
Gregory Szorc
dispatch: use absolute_import...
r25932 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,
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
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from .utils import (
Yuya Nishihara
procutil: bulk-replace util.std* to point to new module
r37137 procutil,
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 stringutil,
)
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
sshserver: do setbinary() by caller (API)...
r37963 initstdio()
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 with tracing.log('parse args into request'):
req = request(pycompat.sysargv[1:])
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 err = None
try:
Yuya Nishihara
dispatch: unify handling of None returned by a command function...
r38015 status = dispatch(req)
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
Gregory Szorc
dispatch: minor code refactor...
r38014
# In all cases we try to flush stdio streams.
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 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
Gregory Szorc
dispatch: minor code refactor...
r38014
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 if util.safehasattr(req.ui, 'ferr'):
Gregory Szorc
dispatch: handle IOError when writing to stderr...
r35671 try:
if err is not None and err.errno != errno.EPIPE:
req.ui.ferr.write('abort: %s\n' %
encoding.strtolocal(err.strerror))
req.ui.ferr.flush()
# There's not much we can do about an I/O error here. So (possibly)
# change the status code and move on.
except IOError:
status = -1
Yuya Nishihara
py3: silence the final IOError by closing stdout/err slightly early...
r36655
_silencestdio()
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
py3: conditionalize initialization of stdio flags...
r36654 if pycompat.ispy3:
Yuya Nishihara
sshserver: do setbinary() by caller (API)...
r37963 def initstdio():
Yuya Nishihara
py3: conditionalize initialization of stdio flags...
r36654 pass
Yuya Nishihara
py3: silence the final IOError by closing stdout/err slightly early...
r36655
def _silencestdio():
for fp in (sys.stdout, sys.stderr):
# Check if the file is okay
try:
fp.flush()
continue
except IOError:
pass
# Otherwise mark it as closed to silence "Exception ignored in"
# message emitted by the interpreter finalizer. Be careful to
Yuya Nishihara
procutil: bulk-replace util.std* to point to new module
r37137 # not close procutil.stdout, which may be a fdopen-ed file object
# and its close() actually closes the underlying file descriptor.
Yuya Nishihara
py3: silence the final IOError by closing stdout/err slightly early...
r36655 try:
fp.close()
except IOError:
pass
Yuya Nishihara
py3: conditionalize initialization of stdio flags...
r36654 else:
Yuya Nishihara
sshserver: do setbinary() by caller (API)...
r37963 def initstdio():
Yuya Nishihara
py3: conditionalize initialization of stdio flags...
r36654 for fp in (sys.stdin, sys.stdout, sys.stderr):
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 procutil.setbinary(fp)
Yuya Nishihara
dispatch: move initialization of sys.std* files...
r34534
Yuya Nishihara
py3: silence the final IOError by closing stdout/err slightly early...
r36655 def _silencestdio():
pass
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") %
Yuya Nishihara
py3: use bytestr() to coerce position carried by ParseError to string...
r36521 (pycompat.bytestr(inst.args[1]), inst.args[0]))
Yuya Nishihara
py3: use startswith() instead of slicing to detect leading whitespace
r36747 if inst.args[0].startswith(' '):
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039 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):
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 return ' '.join(procutil.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):
Yuya Nishihara
dispatch: unify handling of None returned by a command function...
r38015 """run the command specified in req.args; returns an integer status code"""
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 with tracing.log('dispatch.dispatch'):
if req.ferr:
ferr = req.ferr
elif req.ui:
ferr = req.ui.ferr
else:
ferr = procutil.stderr
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 try:
if not req.ui:
req.ui = uimod.ui.load()
req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
if req.earlyoptions['traceback']:
req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # 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
except error.Abort as inst:
ferr.write(_("abort: %s\n") % inst)
if inst.hint:
ferr.write(_("(%s)\n") % inst.hint)
return -1
except error.ParseError as inst:
_formatparse(ferr.write, inst)
return -1
Idan Kamara
dispatch: assign I/O descriptors from the request to the ui
r14615
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 msg = _formatargs(req.args)
starttime = util.timer()
ret = 1 # default of Python exit code on unhandled exception
Yuya Nishihara
dispatch: catch KeyboardInterrupt more broadly...
r28520 try:
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 ret = _runcatch(req) or 0
except error.ProgrammingError as inst:
req.ui.error(_('** ProgrammingError: %s\n') % inst)
if inst.hint:
req.ui.error(_('** (%s)\n') % inst.hint)
raise
except KeyboardInterrupt as inst:
try:
if isinstance(inst, error.SignalInterrupt):
msg = _("killed!\n")
else:
msg = _("interrupted!\n")
req.ui.error(msg)
except error.SignalInterrupt:
# maybe pager would quit without consuming all the output, and
# SIGPIPE was raised. we cannot print anything in this case.
pass
except IOError as inst:
if inst.errno != errno.EPIPE:
raise
ret = -1
finally:
duration = util.timer() - starttime
req.ui.flush()
if req.ui.logblockedtimes:
req.ui._blockedtimes['command_duration'] = duration * 1000
req.ui.log('uiblocked', 'ui blocked ms',
**pycompat.strkwargs(req.ui._blockedtimes))
req.ui.log("commandfinish", "%s exited %d after %0.2f seconds\n",
msg, ret & 255, duration)
try:
req._runexithandlers()
except: # exiting, so no re-raises
ret = ret or -1
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):
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 with tracing.log('dispatch._runcatch'):
def catchterm(*args):
raise error.SignalInterrupt
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 ui = req.ui
Augie Fackler
dispatch: protect against malicious 'hg serve --stdio' invocations (sec)...
r32050 try:
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 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
Augie Fackler
dispatch: protect against malicious 'hg serve --stdio' invocations (sec)...
r32050
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 def _runcatchfunc():
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: %s') %
(stringutil.pprint(req.args),))
Sean Farley
dispatch: move command line --config argument parsing to _runcatch()...
r19639
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 try:
debugger = 'pdb'
debugtrace = {
'pdb': pdb.set_trace
}
debugmortem = {
'pdb': pdb.post_mortem
}
Sean Farley
dispatch: move command line --config argument parsing to _runcatch()...
r19639
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # read --config before doing anything else
# (e.g. to change trust settings for reading .hg/hgrc)
cfgs = _parseconfig(req.ui, req.earlyoptions['config'])
if req.repo:
# copy configs that were passed on the cmdline (--config) to
# the repo ui
for sec, name, val in cfgs:
req.repo.ui.setconfig(sec, name, val, source='--config')
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # developer config: ui.debugger
debugger = ui.config("ui", "debugger")
debugmod = pdb
if not debugger or ui.plain():
# if we are in HGPLAIN mode, then disable custom debugging
debugger = 'pdb'
elif req.earlyoptions['debugger']:
# This import can be slow for fancy debuggers, so only
# do it when absolutely necessary, i.e. when actual
# debugging has been requested
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
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 debugtrace[debugger] = debugmod.set_trace
debugmortem[debugger] = debugmod.post_mortem
Sean Farley
dispatch: add ability to specify a custom pdb module as a debugger...
r19640
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # enter the debugger before command execution
if req.earlyoptions['debugger']:
ui.warn(_("entering debugger - "
"type c to continue starting hg or h for help\n"))
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 if (debugger != 'pdb' and
debugtrace[debugger] == debugtrace['pdb']):
ui.warn(_("%s debugger specified "
"but its module was not found\n") % debugger)
with demandimport.deactivated():
debugtrace[debugger]()
try:
return _dispatch(req)
finally:
ui.flush()
except: # re-raises
# enter the debugger when we hit an exception
if req.earlyoptions['debugger']:
traceback.print_exc()
debugmortem[debugger](sys.exc_info()[2])
raise
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:
ui.warn(_("hg: %s\n") % inst.args[1])
Martin von Zweigbergk
dispatch: show a short error message when invalid global option given...
r38824 ui.warn(_("(use 'hg help -v' for a list of global options)\n"))
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.warn(nocmdmsg)
Martin von Zweigbergk
dispatch: don't show list of commands on bogus command...
r38823 ui.warn(_("(use 'hg help' for a list of commands)\n"))
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:
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 cmd = ' '.join(map(procutil.shellquote, args))
Alexander Solovyov
add positional arguments to non-shell aliases
r14265
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.
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 replacemap['"$@"'] = ' '.join(procutil.shellquote(arg) for arg in args)
Siddharth Agarwal
alias: expand "$@" as list of parameters quoted individually (BC) (issue4200)...
r22158 # 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):
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 def __init__(self, ui, 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('!'):
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 shdef = self.definition[1:]
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 "
Kyle Lippincott
debug: add newlines at the end of three locations that appear to need it...
r35482 "of %i variable in alias '%s' definition.\n"
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 ''
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef)
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
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 self._populatehelp(ui, name, shdef, self.fn)
Steve Losh
dispatch: add shell aliases...
r11524 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")
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 % (self.name, stringutil.forcebytestr(inst)))
Yuya Nishihara
alias: handle shlex error in command aliases...
r21569 return
Yuya Nishihara
dispatch: replace _earlygetopt(strip=True) with new parser...
r35225 earlyopts, args = _earlysplitopts(args)
if earlyopts:
self.badalias = (_("error in definition for alias '%s': %s may "
"only be given on the command line")
Pulkit Goyal
py3: use pycompat.ziplist instead of zip...
r35960 % (self.name, '/'.join(pycompat.ziplist(*earlyopts)
[0])))
Yuya Nishihara
dispatch: replace _earlygetopt(strip=True) with new parser...
r35225 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
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:
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 self.fn, self.opts, cmdhelp = tableentry
Nicolas Dumazet
alias: do not crash when aliased command has no usage help text
r9993 else:
self.fn, self.opts = tableentry
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 cmdhelp = None
Nicolas Dumazet
alias: do not crash when aliased command has no usage help text
r9993
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
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
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
Yuya Nishihara
alias: reject non-ascii characters in user help/doc strings...
r37157 # confine strings to be passed to i18n.gettext()
cfg = {}
for k in ('doc', 'help'):
v = ui.config('alias', '%s:%s' % (name, k), None)
if v is None:
continue
if not encoding.isasciistr(v):
self.badalias = (_("non-ASCII character in alias definition "
"'%s:%s'") % (name, k))
return
cfg[k] = v
self.help = cfg.get('help', defaulthelp or '')
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 if self.help and 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
py3: bytes/unicode dance on __doc__ of cmdalias
r37158 doc = cfg.get('doc', pycompat.getdoc(fn))
if doc is not None:
doc = pycompat.sysstr(doc)
self.__doc__ = doc
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152
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):
Gregory Szorc
registrar: replace "cmdtype" with an intent-based mechanism (API)...
r37734 adefaults = {r'norepo': True, r'intents': set(),
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"""
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 def __init__(self, ui, name, definition, cmdtable, source):
self.ui = ui
Jun Wu
alias: make alias command lazily resolved...
r34307 self.name = name
self.definition = definition
self.cmdtable = cmdtable.copy()
self.source = source
@util.propertycache
def _aliasdef(self):
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 return cmdalias(self.ui, self.name, self.definition, self.cmdtable,
self.source)
Jun Wu
alias: make alias command lazily resolved...
r34307
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.
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 for alias, definition in ui.configitems('alias', ignoresub=True):
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)
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
Jun Wu
alias: make alias command lazily resolved...
r34307 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:
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 raise error.CommandError(None, stringutil.forcebytestr(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:
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 raise error.CommandError(cmd, stringutil.forcebytestr(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 '
Yuya Nishihara
py3: fix some unicode madness in global exception catcher
r36659 '(use --config section.name=value)')
% pycompat.bytestr(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: replace _earlygetopt(strip=True) with new parser...
r35225 def _earlysplitopts(args):
"""Split args into a list of possible early options and remainder args"""
shortoptions = 'R:'
# TODO: perhaps 'debugger' should be included
longoptions = ['cwd=', 'repository=', 'repo=', 'config=']
return fancyopts.earlygetopt(args, shortoptions, longoptions,
gnu=True, keepsep=True)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
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
Yuya Nishihara
dispatch: replace _earlygetopt(strip=True) with new parser...
r35225 _earlyopts, args = _earlysplitopts(args)
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)
Boris Feld
debug: process --debug flag earlier...
r38552 if (req.earlyoptions['verbose'] or req.earlyoptions['debug']
or req.earlyoptions['quiet']):
for opt in ('verbose', 'debug', 'quiet'):
val = pycompat.bytestr(bool(req.earlyoptions[opt]))
for ui_ in uis:
ui_.setconfig('ui', opt, val, '--' + opt)
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
Boris Feld
debug: process --debug flag earlier...
r38552 # if abbreviated version of this were used, take them in account, now
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 if options['verbose'] or options['debug'] or options['quiet']:
for opt in ('verbose', 'debug', 'quiet'):
Boris Feld
debug: process --debug flag earlier...
r38552 if options[opt] == req.earlyoptions[opt]:
continue
Yuya Nishihara
py3: replace "if ispy3" by pycompat.bytestr()
r35916 val = pycompat.bytestr(bool(options[opt]))
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
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 if stringutil.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,
Gregory Szorc
hg: pass command intents to repo/peer creation (API)...
r37735 presetupfuncs=req.prereposetups,
intents=func.intents)
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():
Yuya Nishihara
py3: replace "if ispy3" by pycompat.sysbytes() or util.forcebytestr()
r35917 # 'testedwith' should be bytes, but not all extensions are ported
# to py3 and we don't want UnicodeException because of that.
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 testedwith = stringutil.forcebytestr(getattr(mod, 'testedwith', ''))
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)):
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 testedwith = '.'.join([stringutil.forcebytestr(c)
for c in testedwith])
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 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')
Pulkit Goyal
py3: convert the report to bytes...
r38045 % (name, testedwith, name, stringutil.forcebytestr(report)))
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 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')
Yuya Nishihara
py3: replace "if ispy3" by pycompat.sysbytes() or util.forcebytestr()
r35917 sysversion = pycompat.sysbytes(sys.version).replace('\n', '')
Augie Fackler
dispatch: cope with sys.version being unicode on Python 3
r31180 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)
Gregory Szorc
py3: convert traceback representation to bytes when logging...
r36141 ui.log("commandexception", "%s\n%s\n", warning,
pycompat.sysbytes(traceback.format_exc()))
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 ui.warn(warning)
return False # re-raise the exception