brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 512958d Raw
218 lines · python
1# DExTer : Debugging Experience Tester2# ~~~~~~   ~         ~~         ~   ~~3#4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5# See https://llvm.org/LICENSE.txt for license information.6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7"""This is the main entry point.8It implements some functionality common to all subtools such as command line9parsing and running the unit-testing harnesses, before calling the reequested10subtool.11"""12 13import os14import sys15 16from dex.utils import PrettyOutput, Timer17from dex.utils import ExtArgParse as argparse18from dex.utils import get_root_directory19from dex.utils.Exceptions import Error, ToolArgumentError20from dex.utils.Imports import load_module21from dex.utils.Logging import Logger22from dex.utils.UnitTests import unit_tests_ok23from dex.utils.Version import version24from dex.utils import WorkingDirectory25from dex.utils.ReturnCode import ReturnCode26 27 28def _output_bug_report_message(context):29    """In the event of a catastrophic failure, print bug report request to the30    user.31    """32    context.o.red(33        "\n\n"34        "<g>****************************************</>\n"35        "<b>****************************************</>\n"36        "****************************************\n"37        "**                                    **\n"38        "** <y>This is a bug in <a>DExTer</>.</>           **\n"39        "**                                    **\n"40        "**                  <y>Please report it.</> **\n"41        "**                                    **\n"42        "****************************************\n"43        "<b>****************************************</>\n"44        "<g>****************************************</>\n"45        "\n"46        "<b>system:</>\n"47        "<d>{}</>\n\n"48        "<b>version:</>\n"49        "<d>{}</>\n\n"50        "<b>args:</>\n"51        "<d>{}</>\n"52        "\n".format(sys.platform, version("DExTer"), [sys.executable] + sys.argv),53        stream=PrettyOutput.stderr,54    )55 56 57def get_tools_directory():58    """Returns directory path where DExTer tool imports can be59    found.60    """61    tools_directory = os.path.join(get_root_directory(), "tools")62    assert os.path.isdir(tools_directory), tools_directory63    return tools_directory64 65 66def get_tool_names():67    """Returns a list of expected DExTer Tools"""68    return [69        "help",70        "list-debuggers",71        "no-tool-",72        "run-debugger-internal-",73        "test",74        "view",75    ]76 77 78def _set_auto_highlights(context):79    """Flag some strings for auto-highlighting."""80    context.o.auto_reds.extend(81        [82            r"[Ee]rror\:",83            r"[Ee]xception\:",84            r"un(expected|recognized) argument",85        ]86    )87    context.o.auto_yellows.extend(88        [89            r"[Ww]arning\:",90            r"\(did you mean ",91            r"During handling of the above exception, another exception",92        ]93    )94 95 96def _get_options_and_args(context):97    """get the options and arguments from the commandline"""98    parser = argparse.ExtArgumentParser(context, add_help=False)99    parser.add_argument("tool", default=None, nargs="?")100    options, args = parser.parse_known_args(sys.argv[1:])101 102    return options, args103 104 105def _get_tool_name(options):106    """get the name of the dexter tool (if passed) specified on the command107    line, otherwise return 'no_tool_'.108    """109    tool_name = options.tool110    if tool_name is None:111        tool_name = "no_tool_"112    else:113        _is_valid_tool_name(tool_name)114    return tool_name115 116 117def _is_valid_tool_name(tool_name):118    """check tool name matches a tool directory within the dexter tools119    directory.120    """121    valid_tools = get_tool_names()122    if tool_name not in valid_tools:123        raise Error(124            'invalid tool "{}" (choose from {})'.format(125                tool_name, ", ".join([t for t in valid_tools if not t.endswith("-")])126            )127        )128 129 130def _import_tool_module(tool_name):131    """Imports the python module at the tool directory specificed by132    tool_name.133    """134    # format tool argument to reflect tool directory form.135    tool_name = tool_name.replace("-", "_")136 137    tools_directory = get_tools_directory()138    return load_module(tool_name, tools_directory)139 140 141def tool_main(context, tool, args):142    with Timer(tool.name):143        options, defaults = tool.parse_command_line(args)144        Timer.display = options.time_report145        Timer.indent = options.indent_timer_level146        Timer.fn = context.o.blue147        context.options = options148        context.version = version(tool.name)149 150        if options.version:151            context.o.green("{}\n".format(context.version))152            return ReturnCode.OK153 154        if options.verbose:155            context.logger.verbosity = 2156        elif options.no_warnings:157            context.logger.verbosity = 0158 159        if options.unittest != "off" and not unit_tests_ok(context):160            raise Error("<d>unit test failures</>")161 162        if options.colortest:163            context.o.colortest()164            return ReturnCode.OK165 166        try:167            tool.handle_base_options(defaults)168        except ToolArgumentError as e:169            raise Error(e)170 171        dir_ = context.options.working_directory172        with WorkingDirectory(context, dir=dir_) as context.working_directory:173            return_code = tool.go()174 175        return return_code176 177 178class Context(object):179    """Context encapsulates globally useful objects and data; passed to many180    Dexter functions.181    """182 183    def __init__(self):184        self.o: PrettyOutput = None185        self.logger: Logger = None186        self.working_directory: str = None187        self.options: dict = None188        self.version: str = None189        self.root_directory: str = None190 191 192def main() -> ReturnCode:193    context = Context()194    with PrettyOutput() as context.o:195        context.logger = Logger(context.o)196        try:197            context.root_directory = get_root_directory()198            # Flag some strings for auto-highlighting.199            _set_auto_highlights(context)200            options, args = _get_options_and_args(context)201            # raises 'Error' if command line tool is invalid.202            tool_name = _get_tool_name(options)203            module = _import_tool_module(tool_name)204            return tool_main(context, module.Tool(context), args)205        except Error as e:206            context.logger.error(str(e))207            try:208                if context.options.error_debug:209                    raise210            except AttributeError:211                pass212            return ReturnCode._ERROR213        except (KeyboardInterrupt, SystemExit):214            raise215        except:  # noqa216            _output_bug_report_message(context)217            raise218