1#!/usr/bin/env python3 2# 3# Copyright (C) 2023 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17""" 18Creates the next compatibility matrix. 19""" 20 21import argparse 22import os 23import pathlib 24import shutil 25import subprocess 26import textwrap 27 28 29def check_call(*args, **kwargs): 30 print(args) 31 subprocess.check_call(*args, **kwargs) 32 33 34def check_output(*args, **kwargs): 35 print(args) 36 return subprocess.check_output(*args, **kwargs) 37 38 39class Bump(object): 40 41 def __init__(self, cmdline_args): 42 self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"]) 43 self.interfaces_dir = self.top / "hardware/interfaces" 44 45 self.current_level = cmdline_args.current_level 46 self.current_letter = cmdline_args.current_letter 47 self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml" 48 self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml" 49 self.device_module_name = "framework_compatibility_matrix.device.xml" 50 51 self.next_level = cmdline_args.next_level 52 self.next_letter = cmdline_args.next_letter 53 self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml" 54 self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml" 55 56 def run(self): 57 self.bump_kernel_configs() 58 self.copy_matrix() 59 self.edit_android_bp() 60 self.edit_android_mk() 61 62 def bump_kernel_configs(self): 63 check_call([ 64 self.top / "kernel/configs/tools/bump.py", 65 self.current_letter, 66 self.next_letter, 67 ]) 68 69 def copy_matrix(self): 70 with open(self.current_xml) as f_current, open(self.next_xml, "w") as f_next: 71 f_next.write(f_current.read().replace(f"level=\"{self.current_level}\"", f"level=\"{self.next_level}\"")) 72 73 def edit_android_bp(self): 74 android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp" 75 76 with open(android_bp, "r+") as f: 77 if self.next_module_name not in f.read(): 78 f.seek(0, 2) # end of file 79 f.write("\n") 80 f.write( 81 textwrap.dedent(f"""\ 82 vintf_compatibility_matrix {{ 83 name: "{self.next_module_name}", 84 }} 85 """)) 86 87 next_kernel_configs = check_output( 88 """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""", 89 cwd=self.top / "kernel/configs" / 90 self.next_letter, 91 text=True, 92 shell=True, 93 ).splitlines() 94 print(next_kernel_configs) 95 96 check_call([ 97 "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem", 98 "-str", self.next_xml.name, android_bp 99 ]) 100 101 check_call([ 102 "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs", 103 "-a", 104 self.next_xml.relative_to(android_bp.parent), android_bp 105 ]) 106 107 check_call([ 108 "bpmodify", "-w", "-m", self.next_module_name, "-property", 109 "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp 110 ]) 111 112 def edit_android_mk(self): 113 android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk" 114 lines = [] 115 with open(android_mk) as f: 116 if self.next_module_name in f.read(): 117 return 118 f.seek(0) 119 for line in f: 120 if f" {self.device_module_name} \\\n" in line: 121 lines.append(f" {self.current_module_name} \\\n") 122 123 if self.current_module_name in line: 124 lines.append(f" {self.next_module_name} \\\n") 125 else: 126 lines.append(line) 127 128 with open(android_mk, "w") as f: 129 f.write("".join(lines)) 130 131 132def main(): 133 parser = argparse.ArgumentParser(description=__doc__) 134 parser.add_argument("current_level", 135 type=str, 136 help="VINTF level of the current version (e.g. 9)") 137 parser.add_argument("next_level", 138 type=str, 139 help="VINTF level of the next version (e.g. 10)") 140 parser.add_argument("current_letter", 141 type=str, 142 help="Letter of the API level of the current version (e.g. v)") 143 parser.add_argument("next_letter", 144 type=str, 145 help="Letter of the API level of the next version (e.g. w)") 146 cmdline_args = parser.parse_args() 147 148 Bump(cmdline_args).run() 149 150 151if __name__ == "__main__": 152 main() 153