1import os 2import sys 3 4 5class TestingConfig(object): 6 """ 7 TestingConfig - Information on the tests inside a suite. 8 """ 9 10 @staticmethod 11 def fromdefaults(litConfig): 12 """ 13 fromdefaults(litConfig) -> TestingConfig 14 15 Create a TestingConfig object with default values. 16 """ 17 # Set the environment based on the command line arguments. 18 environment = { 19 "PATH": os.pathsep.join(litConfig.path + [os.environ.get("PATH", "")]), 20 "LLVM_DISABLE_CRASH_REPORT": "1", 21 } 22 23 pass_vars = [ 24 "LIBRARY_PATH", 25 "LD_LIBRARY_PATH", 26 "SYSTEMROOT", 27 "TERM", 28 "CLANG", 29 "CLANG_TOOLCHAIN_PROGRAM_TIMEOUT", 30 "LLDB", 31 "LD_PRELOAD", 32 "LLVM_SYMBOLIZER_PATH", 33 "LLVM_PROFILE_FILE", 34 "ASAN_SYMBOLIZER_PATH", 35 "HWASAN_SYMBOLIZER_PATH", 36 "LSAN_SYMBOLIZER_PATH", 37 "MSAN_SYMBOLIZER_PATH", 38 "TSAN_SYMBOLIZER_PATH", 39 "UBSAN_SYMBOLIZER_PATH", 40 "ASAN_OPTIONS", 41 "LSAN_OPTIONS", 42 "HWASAN_OPTIONS", 43 "MSAN_OPTIONS", 44 "RTSAN_OPTIONS", 45 "TSAN_OPTIONS", 46 "UBSAN_OPTIONS", 47 "ADB", 48 "ADB_SERVER_SOCKET", 49 "ANDROID_SERIAL", 50 "SSH_AUTH_SOCK", 51 "SANITIZER_IGNORE_CVE_2016_2143", 52 "TMPDIR", 53 "TMP", 54 "TEMP", 55 "TEMPDIR", 56 "AVRLIT_BOARD", 57 "AVRLIT_PORT", 58 "FILECHECK_OPTS", 59 "VCINSTALLDIR", 60 "VCToolsinstallDir", 61 "VSINSTALLDIR", 62 "WindowsSdkDir", 63 "WindowsSDKLibVersion", 64 "SOURCE_DATE_EPOCH", 65 "GTEST_FILTER", 66 "DFLTCC", 67 "QEMU_LD_PREFIX", 68 "QEMU_CPU", 69 ] 70 71 if sys.platform.startswith("aix"): 72 pass_vars += ["LIBPATH"] 73 elif sys.platform == "win32": 74 pass_vars += [ 75 "COMSPEC", 76 "INCLUDE", 77 "LIB", 78 "PATHEXT", 79 "USERPROFILE", 80 ] 81 environment["PYTHONBUFFERED"] = "1" 82 # Avoid Windows heuristics which try to detect potential installer 83 # programs (which may need to run with elevated privileges) and ask 84 # if the user wants to run them in that way. This heuristic may 85 # match for executables containing the substrings "patch" (which is 86 # a substring of "dispatch"), "update", "setup", etc. Set this 87 # environment variable indicating that we want to execute them with 88 # the current user. 89 environment["__COMPAT_LAYER"] = "RunAsInvoker" 90 91 for var in pass_vars: 92 val = os.environ.get(var, "") 93 # Check for empty string as some variables such as LD_PRELOAD cannot be empty 94 # ('') for OS's such as OpenBSD. 95 if val: 96 environment[var] = val 97 98 # Set the default available features based on the LitConfig. 99 available_features = [] 100 if litConfig.useValgrind: 101 available_features.append("valgrind") 102 if litConfig.valgrindLeakCheck: 103 available_features.append("vg_leak") 104 105 return TestingConfig( 106 None, 107 name="<unnamed>", 108 suffixes=set(), 109 test_format=None, 110 environment=environment, 111 substitutions=[], 112 unsupported=False, 113 test_exec_root=None, 114 test_source_root=None, 115 excludes=[], 116 available_features=available_features, 117 pipefail=True, 118 standalone_tests=False, 119 ) 120 121 def load_from_path(self, path, litConfig): 122 """ 123 load_from_path(path, litConfig) 124 125 Load the configuration module at the provided path into the given config 126 object. 127 """ 128 129 # Load the config script data. 130 data = None 131 f = open(path) 132 try: 133 data = f.read() 134 except: 135 litConfig.fatal("unable to load config file: %r" % (path,)) 136 f.close() 137 138 # Execute the config script to initialize the object. 139 cfg_globals = dict(globals()) 140 cfg_globals["config"] = self 141 cfg_globals["lit_config"] = litConfig 142 cfg_globals["__file__"] = path 143 try: 144 exec(compile(data, path, "exec"), cfg_globals, None) 145 if litConfig.debug: 146 litConfig.note("... loaded config %r" % path) 147 except SystemExit: 148 e = sys.exc_info()[1] 149 # We allow normal system exit inside a config file to just 150 # return control without error. 151 if e.args: 152 raise 153 except: 154 import traceback 155 156 litConfig.fatal( 157 "unable to parse config file %r, traceback: %s" 158 % (path, traceback.format_exc()) 159 ) 160 self.finish(litConfig) 161 162 def __init__( 163 self, 164 parent, 165 name, 166 suffixes, 167 test_format, 168 environment, 169 substitutions, 170 unsupported, 171 test_exec_root, 172 test_source_root, 173 excludes, 174 available_features, 175 pipefail, 176 limit_to_features=[], 177 is_early=False, 178 parallelism_group=None, 179 standalone_tests=False, 180 ): 181 self.parent = parent 182 self.name = str(name) 183 self.suffixes = set(suffixes) 184 self.test_format = test_format 185 self.environment = dict(environment) 186 self.substitutions = list(substitutions) 187 self.unsupported = unsupported 188 self.test_exec_root = test_exec_root 189 self.test_source_root = test_source_root 190 self.excludes = set(excludes) 191 self.available_features = set(available_features) 192 self.pipefail = pipefail 193 self.standalone_tests = standalone_tests 194 # This list is used by TestRunner.py to restrict running only tests that 195 # require one of the features in this list if this list is non-empty. 196 # Configurations can set this list to restrict the set of tests to run. 197 self.limit_to_features = set(limit_to_features) 198 self.parallelism_group = parallelism_group 199 self._recursiveExpansionLimit = None 200 201 @property 202 def recursiveExpansionLimit(self): 203 return self._recursiveExpansionLimit 204 205 @recursiveExpansionLimit.setter 206 def recursiveExpansionLimit(self, value): 207 if value is not None and not isinstance(value, int): 208 raise ValueError( 209 "recursiveExpansionLimit must be either None or an integer (got <{}>)".format( 210 value 211 ) 212 ) 213 if isinstance(value, int) and value < 0: 214 raise ValueError( 215 "recursiveExpansionLimit must be a non-negative integer (got <{}>)".format( 216 value 217 ) 218 ) 219 self._recursiveExpansionLimit = value 220 221 def finish(self, litConfig): 222 """finish() - Finish this config object, after loading is complete.""" 223 224 self.name = str(self.name) 225 self.suffixes = set(self.suffixes) 226 self.environment = dict(self.environment) 227 self.substitutions = list(self.substitutions) 228 if self.test_exec_root is not None: 229 # FIXME: This should really only be suite in test suite config 230 # files. Should we distinguish them? 231 self.test_exec_root = str(self.test_exec_root) 232 if self.test_source_root is not None: 233 # FIXME: This should really only be suite in test suite config 234 # files. Should we distinguish them? 235 self.test_source_root = str(self.test_source_root) 236 self.excludes = set(self.excludes) 237 238 @property 239 def root(self): 240 """root attribute - The root configuration for the test suite.""" 241 if self.parent is None: 242 return self 243 else: 244 return self.parent.root 245 246 247class SubstituteCaptures: 248 """ 249 Helper class to indicate that the substitutions contains backreferences. 250 251 This can be used as the following in lit.cfg to mark subsitutions as having 252 back-references:: 253 254 config.substutions.append(('\b[^ ]*.cpp', SubstituteCaptures('\0.txt'))) 255 256 """ 257 258 def __init__(self, substitution): 259 self.substitution = substitution 260 261 def replace(self, pattern, replacement): 262 return self.substitution 263 264 def __str__(self): 265 return self.substitution 266 267 def __len__(self): 268 return len(self.substitution) 269 270 def __getitem__(self, item): 271 return self.substitution.__getitem__(item) 272