xref: /aosp_15_r20/hardware/interfaces/compatibility_matrices/bump.py (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*4d7e907cSAndroid Build Coastguard Worker#
3*4d7e907cSAndroid Build Coastguard Worker# Copyright (C) 2023 The Android Open Source Project
4*4d7e907cSAndroid Build Coastguard Worker#
5*4d7e907cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*4d7e907cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*4d7e907cSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*4d7e907cSAndroid Build Coastguard Worker#
9*4d7e907cSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*4d7e907cSAndroid Build Coastguard Worker#
11*4d7e907cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*4d7e907cSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*4d7e907cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*4d7e907cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*4d7e907cSAndroid Build Coastguard Worker# limitations under the License.
16*4d7e907cSAndroid Build Coastguard Worker#
17*4d7e907cSAndroid Build Coastguard Worker"""
18*4d7e907cSAndroid Build Coastguard WorkerCreates the next compatibility matrix.
19*4d7e907cSAndroid Build Coastguard Worker"""
20*4d7e907cSAndroid Build Coastguard Worker
21*4d7e907cSAndroid Build Coastguard Workerimport argparse
22*4d7e907cSAndroid Build Coastguard Workerimport os
23*4d7e907cSAndroid Build Coastguard Workerimport pathlib
24*4d7e907cSAndroid Build Coastguard Workerimport re
25*4d7e907cSAndroid Build Coastguard Workerimport subprocess
26*4d7e907cSAndroid Build Coastguard Workerimport textwrap
27*4d7e907cSAndroid Build Coastguard Worker
28*4d7e907cSAndroid Build Coastguard Worker
29*4d7e907cSAndroid Build Coastguard Workerdef check_call(*args, **kwargs):
30*4d7e907cSAndroid Build Coastguard Worker    print(args)
31*4d7e907cSAndroid Build Coastguard Worker    subprocess.check_call(*args, **kwargs)
32*4d7e907cSAndroid Build Coastguard Worker
33*4d7e907cSAndroid Build Coastguard Worker
34*4d7e907cSAndroid Build Coastguard Workerdef check_output(*args, **kwargs):
35*4d7e907cSAndroid Build Coastguard Worker    print(args)
36*4d7e907cSAndroid Build Coastguard Worker    return subprocess.check_output(*args, **kwargs)
37*4d7e907cSAndroid Build Coastguard Worker
38*4d7e907cSAndroid Build Coastguard Worker
39*4d7e907cSAndroid Build Coastguard Workerclass Bump(object):
40*4d7e907cSAndroid Build Coastguard Worker
41*4d7e907cSAndroid Build Coastguard Worker    def __init__(self, cmdline_args):
42*4d7e907cSAndroid Build Coastguard Worker        self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
43*4d7e907cSAndroid Build Coastguard Worker        self.interfaces_dir = self.top / "hardware/interfaces"
44*4d7e907cSAndroid Build Coastguard Worker
45*4d7e907cSAndroid Build Coastguard Worker        self.current_level = cmdline_args.current_level
46*4d7e907cSAndroid Build Coastguard Worker        self.current_letter = cmdline_args.current_letter
47*4d7e907cSAndroid Build Coastguard Worker        self.current_version = cmdline_args.platform_version
48*4d7e907cSAndroid Build Coastguard Worker        self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
49*4d7e907cSAndroid Build Coastguard Worker        self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
50*4d7e907cSAndroid Build Coastguard Worker        self.device_module_name = "framework_compatibility_matrix.device.xml"
51*4d7e907cSAndroid Build Coastguard Worker
52*4d7e907cSAndroid Build Coastguard Worker        self.next_level = cmdline_args.next_level
53*4d7e907cSAndroid Build Coastguard Worker        self.next_letter = cmdline_args.next_letter
54*4d7e907cSAndroid Build Coastguard Worker        self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
55*4d7e907cSAndroid Build Coastguard Worker        self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
56*4d7e907cSAndroid Build Coastguard Worker
57*4d7e907cSAndroid Build Coastguard Worker    def run(self):
58*4d7e907cSAndroid Build Coastguard Worker        self.bump_kernel_configs()
59*4d7e907cSAndroid Build Coastguard Worker        self.copy_matrix()
60*4d7e907cSAndroid Build Coastguard Worker        self.edit_android_bp()
61*4d7e907cSAndroid Build Coastguard Worker        self.bump_libvintf()
62*4d7e907cSAndroid Build Coastguard Worker
63*4d7e907cSAndroid Build Coastguard Worker    def bump_kernel_configs(self):
64*4d7e907cSAndroid Build Coastguard Worker        check_call([
65*4d7e907cSAndroid Build Coastguard Worker            self.top / "kernel/configs/tools/bump.py",
66*4d7e907cSAndroid Build Coastguard Worker            self.current_letter.lower(),
67*4d7e907cSAndroid Build Coastguard Worker            self.next_letter.lower(),
68*4d7e907cSAndroid Build Coastguard Worker        ])
69*4d7e907cSAndroid Build Coastguard Worker
70*4d7e907cSAndroid Build Coastguard Worker    def copy_matrix(self):
71*4d7e907cSAndroid Build Coastguard Worker        with open(self.current_xml) as f_current, open(self.next_xml, "w") as f_next:
72*4d7e907cSAndroid Build Coastguard Worker            f_next.write(f_current.read().replace(f"level=\"{self.current_level}\"", f"level=\"{self.next_level}\""))
73*4d7e907cSAndroid Build Coastguard Worker
74*4d7e907cSAndroid Build Coastguard Worker    def edit_android_bp(self):
75*4d7e907cSAndroid Build Coastguard Worker        android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
76*4d7e907cSAndroid Build Coastguard Worker
77*4d7e907cSAndroid Build Coastguard Worker        with open(android_bp, "r+") as f:
78*4d7e907cSAndroid Build Coastguard Worker            if self.next_module_name not in f.read():
79*4d7e907cSAndroid Build Coastguard Worker                f.seek(0, 2)  # end of file
80*4d7e907cSAndroid Build Coastguard Worker                f.write("\n")
81*4d7e907cSAndroid Build Coastguard Worker                f.write(
82*4d7e907cSAndroid Build Coastguard Worker                    textwrap.dedent(f"""\
83*4d7e907cSAndroid Build Coastguard Worker                        vintf_compatibility_matrix {{
84*4d7e907cSAndroid Build Coastguard Worker                            name: "{self.next_module_name}",
85*4d7e907cSAndroid Build Coastguard Worker                        }}
86*4d7e907cSAndroid Build Coastguard Worker                    """))
87*4d7e907cSAndroid Build Coastguard Worker
88*4d7e907cSAndroid Build Coastguard Worker        next_kernel_configs = check_output(
89*4d7e907cSAndroid Build Coastguard Worker            """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
90*4d7e907cSAndroid Build Coastguard Worker            cwd=self.top / "kernel/configs" /
91*4d7e907cSAndroid Build Coastguard Worker            self.next_letter.lower(),
92*4d7e907cSAndroid Build Coastguard Worker            text=True,
93*4d7e907cSAndroid Build Coastguard Worker            shell=True,
94*4d7e907cSAndroid Build Coastguard Worker        ).splitlines()
95*4d7e907cSAndroid Build Coastguard Worker        print(next_kernel_configs)
96*4d7e907cSAndroid Build Coastguard Worker
97*4d7e907cSAndroid Build Coastguard Worker        check_call([
98*4d7e907cSAndroid Build Coastguard Worker            "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
99*4d7e907cSAndroid Build Coastguard Worker            "-str", self.next_xml.name, android_bp
100*4d7e907cSAndroid Build Coastguard Worker        ])
101*4d7e907cSAndroid Build Coastguard Worker
102*4d7e907cSAndroid Build Coastguard Worker        check_call([
103*4d7e907cSAndroid Build Coastguard Worker            "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
104*4d7e907cSAndroid Build Coastguard Worker            "-a",
105*4d7e907cSAndroid Build Coastguard Worker            self.next_xml.relative_to(android_bp.parent), android_bp
106*4d7e907cSAndroid Build Coastguard Worker        ])
107*4d7e907cSAndroid Build Coastguard Worker
108*4d7e907cSAndroid Build Coastguard Worker        check_call([
109*4d7e907cSAndroid Build Coastguard Worker            "bpmodify", "-w", "-m", self.next_module_name, "-property",
110*4d7e907cSAndroid Build Coastguard Worker            "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
111*4d7e907cSAndroid Build Coastguard Worker        ])
112*4d7e907cSAndroid Build Coastguard Worker
113*4d7e907cSAndroid Build Coastguard Worker        # update the SYSTEM_MATRIX_DEPS variable and the phony module's
114*4d7e907cSAndroid Build Coastguard Worker        # product_variables entry.
115*4d7e907cSAndroid Build Coastguard Worker        lines = []
116*4d7e907cSAndroid Build Coastguard Worker        with open(android_bp) as f:
117*4d7e907cSAndroid Build Coastguard Worker            for line in f:
118*4d7e907cSAndroid Build Coastguard Worker              if f"    \"{self.device_module_name}\",\n" in line:
119*4d7e907cSAndroid Build Coastguard Worker                  lines.append(f"    \"{self.current_module_name}\",\n")
120*4d7e907cSAndroid Build Coastguard Worker
121*4d7e907cSAndroid Build Coastguard Worker              if f"                \"{self.current_module_name}\",\n" in line:
122*4d7e907cSAndroid Build Coastguard Worker                  lines.append(f"                \"{self.next_module_name}\",\n")
123*4d7e907cSAndroid Build Coastguard Worker              else:
124*4d7e907cSAndroid Build Coastguard Worker                  lines.append(line)
125*4d7e907cSAndroid Build Coastguard Worker
126*4d7e907cSAndroid Build Coastguard Worker        with open(android_bp, "w") as f:
127*4d7e907cSAndroid Build Coastguard Worker            f.write("".join(lines))
128*4d7e907cSAndroid Build Coastguard Worker
129*4d7e907cSAndroid Build Coastguard Worker    def bump_libvintf(self):
130*4d7e907cSAndroid Build Coastguard Worker        if not self.current_version:
131*4d7e907cSAndroid Build Coastguard Worker            print("Skip libvintf update...")
132*4d7e907cSAndroid Build Coastguard Worker            return
133*4d7e907cSAndroid Build Coastguard Worker        try:
134*4d7e907cSAndroid Build Coastguard Worker            check_call(["grep", "-h",
135*4d7e907cSAndroid Build Coastguard Worker                        f"{self.current_letter.upper()} = {self.current_level}",
136*4d7e907cSAndroid Build Coastguard Worker                        "system/libvintf/include/vintf/Level.h"])
137*4d7e907cSAndroid Build Coastguard Worker        except subprocess.CalledProcessError:
138*4d7e907cSAndroid Build Coastguard Worker            print("Adding new API level to libvintf")
139*4d7e907cSAndroid Build Coastguard Worker            add_lines_above("system/libvintf/analyze_matrix/analyze_matrix.cpp",
140*4d7e907cSAndroid Build Coastguard Worker                            "        case Level::UNSPECIFIED:",
141*4d7e907cSAndroid Build Coastguard Worker                            textwrap.indent(textwrap.dedent(f"""\
142*4d7e907cSAndroid Build Coastguard Worker                                    case Level::{self.current_letter.upper()}:
143*4d7e907cSAndroid Build Coastguard Worker                                        return "Android {self.current_version} ({self.current_letter.upper()})";"""),
144*4d7e907cSAndroid Build Coastguard Worker                            "    "*2))
145*4d7e907cSAndroid Build Coastguard Worker            add_lines_above("system/libvintf/include/vintf/Level.h",
146*4d7e907cSAndroid Build Coastguard Worker                            "    // To add new values:",
147*4d7e907cSAndroid Build Coastguard Worker                            f"    {self.current_letter.upper()} = {self.current_level},")
148*4d7e907cSAndroid Build Coastguard Worker            add_lines_above("system/libvintf/include/vintf/Level.h",
149*4d7e907cSAndroid Build Coastguard Worker                            "        Level::UNSPECIFIED,",
150*4d7e907cSAndroid Build Coastguard Worker                            f"        Level::{self.current_letter.upper()},")
151*4d7e907cSAndroid Build Coastguard Worker            add_lines_above("system/libvintf/RuntimeInfo.cpp",
152*4d7e907cSAndroid Build Coastguard Worker                            "            // Add more levels above this line.",
153*4d7e907cSAndroid Build Coastguard Worker                            textwrap.indent(textwrap.dedent(f"""\
154*4d7e907cSAndroid Build Coastguard Worker                                        case {self.current_version}: {{
155*4d7e907cSAndroid Build Coastguard Worker                                            ret = Level::{self.current_letter.upper()};
156*4d7e907cSAndroid Build Coastguard Worker                                        }} break;"""),
157*4d7e907cSAndroid Build Coastguard Worker                            "    "*3))
158*4d7e907cSAndroid Build Coastguard Worker
159*4d7e907cSAndroid Build Coastguard Worker
160*4d7e907cSAndroid Build Coastguard Workerdef add_lines_above(file, pattern, lines):
161*4d7e907cSAndroid Build Coastguard Worker    with open(file, 'r+') as f:
162*4d7e907cSAndroid Build Coastguard Worker        text = f.read()
163*4d7e907cSAndroid Build Coastguard Worker        split_text = re.split(rf"\n{pattern}\n", text)
164*4d7e907cSAndroid Build Coastguard Worker        if len(split_text) != 2:
165*4d7e907cSAndroid Build Coastguard Worker            # Only one pattern must be found, otherwise the source must be
166*4d7e907cSAndroid Build Coastguard Worker            # changed unexpectedly.
167*4d7e907cSAndroid Build Coastguard Worker            raise Exception(
168*4d7e907cSAndroid Build Coastguard Worker                f'Pattern "{pattern}" not found or multiple patterns found in {file}')
169*4d7e907cSAndroid Build Coastguard Worker        f.seek(0)
170*4d7e907cSAndroid Build Coastguard Worker        f.write(f"\n{lines}\n{pattern}\n".join(split_text))
171*4d7e907cSAndroid Build Coastguard Worker        f.truncate()
172*4d7e907cSAndroid Build Coastguard Worker
173*4d7e907cSAndroid Build Coastguard Worker
174*4d7e907cSAndroid Build Coastguard Workerdef main():
175*4d7e907cSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description=__doc__)
176*4d7e907cSAndroid Build Coastguard Worker    parser.add_argument("current_level",
177*4d7e907cSAndroid Build Coastguard Worker                        type=str,
178*4d7e907cSAndroid Build Coastguard Worker                        help="VINTF level of the current version (e.g. 202404)")
179*4d7e907cSAndroid Build Coastguard Worker    parser.add_argument("next_level",
180*4d7e907cSAndroid Build Coastguard Worker                        type=str,
181*4d7e907cSAndroid Build Coastguard Worker                        help="VINTF level of the next version (e.g. 202504)")
182*4d7e907cSAndroid Build Coastguard Worker    parser.add_argument("current_letter",
183*4d7e907cSAndroid Build Coastguard Worker                        type=str,
184*4d7e907cSAndroid Build Coastguard Worker                        help="Letter of the API level of the current version (e.g. v)")
185*4d7e907cSAndroid Build Coastguard Worker    parser.add_argument("next_letter",
186*4d7e907cSAndroid Build Coastguard Worker                        type=str,
187*4d7e907cSAndroid Build Coastguard Worker                        help="Letter of the API level of the next version (e.g. w)")
188*4d7e907cSAndroid Build Coastguard Worker    parser.add_argument("platform_version",
189*4d7e907cSAndroid Build Coastguard Worker                        type=str,
190*4d7e907cSAndroid Build Coastguard Worker                        nargs="?",
191*4d7e907cSAndroid Build Coastguard Worker                        help="Android release version number number (e.g. 15)")
192*4d7e907cSAndroid Build Coastguard Worker    cmdline_args = parser.parse_args()
193*4d7e907cSAndroid Build Coastguard Worker
194*4d7e907cSAndroid Build Coastguard Worker    Bump(cmdline_args).run()
195*4d7e907cSAndroid Build Coastguard Worker
196*4d7e907cSAndroid Build Coastguard Worker
197*4d7e907cSAndroid Build Coastguard Workerif __name__ == "__main__":
198*4d7e907cSAndroid Build Coastguard Worker    main()
199