xref: /aosp_15_r20/bootable/libbootloader/gbl/bazel.py (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker# Copyright (C) 2024 The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker#
3*5225e6b1SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker#
7*5225e6b1SAndroid Build Coastguard Worker#       http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker#
9*5225e6b1SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker# limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker
15*5225e6b1SAndroid Build Coastguard Workerimport argparse
16*5225e6b1SAndroid Build Coastguard Workerimport os
17*5225e6b1SAndroid Build Coastguard Workerimport pathlib
18*5225e6b1SAndroid Build Coastguard Workerimport sys
19*5225e6b1SAndroid Build Coastguard Workerfrom typing import Tuple, Optional
20*5225e6b1SAndroid Build Coastguard Worker
21*5225e6b1SAndroid Build Coastguard Worker_BAZEL_REL_PATH = "prebuilts/kernel-build-tools/bazel/linux-x86_64/bazel"
22*5225e6b1SAndroid Build Coastguard Worker
23*5225e6b1SAndroid Build Coastguard Worker
24*5225e6b1SAndroid Build Coastguard Workerdef _partition(lst: list[str], index: Optional[int]) \
25*5225e6b1SAndroid Build Coastguard Worker        -> Tuple[list[str], Optional[str], list[str]]:
26*5225e6b1SAndroid Build Coastguard Worker    """Returns the triple split by index.
27*5225e6b1SAndroid Build Coastguard Worker
28*5225e6b1SAndroid Build Coastguard Worker    That is, return a tuple:
29*5225e6b1SAndroid Build Coastguard Worker    (everything before index, the element at index, everything after index)
30*5225e6b1SAndroid Build Coastguard Worker
31*5225e6b1SAndroid Build Coastguard Worker    If index is None, return (the list, None, empty list)
32*5225e6b1SAndroid Build Coastguard Worker    """
33*5225e6b1SAndroid Build Coastguard Worker    if index is None:
34*5225e6b1SAndroid Build Coastguard Worker        return lst[:], None, []
35*5225e6b1SAndroid Build Coastguard Worker    return lst[:index], lst[index], lst[index + 1:]
36*5225e6b1SAndroid Build Coastguard Worker
37*5225e6b1SAndroid Build Coastguard Worker
38*5225e6b1SAndroid Build Coastguard Workerclass BazelWrapper(object):
39*5225e6b1SAndroid Build Coastguard Worker    def __init__(self, workspace_dir: pathlib.Path, bazel_args: list[str]):
40*5225e6b1SAndroid Build Coastguard Worker        """Splits arguments to the bazel binary based on the functionality.
41*5225e6b1SAndroid Build Coastguard Worker
42*5225e6b1SAndroid Build Coastguard Worker        bazel [startup_options] command         [command_args] --               [target_patterns]
43*5225e6b1SAndroid Build Coastguard Worker                                 ^- command_idx                ^- dash_dash_idx
44*5225e6b1SAndroid Build Coastguard Worker
45*5225e6b1SAndroid Build Coastguard Worker        See https://bazel.build/reference/command-line-reference
46*5225e6b1SAndroid Build Coastguard Worker
47*5225e6b1SAndroid Build Coastguard Worker        Args:
48*5225e6b1SAndroid Build Coastguard Worker            workspace_dir: root of workspace.
49*5225e6b1SAndroid Build Coastguard Worker            bazel_args: The list of arguments the user provides through command line
50*5225e6b1SAndroid Build Coastguard Worker            env: existing environment
51*5225e6b1SAndroid Build Coastguard Worker        """
52*5225e6b1SAndroid Build Coastguard Worker
53*5225e6b1SAndroid Build Coastguard Worker        self.workspace_dir = workspace_dir
54*5225e6b1SAndroid Build Coastguard Worker
55*5225e6b1SAndroid Build Coastguard Worker        self.bazel_path = self.workspace_dir / _BAZEL_REL_PATH
56*5225e6b1SAndroid Build Coastguard Worker
57*5225e6b1SAndroid Build Coastguard Worker        command_idx = None
58*5225e6b1SAndroid Build Coastguard Worker        for idx, arg in enumerate(bazel_args):
59*5225e6b1SAndroid Build Coastguard Worker            if not arg.startswith("-"):
60*5225e6b1SAndroid Build Coastguard Worker                command_idx = idx
61*5225e6b1SAndroid Build Coastguard Worker                break
62*5225e6b1SAndroid Build Coastguard Worker
63*5225e6b1SAndroid Build Coastguard Worker        self.startup_options, self.command, remaining_args = _partition(bazel_args,
64*5225e6b1SAndroid Build Coastguard Worker                                                                        command_idx)
65*5225e6b1SAndroid Build Coastguard Worker
66*5225e6b1SAndroid Build Coastguard Worker        # Split command_args into `command_args -- target_patterns`
67*5225e6b1SAndroid Build Coastguard Worker        dash_dash_idx = None
68*5225e6b1SAndroid Build Coastguard Worker        try:
69*5225e6b1SAndroid Build Coastguard Worker            dash_dash_idx = remaining_args.index("--")
70*5225e6b1SAndroid Build Coastguard Worker        except ValueError:
71*5225e6b1SAndroid Build Coastguard Worker            # If -- is not found, put everything in command_args. These arguments
72*5225e6b1SAndroid Build Coastguard Worker            # are not provided to the Bazel executable target.
73*5225e6b1SAndroid Build Coastguard Worker            pass
74*5225e6b1SAndroid Build Coastguard Worker
75*5225e6b1SAndroid Build Coastguard Worker        self.command_args, self.dash_dash, self.target_patterns = _partition(remaining_args,
76*5225e6b1SAndroid Build Coastguard Worker                                                                             dash_dash_idx)
77*5225e6b1SAndroid Build Coastguard Worker
78*5225e6b1SAndroid Build Coastguard Worker        self._parse_startup_options()
79*5225e6b1SAndroid Build Coastguard Worker        self._parse_command_args()
80*5225e6b1SAndroid Build Coastguard Worker        self._add_extra_startup_options()
81*5225e6b1SAndroid Build Coastguard Worker
82*5225e6b1SAndroid Build Coastguard Worker    def add_startup_option_to_parser(self, parser):
83*5225e6b1SAndroid Build Coastguard Worker        parser.add_argument(
84*5225e6b1SAndroid Build Coastguard Worker            "-h", "--help", action="store_true",
85*5225e6b1SAndroid Build Coastguard Worker            help="show this help message and exit"
86*5225e6b1SAndroid Build Coastguard Worker        )
87*5225e6b1SAndroid Build Coastguard Worker
88*5225e6b1SAndroid Build Coastguard Worker    def _parse_startup_options(self):
89*5225e6b1SAndroid Build Coastguard Worker        """Parses the given list of startup_options.
90*5225e6b1SAndroid Build Coastguard Worker
91*5225e6b1SAndroid Build Coastguard Worker        After calling this function, the following attributes are set:
92*5225e6b1SAndroid Build Coastguard Worker        - absolute_user_root: A path holding bazel build output location
93*5225e6b1SAndroid Build Coastguard Worker        - transformed_startup_options: The transformed list of startup_options to replace
94*5225e6b1SAndroid Build Coastguard Worker          existing startup_options to be fed to the Bazel binary
95*5225e6b1SAndroid Build Coastguard Worker        """
96*5225e6b1SAndroid Build Coastguard Worker
97*5225e6b1SAndroid Build Coastguard Worker        parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False)
98*5225e6b1SAndroid Build Coastguard Worker        self.add_startup_option_to_parser(parser)
99*5225e6b1SAndroid Build Coastguard Worker
100*5225e6b1SAndroid Build Coastguard Worker        self.known_startup_options, self.user_startup_options = \
101*5225e6b1SAndroid Build Coastguard Worker            parser.parse_known_args(self.startup_options)
102*5225e6b1SAndroid Build Coastguard Worker
103*5225e6b1SAndroid Build Coastguard Worker        self.absolute_out_dir = self.workspace_dir / "out"
104*5225e6b1SAndroid Build Coastguard Worker        self.absolute_user_root = \
105*5225e6b1SAndroid Build Coastguard Worker            self.absolute_out_dir / "bazel/output_user_root"
106*5225e6b1SAndroid Build Coastguard Worker
107*5225e6b1SAndroid Build Coastguard Worker        if self.known_startup_options.help:
108*5225e6b1SAndroid Build Coastguard Worker            self.transformed_startup_options = [
109*5225e6b1SAndroid Build Coastguard Worker                "--help"
110*5225e6b1SAndroid Build Coastguard Worker            ]
111*5225e6b1SAndroid Build Coastguard Worker
112*5225e6b1SAndroid Build Coastguard Worker        if not self.known_startup_options.help:
113*5225e6b1SAndroid Build Coastguard Worker            javatmp = self.absolute_out_dir / "bazel/javatmp"
114*5225e6b1SAndroid Build Coastguard Worker            self.transformed_startup_options = [
115*5225e6b1SAndroid Build Coastguard Worker                f"--host_jvm_args=-Djava.io.tmpdir={javatmp}",
116*5225e6b1SAndroid Build Coastguard Worker            ]
117*5225e6b1SAndroid Build Coastguard Worker
118*5225e6b1SAndroid Build Coastguard Worker        # See _add_extra_startup_options for extra startup options
119*5225e6b1SAndroid Build Coastguard Worker
120*5225e6b1SAndroid Build Coastguard Worker    def _parse_command_args(self):
121*5225e6b1SAndroid Build Coastguard Worker        """Parses the given list of command_args.
122*5225e6b1SAndroid Build Coastguard Worker
123*5225e6b1SAndroid Build Coastguard Worker        After calling this function, the following attributes are set:
124*5225e6b1SAndroid Build Coastguard Worker        - known_args: A namespace holding options known by this Bazel wrapper script
125*5225e6b1SAndroid Build Coastguard Worker        - transformed_command_args: The transformed list of command_args to replace
126*5225e6b1SAndroid Build Coastguard Worker          existing command_args to be fed to the Bazel binary
127*5225e6b1SAndroid Build Coastguard Worker        - env: A dictionary containing the new environment variables for the subprocess.
128*5225e6b1SAndroid Build Coastguard Worker        """
129*5225e6b1SAndroid Build Coastguard Worker
130*5225e6b1SAndroid Build Coastguard Worker        parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False)
131*5225e6b1SAndroid Build Coastguard Worker
132*5225e6b1SAndroid Build Coastguard Worker        # TODO: Delete these args once build bots no longer specify them
133*5225e6b1SAndroid Build Coastguard Worker        parser.add_argument(
134*5225e6b1SAndroid Build Coastguard Worker            "--make_jobs", metavar="JOBS", type=int, default=None,
135*5225e6b1SAndroid Build Coastguard Worker            help="unused")
136*5225e6b1SAndroid Build Coastguard Worker        parser.add_argument(
137*5225e6b1SAndroid Build Coastguard Worker            "--make_keep_going", action="store_true", default=False,
138*5225e6b1SAndroid Build Coastguard Worker            help="unused")
139*5225e6b1SAndroid Build Coastguard Worker        parser.add_argument(
140*5225e6b1SAndroid Build Coastguard Worker            "--repo_manifest", metavar="<repo_root>:<manifest.xml>",
141*5225e6b1SAndroid Build Coastguard Worker            help="unused")
142*5225e6b1SAndroid Build Coastguard Worker
143*5225e6b1SAndroid Build Coastguard Worker        # Skip startup options (before command) and target_patterns (after --)
144*5225e6b1SAndroid Build Coastguard Worker        _, self.transformed_command_args = parser.parse_known_args(
145*5225e6b1SAndroid Build Coastguard Worker            self.command_args)
146*5225e6b1SAndroid Build Coastguard Worker
147*5225e6b1SAndroid Build Coastguard Worker    def _add_extra_startup_options(self):
148*5225e6b1SAndroid Build Coastguard Worker        """Adds extra startup options after command args are parsed."""
149*5225e6b1SAndroid Build Coastguard Worker
150*5225e6b1SAndroid Build Coastguard Worker        self.transformed_startup_options += self.user_startup_options
151*5225e6b1SAndroid Build Coastguard Worker
152*5225e6b1SAndroid Build Coastguard Worker        if not self.known_startup_options.help:
153*5225e6b1SAndroid Build Coastguard Worker            self.transformed_startup_options.append(
154*5225e6b1SAndroid Build Coastguard Worker                f"--output_user_root={self.absolute_user_root}")
155*5225e6b1SAndroid Build Coastguard Worker
156*5225e6b1SAndroid Build Coastguard Worker    def _build_final_args(self) -> list[str]:
157*5225e6b1SAndroid Build Coastguard Worker        """Builds the final arguments for the subprocess."""
158*5225e6b1SAndroid Build Coastguard Worker        # final_args:
159*5225e6b1SAndroid Build Coastguard Worker        # bazel [startup_options] [additional_startup_options] command [transformed_command_args] -- [target_patterns]
160*5225e6b1SAndroid Build Coastguard Worker
161*5225e6b1SAndroid Build Coastguard Worker        final_args = [self.bazel_path] + self.transformed_startup_options
162*5225e6b1SAndroid Build Coastguard Worker
163*5225e6b1SAndroid Build Coastguard Worker        if self.command is not None:
164*5225e6b1SAndroid Build Coastguard Worker            final_args.append(self.command)
165*5225e6b1SAndroid Build Coastguard Worker        final_args += self.transformed_command_args
166*5225e6b1SAndroid Build Coastguard Worker        if self.dash_dash is not None:
167*5225e6b1SAndroid Build Coastguard Worker            final_args.append(self.dash_dash)
168*5225e6b1SAndroid Build Coastguard Worker        final_args += self.target_patterns
169*5225e6b1SAndroid Build Coastguard Worker
170*5225e6b1SAndroid Build Coastguard Worker        return final_args
171*5225e6b1SAndroid Build Coastguard Worker
172*5225e6b1SAndroid Build Coastguard Worker    def run(self) -> int:
173*5225e6b1SAndroid Build Coastguard Worker        """Runs the wrapper.
174*5225e6b1SAndroid Build Coastguard Worker
175*5225e6b1SAndroid Build Coastguard Worker        Returns:
176*5225e6b1SAndroid Build Coastguard Worker            doesn't return"""
177*5225e6b1SAndroid Build Coastguard Worker        final_args = self._build_final_args()
178*5225e6b1SAndroid Build Coastguard Worker
179*5225e6b1SAndroid Build Coastguard Worker        os.execve(path=self.bazel_path, argv=final_args, env=os.environ)
180*5225e6b1SAndroid Build Coastguard Worker
181*5225e6b1SAndroid Build Coastguard Worker
182*5225e6b1SAndroid Build Coastguard Workerdef _bazel_wrapper_main():
183*5225e6b1SAndroid Build Coastguard Worker    # <workspace_dir>/bootable/libbootloader/gbl/bazel.py
184*5225e6b1SAndroid Build Coastguard Worker    workspace_dir = (
185*5225e6b1SAndroid Build Coastguard Worker        pathlib.Path(__file__).resolve().parent.parent.parent.parent)
186*5225e6b1SAndroid Build Coastguard Worker    return BazelWrapper(workspace_dir=workspace_dir,
187*5225e6b1SAndroid Build Coastguard Worker                        bazel_args=sys.argv[1:]).run()
188*5225e6b1SAndroid Build Coastguard Worker
189*5225e6b1SAndroid Build Coastguard Worker
190*5225e6b1SAndroid Build Coastguard Workerif __name__ == "__main__":
191*5225e6b1SAndroid Build Coastguard Worker    sys.exit(_bazel_wrapper_main())
192