##// END OF EJS Templates
lock: pass "success" boolean to _afterlock callbacks...
lock: pass "success" boolean to _afterlock callbacks This lets the callback decide if it should actually run or not. I suspect that most callbacks (and hooks) *should not* run in this scenario, but I'm trying to not break any existing behavior. `persistmanifestcache`, however, seems actively dangerous to run: we just encountered an exception and the repo is in an unknown state (hopefully a consistent one due to transactions, but this is not 100% guaranteed), and the data we cache may be based on this unknown state. This was observed by our users since we wrap some of the functions that persistmanifestcache calls and it expects that the repo object is in a certain state that we'd set up earlier. If the user hits ctrl-c before we establish that state, we end up crashing there. I'm going to make that extension resilient to this issue, but figured it might be a common issue and should be handled here as well instead of just working around the issue. Differential Revision: https://phab.mercurial-scm.org/D7459

File last commit:

r44105:ac8fd215 default
r44167:4b065b01 default
Show More
dispatch.py
1283 lines | 42.0 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 _
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from .pycompat import getattr
Gregory Szorc
dispatch: use absolute_import...
r25932
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,
rdamazio@google.com
help: displaying documented aliases by default...
r40450 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
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,
)
Augie Fackler
formatting: blacken the codebase...
r43346
Idan Kamara
dispatch: wrap dispatch related information in a request class...
r14438 class request(object):
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
args,
ui=None,
repo=None,
fin=None,
fout=None,
ferr=None,
fmsg=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: pass around ui.fmsg channel...
r40623 # separate stream for status/error messages
self.fmsg = fmsg
Idan Kamara
dispatch: add I/O descriptors to the request
r14613
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 []
Boris Feld
logtoprocess: sends the canonical command name to the subprocess...
r40438 # store the parsed and canonical command
self.canonical_command = None
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)
Augie Fackler
formatting: blacken the codebase...
r43346 except: # re-raises below
Bryan O'Sullivan
ui: add special-purpose atexit functionality...
r31956 if exc is None:
exc = sys.exc_info()[1]
Augie Fackler
cleanup: mark some ui.(status|note|warn|write) calls as not needing i18n...
r43350 self.ui.warnnoi18n(b'error in exit handlers:\n')
Bryan O'Sullivan
ui: add special-purpose atexit functionality...
r31956 self.ui.traceback(force=True)
finally:
if exc is not None:
raise exc
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 def run():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"run the command in sys.argv"
Yuya Nishihara
sshserver: do setbinary() by caller (API)...
r37963 initstdio()
Augie Fackler
cleanup: hgdemandimport.tracing accepts strings, not bytes...
r43532 with tracing.log('parse args into request'):
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if util.safehasattr(req.ui, b'fout'):
Augie Fackler
dispatch: add some assertions to give pytype a helping hand...
r44105 assert req.ui is not None # help pytype
assert req.ui.fout is not None # help pytype
Bryan O'Sullivan
stdio: catch StdioError in dispatch.run and clean up appropriately...
r31960 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if util.safehasattr(req.ui, b'ferr'):
Augie Fackler
dispatch: add some assertions to give pytype a helping hand...
r44105 assert req.ui is not None # help pytype
assert req.ui.ferr is not None # help pytype
Gregory Szorc
dispatch: handle IOError when writing to stderr...
r35671 try:
if err is not None and err.errno != errno.EPIPE:
Augie Fackler
formatting: blacken the codebase...
r43346 req.ui.ferr.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'abort: %s\n' % encoding.strtolocal(err.strerror)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
dispatch: handle IOError when writing to stderr...
r35671 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
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
py3: conditionalize initialization of stdio flags...
r36654 if pycompat.ispy3:
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
py3: conditionalize initialization of stdio flags...
r36654 else:
Augie Fackler
formatting: blacken the codebase...
r43346
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
formatting: blacken the codebase...
r43346
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]
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
dispatch: report similar names consistently
r27623 def _reportsimilar(write, similar):
if len(similar) == 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 write(_(b"(did you mean %s?)\n") % similar[0])
Bryan O'Sullivan
dispatch: report similar names consistently
r27623 elif similar:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ss = b", ".join(sorted(similar))
write(_(b"(did you mean one of %s?)\n") % ss)
Bryan O'Sullivan
dispatch: report similar names consistently
r27623
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: blacken the codebase...
r43346 write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"hg: parse error at %s: %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (pycompat.bytestr(inst.args[1]), inst.args[0])
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if inst.args[0].startswith(b' '):
write(_(b"unexpected leading whitespace\n"))
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 write(_(b"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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 write(_(b"(%s)\n") % inst.hint)
Augie Fackler
dispatch: consolidate formatting of ParseErrors
r24039
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
dispatch: consolidate formatting of arguments...
r31492 def _formatargs(args):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b' '.join(procutil.shellquote(a) for a in args)
Augie Fackler
dispatch: consolidate formatting of arguments...
r31492
Augie Fackler
formatting: blacken the codebase...
r43346
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
cleanup: hgdemandimport.tracing accepts strings, not bytes...
r43532 with tracing.log('dispatch.dispatch'):
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 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))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if req.earlyoptions[b'traceback']:
req.ui.setconfig(b'ui', b'traceback', b'on', b'--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
Yuya Nishihara
dispatch: pass around ui.fmsg channel...
r40623 if req.fmsg:
req.ui.fmsg = req.fmsg
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 except error.Abort as inst:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ferr.write(_(b"abort: %s\n") % inst)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 if inst.hint:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ferr.write(_(b"(%s)\n") % inst.hint)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 req.ui.error(_(b'** ProgrammingError: %s\n') % inst)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 if inst.hint:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 req.ui.error(_(b'** (%s)\n') % inst.hint)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 raise
except KeyboardInterrupt as inst:
try:
if isinstance(inst, error.SignalInterrupt):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b"killed!\n")
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b"interrupted!\n")
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 req.ui._blockedtimes[b'command_duration'] = duration * 1000
Augie Fackler
formatting: blacken the codebase...
r43346 req.ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'uiblocked',
b'ui blocked ms\n',
Augie Fackler
formatting: blacken the codebase...
r43346 **pycompat.strkwargs(req.ui._blockedtimes)
)
Boris Feld
logtoprocess: update commandfinish options arguments...
r40687 return_code = ret & 255
req.ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"commandfinish",
b"%s exited %d after %0.2f seconds\n",
Boris Feld
logtoprocess: update commandfinish options arguments...
r40687 msg,
return_code,
duration,
return_code=return_code,
duration=duration,
canonical_command=req.canonical_command,
)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 try:
req._runexithandlers()
Augie Fackler
formatting: blacken the codebase...
r43346 except: # exiting, so no re-raises
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 ret = ret or -1
return ret
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
formatting: blacken the codebase...
r43346
Idan Kamara
dispatch: use the request to store the ui object...
r14439 def _runcatch(req):
Augie Fackler
cleanup: hgdemandimport.tracing accepts strings, not bytes...
r43532 with tracing.log('dispatch._runcatch'):
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 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
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for name in b'SIGBREAK', b'SIGHUP', b'SIGTERM':
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 num = getattr(signal, name, None)
if num:
signal.signal(num, catchterm)
except ValueError:
Augie Fackler
formatting: blacken the codebase...
r43346 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(
Augie Fackler
formatting: blacken the codebase...
r43346 req.args[:], commands.globalopts, {}
)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 cmd = cmdargs[0]
aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
realcmd = aliases[0]
Augie Fackler
formatting: blacken the codebase...
r43346 except (
error.UnknownCommand,
error.AmbiguousCommand,
IndexError,
getopt.GetoptError,
):
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if realcmd == b'serve' and b'--stdio' in cmdargs:
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # 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.
Augie Fackler
formatting: blacken the codebase...
r43346 if (
len(req.args) != 4
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 or req.args[0] != b'-R'
or req.args[1].startswith(b'--')
or req.args[2] != b'serve'
or req.args[3] != b'--stdio'
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'potentially unsafe serve --stdio invocation: %s')
Augie Fackler
formatting: blacken the codebase...
r43346 % (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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 debugger = b'pdb'
debugtrace = {b'pdb': pdb.set_trace}
debugmortem = {b'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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cfgs = _parseconfig(req.ui, req.earlyoptions[b'config'])
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291
if req.repo:
# copy configs that were passed on the cmdline (--config) to
# the repo ui
for sec, name, val in cfgs:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 req.repo.ui.setconfig(
sec, name, val, source=b'--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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 debugger = ui.config(b"ui", b"debugger")
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 debugmod = pdb
if not debugger or ui.plain():
# if we are in HGPLAIN mode, then disable custom debugging
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 debugger = b'pdb'
elif req.earlyoptions[b'debugger']:
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # 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:
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if req.earlyoptions[b'debugger']:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"entering debugger - "
b"type c to continue starting hg or h for help\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
formatting: blacken the codebase...
r43346 if (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 debugger != b'pdb'
and debugtrace[debugger] == debugtrace[b'pdb']
Augie Fackler
formatting: blacken the codebase...
r43346 ):
ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"%s debugger specified "
b"but its module was not found\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% debugger
)
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 with demandimport.deactivated():
debugtrace[debugger]()
try:
return _dispatch(req)
finally:
ui.flush()
Augie Fackler
formatting: blacken the codebase...
r43346 except: # re-raises
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 # enter the debugger when we hit an exception
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if req.earlyoptions[b'debugger']:
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 traceback.print_exc()
debugmortem[debugger](sys.exc_info()[2])
raise
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
dispatch: have dispatch.dispatch and dispatch._runcatch emit trace events...
r39291 return _callcatch(ui, _runcatchfunc)
Jun Wu
dispatch: split global error handling out so it can be reused...
r29761
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"hg: command '%s' is ambiguous:\n %s\n")
% (inst.args[0], b" ".join(inst.args[1]))
Augie Fackler
formatting: blacken the codebase...
r43346 )
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
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.pager(b'help')
Augie Fackler
dispatch: convert exception payload to bytes more carefully...
r32620 msgbytes = pycompat.bytestr(inst.args[1])
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b"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
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b"hg: %s\n") % inst.args[1])
ui.warn(_(b"(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
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 nocmdmsg = _(b"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)
Augie Fackler
formatting: blacken the codebase...
r43346 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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b"(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
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not util.safehasattr(fn, b'_origfunc'):
Jun Wu
wrapfunction: use functools.partial if possible...
r34089 args = getattr(fn, 'args', args)
Matt Mackall
alias: abort on missing positional args (issue3331)
r16294 if args:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmd = b' '.join(map(procutil.shellquote, args))
Alexander Solovyov
add positional arguments to non-shell aliases
r14265
nums = []
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
add positional arguments to non-shell aliases
r14265 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]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'too few arguments for command alias'))
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
py3: make the regular expression bytes to prevent TypeError
r31491 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346
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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 replacemap = dict((b'$%d' % (i + 1), arg) for i, arg in enumerate(args))
replacemap[b'$0'] = name
replacemap[b'$$'] = b'$'
replacemap[b'$@'] = b' '.join(args)
Siddharth Agarwal
alias: expand "$@" as list of parameters quoted individually (BC) (issue4200)...
r22158 # 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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 replacemap[b'"$@"'] = b' '.join(procutil.shellquote(arg) for arg in args)
Siddharth Agarwal
alias: expand "$@" as list of parameters quoted individually (BC) (issue4200)...
r22158 # escape '\$' for regex
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 regex = b'|'.join(replacemap.keys()).replace(b'$', 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)
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.cmdname = b''
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 = []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.help = b''
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)
Gregory Szorc
py3: finish porting iteritems() to pycompat and remove source transformer...
r43376 for alias, e in pycompat.iteritems(cmdtable):
Brodie Rao
alias: make shadowing behavior more consistent (issue2054)...
r12039 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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.badalias = _(b"no definition for alias '%s'") % self.name
Brendan Cully
Move alias into core
r8655 return
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.definition.startswith(b'!'):
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
Augie Fackler
formatting: blacken the codebase...
r43346
Steve Losh
dispatch: add shell aliases...
r11524 def fn(ui, *args):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 env = {b'HG_ARGS': b' '.join((self.name,) + args)}
Augie Fackler
formatting: blacken the codebase...
r43346
Steve Losh
aliases: provide more flexible ways to work with shell alias arguments...
r11989 def _checkvar(m):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if m.groups()[0] == b'$':
Roman Sokolov
dispatch: support for $ escaping in shell-alias definition...
r13392 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:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"No argument found for substitution "
b"of %i variable in alias '%s' definition.\n"
Augie Fackler
formatting: blacken the codebase...
r43346 % (int(m.groups()[0]), self.name)
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b''
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: blacken the codebase...
r43346 return ui.system(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmd, environ=env, blockedtag=b'alias_%s' % self.name
Augie Fackler
formatting: blacken the codebase...
r43346 )
Steve Losh
dispatch: add shell aliases...
r11524 self.fn = fn
rdamazio@google.com
help: displaying documented aliases by default...
r40450 self.alias = True
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.badalias = _(b"error in definition for alias '%s': %s") % (
Augie Fackler
formatting: blacken the codebase...
r43346 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:
Augie Fackler
formatting: blacken the codebase...
r43346 self.badalias = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"error in definition for alias '%s': %s may "
b"only be given on the command line"
) % (self.name, b'/'.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
rdamazio@google.com
help: displaying documented aliases by default...
r40450 self.alias = True
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.badalias = _(
b"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:
Augie Fackler
formatting: blacken the codebase...
r43346 self.badalias = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"alias '%s' resolves to ambiguous command '%s'"
Augie Fackler
formatting: blacken the codebase...
r43346 ) % (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 = {}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for k in (b'doc', b'help', b'category'):
v = ui.config(b'alias', b'%s:%s' % (name, k), None)
Yuya Nishihara
alias: reject non-ascii characters in user help/doc strings...
r37157 if v is None:
continue
if not encoding.isasciistr(v):
Augie Fackler
formatting: blacken the codebase...
r43346 self.badalias = _(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 b"non-ASCII character in alias definition '%s:%s'"
Augie Fackler
formatting: blacken the codebase...
r43346 ) % (name, k)
Yuya Nishihara
alias: reject non-ascii characters in user help/doc strings...
r37157 return
cfg[k] = v
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.help = cfg.get(b'help', defaulthelp or b'')
if self.help and self.help.startswith(b"hg " + cmd):
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152 # drop prefix in old-style help lines so hg shows the alias
Augie Fackler
formatting: blacken the codebase...
r43346 self.help = self.help[4 + len(cmd) :]
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.owndoc = b'doc' in cfg
doc = cfg.get(b'doc', pycompat.getdoc(fn))
Yuya Nishihara
py3: bytes/unicode dance on __doc__ of cmdalias
r37158 if doc is not None:
doc = pycompat.sysstr(doc)
self.__doc__ = doc
Rodrigo Damazio
help: supporting both help and doc for aliases...
r37152
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.helpcategory = cfg.get(
b'category', registrar.command.CATEGORY_NONE
)
rdamazio@google.com
help: displaying documented aliases by default...
r40450
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):
Augie Fackler
formatting: blacken the codebase...
r43346 adefaults = {
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 'norepo': True,
'intents': set(),
'optionalrepo': False,
'inferrepo': False,
Augie Fackler
formatting: blacken the codebase...
r43346 }
Yuya Nishihara
dispatch: make cmdalias forward command attributes to function...
r28621 if name not in adefaults:
raise AttributeError(name)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.badalias or util.safehasattr(self, b'shell'):
Yuya Nishihara
dispatch: make cmdalias forward command attributes to function...
r28621 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]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 hint = _(b"'%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:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"alias '%s' shadows command '%s'\n" % (self.name, self.cmdname)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Brendan Cully
Move alias into core
r8655
Augie Fackler
formatting: blacken the codebase...
r43346 ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'commandalias',
b"alias '%s' expands to '%s'\n",
Augie Fackler
formatting: blacken the codebase...
r43346 self.name,
self.definition,
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if util.safehasattr(self, b'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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args = b' '.join([self.cmdname] + self.args)
ui.debug(b"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
Augie Fackler
formatting: blacken the codebase...
r43346
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
rdamazio@google.com
help: displaying documented aliases by default...
r40450 self.alias = True
Jun Wu
alias: make alias command lazily resolved...
r34307
@util.propertycache
def _aliasdef(self):
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346
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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for alias, definition in ui.configitems(b'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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 source = ui.configsource(b'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
Augie Fackler
formatting: blacken the codebase...
r43346
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:]
Augie Fackler
formatting: blacken the codebase...
r43346 aliases, entry = cmdutil.findcmd(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmd, commands.table, ui.configbool(b"ui", b"strict")
Augie Fackler
formatting: blacken the codebase...
r43346 )
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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 defaults = ui.config(b"defaults", cmd)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 if defaults:
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 name, value = [cfgelem.strip() for cfgelem in cfg.split(b'=', 1)]
section, name = name.split(b'.', 1)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 if not section or not name:
raise IndexError
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.setconfig(section, name, value, b'--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):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'malformed --config option: %r '
b'(use --config section.name=value)'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% pycompat.bytestr(cfg)
)
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Idan Kamara
dispatch: return read config options
r14753 return configs
Augie Fackler
formatting: blacken the codebase...
r43346
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 = {}
Augie Fackler
formatting: blacken the codebase...
r43346 fancyopts.fancyopts(
args,
commands.globalopts,
options,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 gnu=not ui.plain(b'strictflags'),
Augie Fackler
formatting: blacken the codebase...
r43346 early=True,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 optaliases={b'repository': [b'repo']},
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
dispatch: add HGPLAIN=+strictflags to restrict early parsing of global options...
r35180 return options
Augie Fackler
formatting: blacken the codebase...
r43346
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"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 shortoptions = b'R:'
Yuya Nishihara
dispatch: replace _earlygetopt(strip=True) with new parser...
r35225 # TODO: perhaps 'debugger' should be included
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 longoptions = [b'cwd=', b'repository=', b'repo=', b'config=']
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346 hook.hook(
lui,
repo,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"pre-%s" % cmd,
Augie Fackler
formatting: blacken the codebase...
r43346 True,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args=b" ".join(fullargs),
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: blacken the codebase...
r43346 hook.hook(
lui,
repo,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"post-%s" % cmd,
Augie Fackler
formatting: blacken the codebase...
r43346 False,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args=b" ".join(fullargs),
Augie Fackler
formatting: blacken the codebase...
r43346 result=ret,
pats=cmdpats,
opts=cmdoptions,
)
Jordi Gutiérrez Hermoso
dispatch: add fail-* family of hooks...
r29129 except Exception:
# run failure hook and re-raise
Augie Fackler
formatting: blacken the codebase...
r43346 hook.hook(
lui,
repo,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"fail-%s" % cmd,
Augie Fackler
formatting: blacken the codebase...
r43346 False,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args=b" ".join(fullargs),
Augie Fackler
formatting: blacken the codebase...
r43346 pats=cmdpats,
opts=cmdoptions,
)
Jordi Gutiérrez Hermoso
dispatch: add fail-* family of hooks...
r29129 raise
Bill Barry
dispatch: extract command execution block into method...
r7819 return ret
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Matt Harbison
py3: rename pycompat.getcwd() to encoding.getcwd() (API)...
r39843 wd = encoding.getcwd()
Jun Wu
dispatch: add wd parameter to _getlocal...
r28263 except OSError as e:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"error getting current working directory: %s")
Augie Fackler
formatting: blacken the codebase...
r43346 % encoding.strtolocal(e.strerror)
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 path = cmdutil.findrepo(wd) or b""
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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lui.readconfig(os.path.join(path, b".hg", b"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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lui.readconfig(os.path.join(path, b".hg", b"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
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 strict = ui.configbool(b"ui", b"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
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if cmd and util.safehasattr(fn, b'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:])
Augie Fackler
formatting: blacken the codebase...
r43346 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cwd = req.earlyoptions[b'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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 rpath = req.earlyoptions[b'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)
Augie Fackler
formatting: blacken the codebase...
r43346 if (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 req.earlyoptions[b'verbose']
or req.earlyoptions[b'debug']
or req.earlyoptions[b'quiet']
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for opt in (b'verbose', b'debug', b'quiet'):
Boris Feld
debug: process --debug flag earlier...
r38552 val = pycompat.bytestr(bool(req.earlyoptions[opt]))
for ui_ in uis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui_.setconfig(b'ui', opt, val, b'--' + opt)
Boris Feld
debug: process --debug flag earlier...
r38552
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if req.earlyoptions[b'profile']:
Bryan O'Sullivan
dispatch: move detection of profiling earlier during startup
r30933 for ui_ in uis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui_.setconfig(b'profiling', b'enabled', b'true', b'--profile')
Bryan O'Sullivan
dispatch: move detection of profiling earlier during startup
r30933
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 profile = lui.configbool(b'profiling', b'enabled')
profile: drop maybeprofile...
r32788 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:
Yuya Nishihara
extensions: add "uipopulate" hook, called per instance, not per process...
r40760 # no additional configs will be set, set up the ui instances
for ui_ in uis:
extensions.populateui(ui_)
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fallback = lui.config(b'ui', b'fallbackencoding')
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 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
Boris Feld
logtoprocess: sends the canonical command name to the subprocess...
r40438 # store the canonical command name in request object for later access
req.canonical_command = cmd
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b"config"] != req.earlyoptions[b"config"]:
raise error.Abort(_(b"option --config may not be abbreviated!"))
if options[b"cwd"] != req.earlyoptions[b"cwd"]:
raise error.Abort(_(b"option --cwd may not be abbreviated!"))
if options[b"repository"] != req.earlyoptions[b"repository"]:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"option -R has to be separated from other options (e.g. not "
b"-qR) and --repository may only be abbreviated as --repo!"
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b"debugger"] != req.earlyoptions[b"debugger"]:
raise error.Abort(_(b"option --debugger may not be abbreviated!"))
Yuya Nishihara
dispatch: abort if early boolean options can't be parsed...
r35059 # don't validate --profile/--traceback, which can be enabled from now
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b"encoding"]:
encoding.encoding = options[b"encoding"]
if options[b"encodingmode"]:
encoding.encodingmode = options[b"encodingmode"]
if options[b"time"]:
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 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
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 s = get_times()
Augie Fackler
formatting: blacken the codebase...
r43346
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 def print_time():
t = get_times()
ui.warn(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (
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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b"profile"]:
profile: support --profile in alias and abbreviated version (--prof)...
r32787 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b'verbose'] or options[b'debug'] or options[b'quiet']:
for opt in (b'verbose', b'debug', b'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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui_.setconfig(b'ui', opt, val, b'--' + opt)
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b'traceback']:
Idan Kamara
dispatch: set global options on the request repo.ui...
r14752 for ui_ in uis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui_.setconfig(b'ui', b'traceback', b'on', b'--traceback')
Idan Kamara
dispatch: make sure global options on the command line take precedence...
r14992
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b'noninteractive']:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 for ui_ in uis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui_.setconfig(b'ui', b'interactive', b'off', b'-y')
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if cmdoptions.get(b'insecure', False):
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 coloropt = options[b'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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui_.setconfig(b'ui', b'color', coloropt, b'--color')
Pierre-Yves David
color: add a 'ui.color' option to control color behavior...
r31110 color.setup(ui_)
Pierre-Yves David
color: move triggering of the initialisation logic in core...
r31105
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if stringutil.parsebool(options[b'pager']):
FUJIWARA Katsunori
ui: enable pager always for explicit --pager=on (issue5580)...
r33622 # ui.pager() expects 'internal-always-' prefix in this case
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.pager(b'internal-always-' + cmd)
elif options[b'pager'] != b'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
Yuya Nishihara
extensions: add "uipopulate" hook, called per instance, not per process...
r40760 # configs are fully loaded, set up the ui instances
for ui_ in uis:
extensions.populateui(ui_)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b'version']:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 return commands.version_(ui)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b'help']:
Bryan O'Sullivan
dispatch: start profiling earlier...
r30934 return commands.help_(ui, cmd, command=cmd is not None)
elif not cmd:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return commands.help_(ui, b'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: add some assertions to give pytype a helping hand...
r44105 assert func is not None # help out pytype
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
Yuya Nishihara
dispatch: pass around ui.fmsg channel...
r40623 repo.ui.fmsg = ui.fmsg
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 else:
try:
Augie Fackler
formatting: blacken the codebase...
r43346 repo = hg.repository(
ui,
path=path,
presetupfuncs=req.prereposetups,
intents=func.intents,
)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 if not repo.local():
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"repository '%s' is not local") % path
Augie Fackler
formatting: blacken the codebase...
r43346 )
repo.ui.setconfig(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"bundle", b"mainreporoot", repo.root, b'repo'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 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:
Augie Fackler
formatting: blacken the codebase...
r43346 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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 req.args = [b'--repository', guess] + fullargs
req.earlyoptions[b'repository'] = guess
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 return _dispatch(req)
if not path:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.RepoError(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"no repository found in"
b" '%s' (.hg not found)"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% encoding.getcwd()
)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 raise
if repo:
ui = repo.ui
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if options[b'hidden']:
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 repo = repo.unfiltered()
args.insert(0, repo)
elif rpath:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b"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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.log(b"command", b'%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:
Augie Fackler
formatting: blacken the codebase...
r43346 return runcommand(
lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
)
Arun Kulshreshtha
dispatch: change indentation level in _dispatch()...
r30005 finally:
if repo and repo != req.repo:
repo.close()
Matt Mackall
dispatch: move command dispatching into its own module...
r5178
Augie Fackler
formatting: blacken the codebase...
r43346
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:
Augie Fackler
cleanup: hgdemandimport.tracing accepts strings, not bytes...
r43532 with tracing.log("Running %s command" % cmd):
Boris Feld
tracing: trace command function execution...
r39548 return cmdfunc()
Arun Kulshreshtha
dispatch: make hg --profile wrap reposetup...
r30006 except error.SignatureError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.CommandError(cmd, _(b'invalid arguments'))
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784
Augie Fackler
formatting: blacken the codebase...
r43346
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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 worst = None, ct, b''
if ui.config(b'ui', b'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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = stringutil.forcebytestr(
getattr(mod, 'testedwith', b'')
)
report = getattr(mod, 'buglink', _(b'the extension author.'))
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 if not testedwith.strip():
# We found an untested extension. It's likely the culprit.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 worst = name, b'unknown', report
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 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)):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'.'.join(
Augie Fackler
formatting: blacken the codebase...
r43346 [stringutil.forcebytestr(c) for c in testedwith]
)
warning = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'** Unknown exception encountered with '
b'possibly-broken third-party extension %s\n'
b'** which supports versions %s of Mercurial.\n'
b'** Please disable %s and try your action again.\n'
b'** If that fixes the bug please report it to %s\n'
Augie Fackler
formatting: blacken the codebase...
r43346 ) % (name, testedwith, name, stringutil.forcebytestr(report))
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bugtracker = ui.config(b'ui', b'supportcontact')
Martijn Pieters
dispatch: factor out command failure handling into a function...
r28784 if bugtracker is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bugtracker = _(b"https://mercurial-scm.org/wiki/BugTracker")
Augie Fackler
formatting: blacken the codebase...
r43346 warning = (
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"** unknown exception encountered, "
b"please report by visiting\n** "
Augie Fackler
formatting: blacken the codebase...
r43346 )
+ bugtracker
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 + b'\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 sysversion = pycompat.sysbytes(sys.version).replace(b'\n', b'')
Augie Fackler
formatting: blacken the codebase...
r43346 warning += (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (_(b"** Python %s\n") % sysversion)
+ (_(b"** Mercurial Distributed SCM (version %s)\n") % util.version())
Augie Fackler
formatting: blacken the codebase...
r43346 + (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"** Extensions loaded: %s\n")
% b", ".join([x[0] for x in extensions.extensions()])
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Martijn Pieters
dispatch: split out warning message generation to separate function...
r28821 return warning
Augie Fackler
formatting: blacken the codebase...
r43346
Martijn Pieters
dispatch: split out warning message generation to separate function...
r28821 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)
Augie Fackler
formatting: blacken the codebase...
r43346 ui.log(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"commandexception",
b"%s\n%s\n",
Augie Fackler
formatting: blacken the codebase...
r43346 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