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