tests/logexceptions.py
author Raphaël Gomès <rgomes@octobus.net>
Thu, 09 Jun 2022 10:45:27 +0200
changeset 49345 44319aa4a2a4
parent 48875 6000f5b25c9b
permissions -rw-r--r--
hg-cpython: fallback when encountering an unknown matcher At this point in the process, nothing user-visible has happened, it is still safe to fallback. This can happen now that we're going to be using "container matchers" like unionmatcher and intersectionmatcher. This is easier and less error-prone than recursive checking beforehand since only the presence of a transformation case will allow the process to continue.

# logexceptions.py - Write files containing info about Mercurial exceptions
#
# Copyright 2017 Olivia Mackall <olivia@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.


import inspect
import os
import sys
import traceback
import uuid

from mercurial import (
    dispatch,
    extensions,
)


def handleexception(orig, ui):
    res = orig(ui)

    if not ui.environ.get(b'HGEXCEPTIONSDIR'):
        return res

    dest = os.path.join(
        ui.environ[b'HGEXCEPTIONSDIR'], str(uuid.uuid4()).encode('ascii')
    )

    exc_type, exc_value, exc_tb = sys.exc_info()

    stack = []
    tb = exc_tb
    while tb:
        stack.append(tb)
        tb = tb.tb_next
    stack.reverse()

    hgframe = 'unknown'
    hgline = 'unknown'

    # Find the first Mercurial frame in the stack.
    for tb in stack:
        mod = inspect.getmodule(tb)
        if not mod.__name__.startswith(('hg', 'mercurial')):
            continue

        frame = tb.tb_frame

        try:
            with open(inspect.getsourcefile(tb), 'r') as fh:
                hgline = fh.readlines()[frame.f_lineno - 1].strip()
        except (IndexError, OSError):
            pass

        hgframe = '%s:%d' % (frame.f_code.co_filename, frame.f_lineno)
        break

    primary = traceback.extract_tb(exc_tb)[-1]
    primaryframe = '%s:%d' % (primary.filename, primary.lineno)

    with open(dest, 'wb') as fh:
        parts = [
            str(exc_value),
            primaryframe,
            hgframe,
            hgline,
            ui.environ[b'TESTNAME'].decode('utf-8', 'replace'),
        ]
        fh.write(b'\0'.join(p.encode('utf-8', 'replace') for p in parts))


def extsetup(ui):
    extensions.wrapfunction(dispatch, 'handlecommandexception', handleexception)