blob: 88b7a42013a7bd5f3e31d9fd449972f33a8734b7 [file] [log] [blame]
Yifan Hongace13de2023-04-28 15:54:04 -07001#!/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
20Requires libvintf Level.h to be updated before executing this script.
21"""
22
23import argparse
24import os
25import pathlib
26import shutil
27import subprocess
28import textwrap
29
30
31def check_call(*args, **kwargs):
32 print(args)
33 subprocess.check_call(*args, **kwargs)
34
35
36def check_output(*args, **kwargs):
37 print(args)
38 return subprocess.check_output(*args, **kwargs)
39
40
41class Bump(object):
42
43 def __init__(self, cmdline_args):
44 self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
45 self.interfaces_dir = self.top / "hardware/interfaces"
46
47 self.current_level = cmdline_args.current
48 self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
49 self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
50
51 self.next_level = cmdline_args.next
52 self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
53 self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
54
55 self.level_to_letter = self.get_level_to_letter_mapping()
56 print("Found level mapping in libvintf Level.h:", self.level_to_letter)
57
58 def run(self):
59 self.bump_kernel_configs()
60 self.copy_matrix()
61 self.edit_android_bp()
62 self.edit_android_mk()
63
64 def get_level_to_letter_mapping(self):
65 levels_file = self.top / "system/libvintf/include/vintf/Level.h"
66 with open(levels_file) as f:
67 lines = f.readlines()
68 pairs = [
69 line.split("=", maxsplit=2) for line in lines if "=" in line
70 ]
71 return {
72 level.strip().removesuffix(","): letter.strip()
73 for letter, level in pairs
74 }
75
76 def bump_kernel_configs(self):
77 check_call([
78 self.top / "kernel/configs/tools/bump.py",
79 self.level_to_letter[self.current_level].lower(),
80 self.level_to_letter[self.next_level].lower(),
81 ])
82
83 def copy_matrix(self):
84 shutil.copyfile(self.current_xml, self.next_xml)
85
86 def edit_android_bp(self):
87 android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
88
89 with open(android_bp, "r+") as f:
90 if self.next_module_name not in f.read():
91 f.seek(0, 2) # end of file
92 f.write("\n")
93 f.write(
94 textwrap.dedent(f"""\
95 vintf_compatibility_matrix {{
96 name: "{self.next_module_name}",
97 }}
98 """))
99
100 next_kernel_configs = check_output(
101 """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
102 cwd=self.top / "kernel/configs" /
103 self.level_to_letter[self.next_level].lower(),
104 text=True,
105 shell=True,
106 ).splitlines()
107 print(next_kernel_configs)
108
109 check_call([
110 "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
111 "-str", self.next_xml.name, android_bp
112 ])
113
114 check_call([
115 "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
116 "-a",
117 self.next_xml.relative_to(android_bp.parent), android_bp
118 ])
119
120 check_call([
121 "bpmodify", "-w", "-m", self.next_module_name, "-property",
122 "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
123 ])
124
125 def edit_android_mk(self):
126 android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
127 with open(android_mk) as f:
128 if self.next_module_name in f.read():
129 return
130 f.seek(0)
131 lines = f.readlines()
132 current_module_line_number = None
133 for line_number, line in enumerate(lines):
134 if self.current_module_name in line:
135 current_module_line_number = line_number
136 break
137 assert current_module_line_number is not None
138 lines.insert(current_module_line_number + 1,
139 f" {self.next_module_name} \\\n")
140 with open(android_mk, "w") as f:
141 f.write("".join(lines))
142
143
144def main():
145 parser = argparse.ArgumentParser(description=__doc__)
146 parser.add_argument("current",
147 type=str,
148 help="VINTF level of the current version (e.g. 9)")
149 parser.add_argument("next",
150 type=str,
151 help="VINTF level of the next version (e.g. 10)")
152 cmdline_args = parser.parse_args()
153
154 Bump(cmdline_args).run()
155
156
157if __name__ == "__main__":
158 main()