• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#  Copyright (C) 2023 The Android Open Source Project
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14
15# The following script will parse two source trees and list which APIs were added.
16# Example Usage:
17# python3 /ssd/master/packages/services/Car/tools/GenericCarApiBuilder/scripts/diff_apis_versions.py
18# "/ssd/tm-qpr-dev" "/ssd/master"
19
20import sys
21import os
22import subprocess
23import re
24import csv
25
26from tempfile import NamedTemporaryFile
27
28exempt_apis = [
29    "equals",
30    "hashCode",
31    "finalize",
32    "writeToParcel",
33    "describeContents",
34    "release",
35    "onCarDisconnected",
36    "toString",
37    "dump"
38]
39
40# Strip the fully qualified names from argument names
41# Ex. android.os.Parcel -> Parcel
42def strip_param_prefixes(api):
43    index = api.find("(")
44    args = api[index+1:].split(",")
45    stripped = [arg.split(".")[-1].strip() for arg in args]
46    return api[:index+1] + ",".join(stripped)
47
48# Format an API name into this format packageName.className#methodName()
49def format_name(api):
50    api_split = api.split()
51    formatted = api_split[0] + "." + api_split[1] + "#" + "".join(api_split[3:])
52    return strip_param_prefixes(formatted)
53
54def strip_param_names(api):
55    argGroup = re.search("\((.*)\)",api)
56    if argGroup is None:
57        return api
58    arg = argGroup.group(0)
59    new_arg = re.sub('[^ (]*?(?=\))|[^ ]*?(?=,)', "", arg)
60    return re.sub("\((.*)\)", new_arg, api)
61
62if (len(sys.argv) < 3):
63    print("Need three arguments: <old repo location> <new repo location>")
64    sys.exit(1)
65oldDir = sys.argv[1]
66newDir = sys.argv[2]
67
68java_cmd= "java -jar " + newDir + "/packages/services/Car/tools/GenericCarApiBuilder" \
69                                  "/GenericCarApiBuilder.jar " \
70                                  "--print-all-apis " \
71                                  "--root-dir " + oldDir
72
73java_cmd_2= "java -jar " + newDir + "/packages/services/Car/tools/GenericCarApiBuilder" \
74                                    "/GenericCarApiBuilder.jar " \
75                                    "--print-all-apis " \
76                                    "--root-dir " + newDir
77
78processes = []
79cmds = [java_cmd, java_cmd_2]
80for cmd in cmds:
81    f = NamedTemporaryFile()
82    p = subprocess.Popen(cmd, shell=True, stdout=f)
83    processes.append((p, f))
84
85results = []
86for p, f in processes:
87    p.wait()
88    f.seek(0)
89    results.append(f.read().decode('utf-8').strip().split("\n"))
90    f.close()
91
92old_apis, new_apis = results[0], results[1]
93old_apis = [strip_param_names(i) for i in old_apis]
94new_apis = [strip_param_names(i) for i in new_apis]
95
96new_apis = [format_name(i) for i in new_apis if i not in old_apis]
97
98# Get the build numbers for the last 5 builds:
99cmd_str = "f1-sql --csv_print_column_names=true --csv_output=true --input_file=buildnums-sql-query --output_file=\"buildnums-results.csv\" --print_queries=false;"
100subprocess.run(cmd_str, shell=True)
101
102build_nums = []
103with open("buildnums-results.csv") as fp:
104    next(fp)
105    for row in fp:
106        build_nums.append(row.strip())
107
108for i in build_nums:
109    print(i)
110
111# Get the query results from F1
112data_read = set()
113for build_num in build_nums:
114    f = open('api-coverage-sql-query', 'r')
115    filedata = f.read()
116    f.close()
117
118    newdata = filedata.replace('build_num', build_num)
119
120    f = open('api-coverage-sql-query', 'w')
121    f.write(newdata)
122    f.close()
123
124    print(newdata)
125    cmd_str = "f1-sql --csv_print_column_names=true --csv_output=true --input_file=api-coverage-sql-query --output_file=\"api-coverage-results.csv\" --print_queries=false;"
126    subprocess.run(cmd_str, shell=True)
127
128    # Writeback the old query data.
129    f = open('api-coverage-sql-query', 'w')
130    f.write(filedata)
131    f.close()
132
133    current_data = []
134    with open("api-coverage-results.csv") as fp:
135        for row in fp:
136            current_data.append(strip_param_prefixes(row.replace("$", ".").replace("\"", "").strip()))
137
138    if len(data_read) == 0:
139        data_read = set(current_data)
140        continue
141
142    # Save the intersection of data over multiple runs.
143    data_read = data_read.intersection(set(current_data))
144
145print("**********THE FOLLOWING APIS HAVE BEEN ADDED FROM " + oldDir + " TO " + newDir + "************")
146f = open("apis-without-coverage.txt", "w")
147for api in data_read:
148    if api in new_apis and not any(exempt in api for exempt in exempt_apis):
149        print(api)
150        f.write(api + "\n")
151
152f.close()
153
154# Clean up csv files
155subprocess.run("rm api-coverage-results.csv", shell=True)
156subprocess.run("rm buildnums-results.csv", shell=True)
157