xref: /llvm-project/cross-project-tests/debuginfo-tests/dexter/dex/tools/Main.py (revision 6779376ee917279b16e256839d236cfdf8fd9ab9)
11364750dSJames Henderson# DExTer : Debugging Experience Tester
21364750dSJames Henderson# ~~~~~~   ~         ~~         ~   ~~
31364750dSJames Henderson#
41364750dSJames Henderson# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
51364750dSJames Henderson# See https://llvm.org/LICENSE.txt for license information.
61364750dSJames Henderson# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
71364750dSJames Henderson"""This is the main entry point.
81364750dSJames HendersonIt implements some functionality common to all subtools such as command line
91364750dSJames Hendersonparsing and running the unit-testing harnesses, before calling the reequested
101364750dSJames Hendersonsubtool.
111364750dSJames Henderson"""
121364750dSJames Henderson
131364750dSJames Hendersonimport os
141364750dSJames Hendersonimport sys
151364750dSJames Henderson
161364750dSJames Hendersonfrom dex.utils import PrettyOutput, Timer
171364750dSJames Hendersonfrom dex.utils import ExtArgParse as argparse
181364750dSJames Hendersonfrom dex.utils import get_root_directory
191364750dSJames Hendersonfrom dex.utils.Exceptions import Error, ToolArgumentError
20*6779376eSStephen Tozerfrom dex.utils.Imports import load_module
2173a01952SStephen Tozerfrom dex.utils.Logging import Logger
221364750dSJames Hendersonfrom dex.utils.UnitTests import unit_tests_ok
231364750dSJames Hendersonfrom dex.utils.Version import version
241364750dSJames Hendersonfrom dex.utils import WorkingDirectory
251364750dSJames Hendersonfrom dex.utils.ReturnCode import ReturnCode
261364750dSJames Henderson
271364750dSJames Henderson
281364750dSJames Hendersondef _output_bug_report_message(context):
291364750dSJames Henderson    """In the event of a catastrophic failure, print bug report request to the
301364750dSJames Henderson    user.
311364750dSJames Henderson    """
321364750dSJames Henderson    context.o.red(
33f98ee40fSTobias Hieta        "\n\n"
34f98ee40fSTobias Hieta        "<g>****************************************</>\n"
35f98ee40fSTobias Hieta        "<b>****************************************</>\n"
36f98ee40fSTobias Hieta        "****************************************\n"
37f98ee40fSTobias Hieta        "**                                    **\n"
38f98ee40fSTobias Hieta        "** <y>This is a bug in <a>DExTer</>.</>           **\n"
39f98ee40fSTobias Hieta        "**                                    **\n"
40f98ee40fSTobias Hieta        "**                  <y>Please report it.</> **\n"
41f98ee40fSTobias Hieta        "**                                    **\n"
42f98ee40fSTobias Hieta        "****************************************\n"
43f98ee40fSTobias Hieta        "<b>****************************************</>\n"
44f98ee40fSTobias Hieta        "<g>****************************************</>\n"
45f98ee40fSTobias Hieta        "\n"
46f98ee40fSTobias Hieta        "<b>system:</>\n"
47f98ee40fSTobias Hieta        "<d>{}</>\n\n"
48f98ee40fSTobias Hieta        "<b>version:</>\n"
49f98ee40fSTobias Hieta        "<d>{}</>\n\n"
50f98ee40fSTobias Hieta        "<b>args:</>\n"
51f98ee40fSTobias Hieta        "<d>{}</>\n"
52f98ee40fSTobias Hieta        "\n".format(sys.platform, version("DExTer"), [sys.executable] + sys.argv),
53f98ee40fSTobias Hieta        stream=PrettyOutput.stderr,
54f98ee40fSTobias Hieta    )
551364750dSJames Henderson
561364750dSJames Henderson
571364750dSJames Hendersondef get_tools_directory():
581364750dSJames Henderson    """Returns directory path where DExTer tool imports can be
591364750dSJames Henderson    found.
601364750dSJames Henderson    """
61f98ee40fSTobias Hieta    tools_directory = os.path.join(get_root_directory(), "tools")
621364750dSJames Henderson    assert os.path.isdir(tools_directory), tools_directory
631364750dSJames Henderson    return tools_directory
641364750dSJames Henderson
651364750dSJames Henderson
661364750dSJames Hendersondef get_tool_names():
67f98ee40fSTobias Hieta    """Returns a list of expected DExTer Tools"""
681364750dSJames Henderson    return [
69f98ee40fSTobias Hieta        "help",
70f98ee40fSTobias Hieta        "list-debuggers",
71f98ee40fSTobias Hieta        "no-tool-",
72f98ee40fSTobias Hieta        "run-debugger-internal-",
73f98ee40fSTobias Hieta        "test",
74f98ee40fSTobias Hieta        "view",
751364750dSJames Henderson    ]
761364750dSJames Henderson
771364750dSJames Henderson
781364750dSJames Hendersondef _set_auto_highlights(context):
79f98ee40fSTobias Hieta    """Flag some strings for auto-highlighting."""
80f98ee40fSTobias Hieta    context.o.auto_reds.extend(
81f98ee40fSTobias Hieta        [
82f98ee40fSTobias Hieta            r"[Ee]rror\:",
83f98ee40fSTobias Hieta            r"[Ee]xception\:",
84f98ee40fSTobias Hieta            r"un(expected|recognized) argument",
85f98ee40fSTobias Hieta        ]
86f98ee40fSTobias Hieta    )
87f98ee40fSTobias Hieta    context.o.auto_yellows.extend(
88f98ee40fSTobias Hieta        [
89f98ee40fSTobias Hieta            r"[Ww]arning\:",
90f98ee40fSTobias Hieta            r"\(did you mean ",
91f98ee40fSTobias Hieta            r"During handling of the above exception, another exception",
92f98ee40fSTobias Hieta        ]
93f98ee40fSTobias Hieta    )
941364750dSJames Henderson
951364750dSJames Henderson
961364750dSJames Hendersondef _get_options_and_args(context):
97f98ee40fSTobias Hieta    """get the options and arguments from the commandline"""
981364750dSJames Henderson    parser = argparse.ExtArgumentParser(context, add_help=False)
99f98ee40fSTobias Hieta    parser.add_argument("tool", default=None, nargs="?")
1001364750dSJames Henderson    options, args = parser.parse_known_args(sys.argv[1:])
1011364750dSJames Henderson
1021364750dSJames Henderson    return options, args
1031364750dSJames Henderson
1041364750dSJames Henderson
1051364750dSJames Hendersondef _get_tool_name(options):
1061364750dSJames Henderson    """get the name of the dexter tool (if passed) specified on the command
1071364750dSJames Henderson    line, otherwise return 'no_tool_'.
1081364750dSJames Henderson    """
1091364750dSJames Henderson    tool_name = options.tool
1101364750dSJames Henderson    if tool_name is None:
111f98ee40fSTobias Hieta        tool_name = "no_tool_"
1121364750dSJames Henderson    else:
1131364750dSJames Henderson        _is_valid_tool_name(tool_name)
1141364750dSJames Henderson    return tool_name
1151364750dSJames Henderson
1161364750dSJames Henderson
1171364750dSJames Hendersondef _is_valid_tool_name(tool_name):
1181364750dSJames Henderson    """check tool name matches a tool directory within the dexter tools
1191364750dSJames Henderson    directory.
1201364750dSJames Henderson    """
1211364750dSJames Henderson    valid_tools = get_tool_names()
1221364750dSJames Henderson    if tool_name not in valid_tools:
123f98ee40fSTobias Hieta        raise Error(
124f98ee40fSTobias Hieta            'invalid tool "{}" (choose from {})'.format(
125f98ee40fSTobias Hieta                tool_name, ", ".join([t for t in valid_tools if not t.endswith("-")])
126f98ee40fSTobias Hieta            )
127f98ee40fSTobias Hieta        )
1281364750dSJames Henderson
1291364750dSJames Henderson
1301364750dSJames Hendersondef _import_tool_module(tool_name):
1311364750dSJames Henderson    """Imports the python module at the tool directory specificed by
1321364750dSJames Henderson    tool_name.
1331364750dSJames Henderson    """
1341364750dSJames Henderson    # format tool argument to reflect tool directory form.
135f98ee40fSTobias Hieta    tool_name = tool_name.replace("-", "_")
1361364750dSJames Henderson
1371364750dSJames Henderson    tools_directory = get_tools_directory()
138*6779376eSStephen Tozer    return load_module(tool_name, tools_directory)
1391364750dSJames Henderson
1401364750dSJames Henderson
1411364750dSJames Hendersondef tool_main(context, tool, args):
1421364750dSJames Henderson    with Timer(tool.name):
1431364750dSJames Henderson        options, defaults = tool.parse_command_line(args)
1441364750dSJames Henderson        Timer.display = options.time_report
1451364750dSJames Henderson        Timer.indent = options.indent_timer_level
1461364750dSJames Henderson        Timer.fn = context.o.blue
1471364750dSJames Henderson        context.options = options
1481364750dSJames Henderson        context.version = version(tool.name)
1491364750dSJames Henderson
1501364750dSJames Henderson        if options.version:
151f98ee40fSTobias Hieta            context.o.green("{}\n".format(context.version))
1521364750dSJames Henderson            return ReturnCode.OK
1531364750dSJames Henderson
15473a01952SStephen Tozer        if options.verbose:
15573a01952SStephen Tozer            context.logger.verbosity = 2
15673a01952SStephen Tozer        elif options.no_warnings:
15773a01952SStephen Tozer            context.logger.verbosity = 0
15873a01952SStephen Tozer
159f98ee40fSTobias Hieta        if options.unittest != "off" and not unit_tests_ok(context):
160f98ee40fSTobias Hieta            raise Error("<d>unit test failures</>")
1611364750dSJames Henderson
1621364750dSJames Henderson        if options.colortest:
1631364750dSJames Henderson            context.o.colortest()
1641364750dSJames Henderson            return ReturnCode.OK
1651364750dSJames Henderson
1661364750dSJames Henderson        try:
1671364750dSJames Henderson            tool.handle_base_options(defaults)
1681364750dSJames Henderson        except ToolArgumentError as e:
1691364750dSJames Henderson            raise Error(e)
1701364750dSJames Henderson
1711364750dSJames Henderson        dir_ = context.options.working_directory
1721364750dSJames Henderson        with WorkingDirectory(context, dir=dir_) as context.working_directory:
1731364750dSJames Henderson            return_code = tool.go()
1741364750dSJames Henderson
1751364750dSJames Henderson        return return_code
1761364750dSJames Henderson
1771364750dSJames Henderson
1781364750dSJames Hendersonclass Context(object):
1791364750dSJames Henderson    """Context encapsulates globally useful objects and data; passed to many
1801364750dSJames Henderson    Dexter functions.
1811364750dSJames Henderson    """
1821364750dSJames Henderson
1831364750dSJames Henderson    def __init__(self):
1841364750dSJames Henderson        self.o: PrettyOutput = None
18573a01952SStephen Tozer        self.logger: Logger = None
1861364750dSJames Henderson        self.working_directory: str = None
1871364750dSJames Henderson        self.options: dict = None
1881364750dSJames Henderson        self.version: str = None
1891364750dSJames Henderson        self.root_directory: str = None
1901364750dSJames Henderson
1911364750dSJames Henderson
1921364750dSJames Hendersondef main() -> ReturnCode:
1931364750dSJames Henderson    context = Context()
1941364750dSJames Henderson    with PrettyOutput() as context.o:
19573a01952SStephen Tozer        context.logger = Logger(context.o)
1961364750dSJames Henderson        try:
1971364750dSJames Henderson            context.root_directory = get_root_directory()
1981364750dSJames Henderson            # Flag some strings for auto-highlighting.
1991364750dSJames Henderson            _set_auto_highlights(context)
2001364750dSJames Henderson            options, args = _get_options_and_args(context)
2011364750dSJames Henderson            # raises 'Error' if command line tool is invalid.
2021364750dSJames Henderson            tool_name = _get_tool_name(options)
2031364750dSJames Henderson            module = _import_tool_module(tool_name)
2041364750dSJames Henderson            return tool_main(context, module.Tool(context), args)
2051364750dSJames Henderson        except Error as e:
20673a01952SStephen Tozer            context.logger.error(str(e))
2071364750dSJames Henderson            try:
2081364750dSJames Henderson                if context.options.error_debug:
2091364750dSJames Henderson                    raise
2101364750dSJames Henderson            except AttributeError:
2111364750dSJames Henderson                pass
2121364750dSJames Henderson            return ReturnCode._ERROR
2131364750dSJames Henderson        except (KeyboardInterrupt, SystemExit):
2141364750dSJames Henderson            raise
2151364750dSJames Henderson        except:  # noqa
2161364750dSJames Henderson            _output_bug_report_message(context)
2171364750dSJames Henderson            raise
218