1""" 2Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3See https://llvm.org/LICENSE.txt for license information. 4SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 6Sync lldb and related source from a local machine to a remote machine. 7 8This facilitates working on the lldb sourcecode on multiple machines 9and multiple OS types, verifying changes across all. 10 11Provides helper support for adding lldb test paths to the python path. 12""" 13 14from __future__ import print_function 15from __future__ import absolute_import 16 17# System modules 18import os 19import platform 20import subprocess 21import sys 22 23# Third-party modules 24 25# LLDB modules 26 27 28def add_lldb_test_paths(check_dir): 29 # pylint: disable=line-too-long 30 """Adds lldb test-related paths to the python path. 31 32 Starting with the given directory and working upward through 33 each parent directory up to the root, it looks for the lldb 34 test directory. When found, the lldb test directory and its 35 child test_runner/lib directory will be added to the python 36 system path. 37 38 Instructions for use: 39 40 This method supports a simple way of getting pylint to be able 41 to reliably lint lldb python test scripts (including the test 42 infrastructure itself). To do so, add the following to a 43 .pylintrc file in your home directory: 44 45 [Master] 46 init-hook='import os; import sys; sys.path.append(os.path.expanduser("~/path/to/lldb/packages/Python/lldbsuite/test")); import lldb_pylint_helper; lldb_pylint_helper.add_lldb_test_paths(os.getcwd()); print("sys.path={}\n".format(sys.path))' 47 48 Replace ~/path/to/lldb with a valid path to your local lldb source 49 tree. Note you can have multiple lldb source trees on your system, and 50 this will work just fine. The path in your .pylintrc is just needed to 51 find the paths needed for pylint in whatever lldb source tree you're in. 52 pylint will use the python files in whichever tree it is run from. 53 54 Note it is critical that the init-hook line be contained on a single line. 55 You can remove the print line at the end once you know the pythonpath is 56 getting set up the way you expect. 57 58 With these changes, you will be able to run the following, for example. 59 60 cd lldb/sourcetree/1-of-many/test/lang/c/anonymous 61 pylint TestAnonymous.py 62 63 This will work, and include all the lldb/sourcetree/1-of-many lldb-specific 64 python directories to your path. 65 66 You can then run it in another lldb source tree on the same machine like 67 so: 68 69 cd lldb/sourcetree/2-of-many/test/functionalities/inferior-assert 70 pyline TestInferiorAssert.py 71 72 and this will properly lint that file, using the lldb-specific python 73 directories from the 2-of-many source tree. 74 75 Note at the time I'm writing this, our tests are in pretty sad shape 76 as far as a stock pylint setup goes. But we need to start somewhere :-) 77 78 @param check_dir specifies a directory that will be used to start 79 looking for the lldb test infrastructure python library paths. 80 """ 81 # Add the test-related packages themselves. 82 add_lldb_test_package_paths(check_dir) 83 84 # Add the lldb directory itself 85 add_lldb_module_directory() 86 87 88def add_lldb_module_directory(): 89 """ 90 Desired Approach: 91 92 Part A: find an lldb 93 94 1. Walk up the parent chain from the current directory, looking for 95 a directory matching *build*. If we find that, use it as the 96 root of a directory search for an lldb[.exe] executable. 97 98 2. If 1 fails, use the path and look for an lldb[.exe] in there. 99 100 If Part A ends up with an lldb, go to part B. Otherwise, give up 101 on the lldb python module path. 102 103 Part B: use the output from 'lldb[.exe] -P' to find the lldb dir. 104 105 Current approach: 106 If Darwin, use 'xcrun lldb -P'; others: find lldb on path. 107 108 Drawback to current approach: 109 If the tester is changing the SB API (adding new methods), pylint 110 will not know about them as it is using the wrong lldb python module. 111 In practice, this should be minor. 112 """ 113 try: 114 lldb_module_path = None 115 116 if platform.system() == 'Darwin': 117 # Use xcrun to find the selected lldb. 118 lldb_module_path = subprocess.check_output(["xcrun", "lldb", "-P"]) 119 elif platform.system() == 'Windows': 120 lldb_module_path = subprocess.check_output( 121 ["lldb.exe", "-P"], shell=True) 122 else: 123 # Use the shell to run lldb from the path. 124 lldb_module_path = subprocess.check_output( 125 ["lldb", "-P"], shell=True) 126 127 # Trim the result. 128 if lldb_module_path is not None: 129 lldb_module_path = lldb_module_path.strip() 130 131 # If we have a result, add it to the path 132 if lldb_module_path is not None and len(lldb_module_path) > 0: 133 sys.path.insert(0, lldb_module_path) 134 # pylint: disable=broad-except 135 except Exception as exception: 136 print("failed to find python path: {}".format(exception)) 137 138 139def add_lldb_test_package_paths(check_dir): 140 """Adds the lldb test infrastructure modules to the python path. 141 142 See add_lldb_test_paths for more details. 143 144 @param check_dir the directory of the test. 145 """ 146 147 def child_dirs(parent_dir): 148 return [os.path.join(parent_dir, child) 149 for child in os.listdir(parent_dir) 150 if os.path.isdir(os.path.join(parent_dir, child))] 151 152 check_dir = os.path.realpath(check_dir) 153 while check_dir and len(check_dir) > 0: 154 # If the current directory contains a packages/Python 155 # directory, add that directory to the path. 156 packages_python_child_dir = os.path.join( 157 check_dir, "packages", "Python") 158 if os.path.exists(packages_python_child_dir): 159 sys.path.insert(0, packages_python_child_dir) 160 sys.path.insert(0, os.path.join( 161 packages_python_child_dir, "test_runner", "lib")) 162 163 # Handle third_party module/package directory. 164 third_party_module_dir = os.path.join( 165 check_dir, "third_party", "Python", "module") 166 for child_dir in child_dirs(third_party_module_dir): 167 # Yes, we embed the module in the module parent dir 168 sys.path.insert(0, child_dir) 169 170 # We're done. 171 break 172 173 # Continue looking up the parent chain until we have no more 174 # directories to check. 175 new_check_dir = os.path.dirname(check_dir) 176 # We're done when the new check dir is not different 177 # than the current one. 178 if new_check_dir == check_dir: 179 break 180 check_dir = new_check_dir 181