def dispatch()

in eden/scm/edenscm/mercurial/dispatch.py [0:0]


def dispatch(req):
    "run the command specified in req.args"
    if req.ferr:
        ferr = req.ferr
    elif req.ui:
        ferr = req.ui.ferr
    else:
        ferr = util.stderr

    try:
        if not req.ui:
            req.ui = uimod.ui.load()
        req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
        if req.earlyoptions["traceback"] or req.earlyoptions["trace"]:
            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

    if req.ui.configbool("ui", "threaded"):
        util.preregistersighandlers()

    cmdmsg = _formatargs(req.args)
    starttime = util.timer()
    ret = None
    retmask = 255

    def logatexit():
        ui = req.ui
        if ui.logmeasuredtimes:
            ui.log("measuredtimes", **(ui._measuredtimes))
        hgmetrics = bindings.hgmetrics.summarize()
        if hgmetrics:
            # Comma-separated list of metric prefixes to skip
            # TODO(meyer): Just skip printing metrics, rather than skipping logging them entirely.
            skip = ui.configlist("devel", "skip-metrics", [])
            # Re-arrange metrics so "a_b_c", "a_b_d", "a_c" becomes
            # {'a': {'b': {'c': ..., 'd': ...}, 'c': ...}
            metrics = {}
            splitre = re.compile(r"_|/|\.")
            for key, value in hgmetrics.items():
                for prefix in skip:
                    if key.startswith(prefix):
                        break
                else:
                    cur = metrics
                    names = splitre.split(key)
                    for name in names[:-1]:
                        cur = cur.setdefault(name, {})
                    cur[names[-1]] = value
            # pprint.pformat stablizes the output
            from pprint import pformat

            if metrics:
                # developer config: devel.print-metrics
                if ui.configbool("devel", "print-metrics"):
                    # Print it out.
                    msg = "%s\n" % pformat({"metrics": metrics}).replace("'", " ")
                    ui.flush()
                    ui.write_err(msg, label="hgmetrics")

                # Write to blackbox, and sampling
                ui.log(
                    "metrics", pformat({"metrics": metrics}, width=1024), **hgmetrics
                )
        blackbox.sync()

    if util.isoldversion():
        hintutil.trigger("old-version")

    # by registering this exit handler here, we guarantee that it runs
    # after other exithandlers, like the killpager one
    req.ui.atexit(logatexit)

    try:
        ret = _runcatch(req)
    except error.ProgrammingError as inst:
        req.ui.warn(_("** ProgrammingError: %s\n") % inst)
        if inst.hint:
            req.ui.warn(_("** (%s)\n") % inst.hint)
        raise
    except KeyboardInterrupt as inst:
        try:
            if isinstance(inst, error.SignalInterrupt):
                msg = _("killed!\n")
            else:
                msg = _("interrupted!\n")
            req.ui.warn(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
    except IOError as inst:
        # Windows does not have SIGPIPE, so pager exit does not
        # get raised as a SignalInterrupt. Let's handle the error
        # explicitly here
        if not pycompat.iswindows or inst.errno != errno.EINVAL:
            raise
        ret = -1
    finally:
        duration = util.timer() - starttime
        req.ui.flush()
        req.ui.log(
            "command_finish",
            "%s exited %d after %0.2f seconds\n",
            cmdmsg,
            ret or 0,
            duration,
        )

        threshold = req.ui.configint("tracing", "threshold")
        if duration >= threshold:
            key = "flat/perftrace-%(host)s-%(pid)s-%(time)s" % {
                "host": socket.gethostname(),
                "pid": os.getpid(),
                "time": time.time(),
            }
            # TODO: Move this into a background task that renders from
            # blackbox instead.
            # The "duration" is chosen dynamically for long commands.
            # The ASCII implementation will fold repetitive calls so
            # the length of the output is practically bounded.
            output = bindings.tracing.singleton.ascii(
                # Minimum resolution = 1% of max(duration, threshold)
                # It's in microseconds (1e6) to divide it by 100 = 1e4
                int((max([duration, threshold]) * 1e4))
            )
            if req.ui.configbool("tracing", "stderr"):
                req.ui.warn("%s\n" % output)
            req.ui.log("perftrace", "Trace:\n%s\n", output, key=key, payload=output)
            req.ui.log("perftracekey", "Trace key:%s\n", key, perftracekey=key)

        def truncateduration(duration):
            """Truncate the passed in duration to only 3 significant digits."""
            millis = int(duration * 1000)
            if millis < 1000:
                return millis

            for power in range(3, 19):
                threshold = 10 ** power
                if millis < threshold:
                    factor = int(threshold / 1000)
                    return int(millis / factor) * factor
            return millis

        req.ui._measuredtimes["command_duration"] = truncateduration(duration)
        retmask = req.ui.configint("ui", "exitcodemask")

        try:
            req._runexithandlers()
        except:  # exiting, so no re-raises
            ret = ret or -1
    if ret is None:
        ret = 0
    return ret & retmask