1#!/usr/bin/env python
2#
3# Copyright (C) 2022 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"""Command line tool to convert API files to sdk-extensions-info.
17
18Example use:
19
20  $ ./api-to-sdk-ext-info.py $(gettop)/prebuilts/sdk/extensions/1/public/api/framework-sdkextensions.txt >/tmp/1.txt
21  $ ./api-to-sdk-ext-info.py $(gettop)/prebuilts/sdk/extensions/2/public/api/framework-sdkextensions.txt >/tmp/2.txt
22  $ diff /tmp/{1,2}.txt
23  0a1,2
24  > android.os.ext.SdkExtensions.getAllExtensionVersions
25  > android.os.ext.SdkExtensions.getExtensionVersion
26"""
27
28import re
29import sys
30
31re_package = re.compile(r"^package (.*?) \{(.*?)^\}", re.M + re.S)
32re_class = re.compile(r"^  .*? (?:class|interface) (\S+) .*?\{(.*?)^  \}", re.M + re.S)
33re_method = re.compile("^    (?:ctor|method).* (\S+)\([^)]*\);", re.M)
34re_field = re.compile(r"^    field.* (\S+)(?: =.*);", re.M)
35
36
37def parse_class(package_name, class_name, contents):
38    def print_members(regex, contents):
39        # sdk-extensions-info ignores method signatures: overloaded methods are
40        # collapsed into the same item; use a set to get this behaviour for free
41        members = set()
42        for symbol_name in regex.findall(contents):
43            members.add(f"{package_name}.{class_name}.{symbol_name}")
44        if len(members) > 0:
45            print("\n".join(sorted(members)))
46
47    print_members(re_field, contents)
48    print_members(re_method, contents)
49
50
51def parse_package(package_name, contents):
52    for match in re_class.findall(contents):
53        parse_class(package_name, match[0], match[1])
54
55
56def main():
57    with open(sys.argv[1]) as f:
58        contents = f.read()
59
60    if contents.splitlines()[0] != "// Signature format: 2.0":
61        raise "unexpected file format"
62    for match in re_package.findall(contents):
63        parse_package(match[0], match[1])
64
65
66if __name__ == "__main__":
67    main()
68