1# DExTer : Debugging Experience Tester 2# ~~~~~~ ~ ~~ ~ ~~ 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-exception 7"""Base class for all subtools.""" 8 9import abc 10import os 11import tempfile 12 13from dex import __version__ 14from dex.utils import ExtArgParse 15from dex.utils import PrettyOutput 16from dex.utils.ReturnCode import ReturnCode 17 18 19class ToolBase(object, metaclass=abc.ABCMeta): 20 def __init__(self, context): 21 self.context = context 22 self.parser = None 23 24 @abc.abstractproperty 25 def name(self): 26 pass 27 28 @abc.abstractmethod 29 def add_tool_arguments(self, parser, defaults): 30 pass 31 32 def parse_command_line(self, args): 33 """Define two parsers: pparser and self.parser. 34 pparser deals with args that need to be parsed prior to any of those of 35 self.parser. For example, any args which may affect the state of 36 argparse error output. 37 """ 38 39 class defaults(object): 40 pass 41 42 pparser = ExtArgParse.ExtArgumentParser( 43 self.context, add_help=False, prog=self.name 44 ) 45 46 pparser.add_argument( 47 "--no-color-output", 48 action="store_true", 49 default=False, 50 help="do not use colored output on stdout/stderr", 51 ) 52 pparser.add_argument( 53 "--time-report", 54 action="store_true", 55 default=False, 56 help="display timing statistics", 57 ) 58 59 self.parser = ExtArgParse.ExtArgumentParser( 60 self.context, parents=[pparser], prog=self.name 61 ) 62 self.parser.add_argument( 63 "-v", 64 "--verbose", 65 action="store_true", 66 default=False, 67 help="enable verbose output (overrides --no-warnings)", 68 ) 69 self.parser.add_argument( 70 "-V", 71 "--version", 72 action="store_true", 73 default=False, 74 help="display the DExTer version and exit", 75 ) 76 self.parser.add_argument( 77 "-w", 78 "--no-warnings", 79 action="store_true", 80 default=False, 81 help="suppress warning output", 82 ) 83 self.parser.add_argument( 84 "--unittest", 85 type=str, 86 choices=["off", "show-failures", "show-all"], 87 default="off", 88 help="run the DExTer codebase unit tests", 89 ) 90 91 suppress = ExtArgParse.SUPPRESS # pylint: disable=no-member 92 self.parser.add_argument( 93 "--colortest", action="store_true", default=False, help=suppress 94 ) 95 self.parser.add_argument( 96 "--error-debug", action="store_true", default=False, help=suppress 97 ) 98 defaults.working_directory = os.path.join(tempfile.gettempdir(), "dexter") 99 self.parser.add_argument( 100 "--indent-timer-level", type=int, default=1, help=suppress 101 ) 102 self.parser.add_argument( 103 "--working-directory", 104 type=str, 105 metavar="<file>", 106 default=None, 107 display_default=defaults.working_directory, 108 help="location of working directory", 109 ) 110 self.parser.add_argument( 111 "--save-temps", 112 action="store_true", 113 default=False, 114 help="save temporary files", 115 ) 116 117 self.add_tool_arguments(self.parser, defaults) 118 119 # If an error is encountered during pparser, show the full usage text 120 # including self.parser options. Strip the preceding 'usage: ' to avoid 121 # having it appear twice. 122 pparser.usage = self.parser.format_usage().lstrip("usage: ") 123 124 options, args = pparser.parse_known_args(args) 125 126 if options.no_color_output: 127 PrettyOutput.stdout.color_enabled = False 128 PrettyOutput.stderr.color_enabled = False 129 130 options = self.parser.parse_args(args, namespace=options) 131 return options, defaults 132 133 def handle_base_options(self, defaults): 134 self.handle_options(defaults) 135 136 options = self.context.options 137 138 if options.working_directory is None: 139 options.working_directory = defaults.working_directory 140 141 @abc.abstractmethod 142 def handle_options(self, defaults): 143 pass 144 145 @abc.abstractmethod 146 def go(self) -> ReturnCode: 147 pass 148