Exemple #1
0
def run():
    "run the command in sys.argv"
    initstdio()
    with tracing.log('parse args into request'):
        req = request(pycompat.sysargv[1:])
    err = None
    try:
        status = dispatch(req)
    except error.StdioError as e:
        err = e
        status = -1

    # In all cases we try to flush stdio streams.
    if util.safehasattr(req.ui, 'fout'):
        try:
            req.ui.fout.flush()
        except IOError as e:
            err = e
            status = -1

    if util.safehasattr(req.ui, 'ferr'):
        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

    _silencestdio()
    sys.exit(status & 255)
Exemple #2
0
def _runcommand(ui, options, cmd, cmdfunc):
    """Run a command function, possibly with profiling enabled."""
    try:
        with tracing.log("Running %s command" % cmd):
            return cmdfunc()
    except error.SignatureError:
        raise error.CommandError(cmd, _('invalid arguments'))
Exemple #3
0
    def finalextsetup(self, ui):
        """Method to be used as a the extension extsetup

        The following operations belong here:

        - Changes depending on the status of other extensions. (if
          extensions.find('mq'))
        - Add a global option to all commands
        """
        knownexts = {}

        for ext, command, wrapper, opts in self._extcommandwrappers:
            if ext not in knownexts:
                try:
                    e = extensions.find(ext)
                except KeyError:
                    # Extension isn't enabled, so don't bother trying to wrap
                    # it.
                    continue
                knownexts[ext] = e.cmdtable
            entry = extensions.wrapcommand(knownexts[ext], command, wrapper)
            if opts:
                for opt in opts:
                    entry[1].append(opt)

        for c in self._extcallables:
            with tracing.log('finalextsetup: %s', repr(c)):
                c(ui)
Exemple #4
0
    def finaluisetup(self, ui):
        """Method to be used as the extension uisetup

        The following operations belong here:

        - Changes to ui.__class__ . The ui object that will be used to run the
          command has not yet been created. Changes made here will affect ui
          objects created after this, and in particular the ui that will be
          passed to runcommand
        - Command wraps (extensions.wrapcommand)
        - Changes that need to be visible to other extensions: because
          initialization occurs in phases (all extensions run uisetup, then all
          run extsetup), a change made here will be visible to other extensions
          during extsetup
        - Monkeypatch or wrap function (extensions.wrapfunction) of dispatch
          module members
        - Setup of pre-* and post-* hooks
        - pushkey setup
        """
        for command, wrapper, opts in self._commandwrappers:
            entry = extensions.wrapcommand(commands.table, command, wrapper)
            if opts:
                for opt in opts:
                    entry[1].append(opt)
        for cont, funcname, wrapper in self._functionwrappers:
            extensions.wrapfunction(cont, funcname, wrapper)
        for c in self._uicallables:
            with tracing.log('finaluisetup: %s', repr(c)):
                c(ui)
Exemple #5
0
    def finalreposetup(self, ui, repo):
        """Method to be used as the extension reposetup

        The following operations belong here:

        - All hooks but pre-* and post-*
        - Modify configuration variables
        - Changes to repo.__class__, repo.dirstate.__class__
        """
        for c in self._repocallables:
            with tracing.log('finalreposetup: %s', repr(c)):
                c(ui, repo)
def run():
    """run the command in sys.argv"""
    try:
        initstdio()
        with tracing.log('parse args into request'):
            req = request(pycompat.sysargv[1:])

        status = dispatch(req)
        _silencestdio()
    except KeyboardInterrupt:
        # Catch early/late KeyboardInterrupt as last ditch. Here nothing will
        # be printed to console to avoid another IOError/KeyboardInterrupt.
        status = -1
    sys.exit(status & 255)
Exemple #7
0
def _runcatch(req):
    with tracing.log('dispatch._runcatch'):
        def catchterm(*args):
            raise error.SignalInterrupt

        ui = req.ui
        try:
            for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
                num = getattr(signal, name, None)
                if num:
                    signal.signal(num, catchterm)
        except ValueError:
            pass # happens if called in a thread

        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),))

            try:
                debugger = 'pdb'
                debugtrace = {
                    'pdb': pdb.set_trace
                }
                debugmortem = {
                    'pdb': pdb.post_mortem
                }

                # 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')

                # 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

                debugtrace[debugger] = debugmod.set_trace
                debugmortem[debugger] = debugmod.post_mortem

                # 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"))

                    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)
Exemple #8
0
def dispatch(req):
    """run the command specified in req.args; returns an integer status code"""
    with tracing.log('dispatch.dispatch'):
        if req.ferr:
            ferr = req.ferr
        elif req.ui:
            ferr = req.ui.ferr
        else:
            ferr = procutil.stderr

        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')

            # 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

        msg = _formatargs(req.args)
        starttime = util.timer()
        ret = 1  # default of Python exit code on unhandled exception
        try:
            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,
                       canonical_command=req.canonical_command)
            try:
                req._runexithandlers()
            except: # exiting, so no re-raises
                ret = ret or -1
        return ret
def _rundispatch(req):
    with tracing.log('dispatch._rundispatch'):
        if req.ferr:
            ferr = req.ferr
        elif req.ui:
            ferr = req.ui.ferr
        else:
            ferr = procutil.stderr

        try:
            if not req.ui:
                req.ui = uimod.ui.load()
            req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
            if req.earlyoptions[b'traceback']:
                req.ui.setconfig(b'ui', b'traceback', b'on', b'--traceback')

            # 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
            if req.fmsg:
                req.ui.fmsg = req.fmsg
        except error.Abort as inst:
            ferr.write(inst.format())
            return -1

        msg = _formatargs(req.args)
        starttime = util.timer()
        ret = 1  # default of Python exit code on unhandled exception
        try:
            ret = _runcatch(req) or 0
        except error.ProgrammingError as inst:
            req.ui.error(_(b'** ProgrammingError: %s\n') % inst)
            if inst.hint:
                req.ui.error(_(b'** (%s)\n') % inst.hint)
            raise
        except KeyboardInterrupt as inst:
            try:
                if isinstance(inst, error.SignalInterrupt):
                    msg = _(b"killed!\n")
                else:
                    msg = _(b"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()  # record blocked times
            if req.ui.logblockedtimes:
                req.ui._blockedtimes[b'command_duration'] = duration * 1000
                req.ui.log(b'uiblocked', b'ui blocked ms\n',
                           **pycompat.strkwargs(req.ui._blockedtimes))
            return_code = ret & 255
            req.ui.log(
                b"commandfinish",
                b"%s exited %d after %0.2f seconds\n",
                msg,
                return_code,
                duration,
                return_code=return_code,
                duration=duration,
                canonical_command=req.canonical_command,
            )
            try:
                req._runexithandlers()
            except:  # exiting, so no re-raises
                ret = ret or -1
            # do flush again since ui.log() and exit handlers may write to ui
            req.ui.flush()
        return ret