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