OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """api_static_checks.py - Check Cronet implementation does not call through | 6 """api_static_checks.py - Enforce Cronet API requirements.""" |
7 API classes. | |
8 """ | |
9 | 7 |
10 import argparse | 8 import argparse |
11 import os | 9 import os |
12 import re | 10 import re |
13 import shutil | 11 import shutil |
14 import sys | 12 import sys |
15 import tempfile | 13 import tempfile |
16 | 14 |
| 15 import update_api |
| 16 |
17 REPOSITORY_ROOT = os.path.abspath(os.path.join( | 17 REPOSITORY_ROOT = os.path.abspath(os.path.join( |
18 os.path.dirname(__file__), '..', '..', '..')) | 18 os.path.dirname(__file__), '..', '..', '..')) |
19 | 19 |
20 sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util')) | 20 sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util')) |
21 import build_utils | 21 import build_utils |
22 | 22 |
23 # These regular expressions catch the beginning of lines that declar classes and | 23 # These regular expressions catch the beginning of lines that declar classes and |
24 # methods. The first group returned by a match is the class or method name. | 24 # methods. The first group returned by a match is the class or method name. |
25 CLASS_RE = re.compile(r'.*class ([^ ]*) .*{') | 25 from update_api import CLASS_RE |
26 METHOD_RE = re.compile(r'.* ([^ ]*)\(.*\);') | 26 METHOD_RE = re.compile(r'.* ([^ ]*)\(.*\);') |
27 | 27 |
28 # Allowed exceptions. Adding anything to this list is dangerous and should be | 28 # Allowed exceptions. Adding anything to this list is dangerous and should be |
29 # avoided if possible. For now these exceptions are for APIs that existed in | 29 # avoided if possible. For now these exceptions are for APIs that existed in |
30 # the first version of Cronet and will be supported forever. | 30 # the first version of Cronet and will be supported forever. |
31 # TODO(pauljensen): Remove these. | 31 # TODO(pauljensen): Remove these. |
32 ALLOWED_EXCEPTIONS = [ | 32 ALLOWED_EXCEPTIONS = [ |
33 'org.chromium.net.impl.CronetEngineBuilderImpl/build ->' | 33 'org.chromium.net.impl.CronetEngineBuilderImpl/build ->' |
34 ' org/chromium/net/ExperimentalCronetEngine/getVersionString', | 34 ' org/chromium/net/ExperimentalCronetEngine/getVersionString', |
35 'org.chromium.net.urlconnection.CronetFixedModeOutputStream$UploadDataProviderI' | 35 'org.chromium.net.urlconnection.CronetFixedModeOutputStream$UploadDataProviderI' |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 # Ignore VersionSafe calls | 86 # Ignore VersionSafe calls |
87 if 'VersionSafeCallbacks' in caller_class: | 87 if 'VersionSafeCallbacks' in caller_class: |
88 continue | 88 continue |
89 bad_call = '%s/%s -> %s/%s' % (caller_class, caller_method, | 89 bad_call = '%s/%s -> %s/%s' % (caller_class, caller_method, |
90 callee_class, callee_method) | 90 callee_class, callee_method) |
91 if bad_call in ALLOWED_EXCEPTIONS: | 91 if bad_call in ALLOWED_EXCEPTIONS: |
92 continue | 92 continue |
93 bad_calls += [bad_call] | 93 bad_calls += [bad_call] |
94 | 94 |
95 | 95 |
96 def main(args): | 96 def check_api_calls(opts): |
97 # Returns True if no calls through API classes in implementation. | 97 # Returns True if no calls through API classes in implementation. |
98 | 98 |
99 parser = argparse.ArgumentParser( | |
100 description='Check modules do not contain ARM Neon instructions.') | |
101 parser.add_argument('--api_jar', | |
102 help='Path to API jar (i.e. cronet_api.jar)', | |
103 required=True, | |
104 metavar='path/to/cronet_api.jar') | |
105 parser.add_argument('--impl_jar', | |
106 help='Path to implementation jar ' | |
107 '(i.e. cronet_impl_native_java.jar)', | |
108 required=True, | |
109 metavar='path/to/cronet_impl_native_java.jar', | |
110 action='append') | |
111 parser.add_argument('--stamp', help='Path to touch on success.') | |
112 opts = parser.parse_args(args) | |
113 | |
114 temp_dir = tempfile.mkdtemp() | 99 temp_dir = tempfile.mkdtemp() |
115 | 100 |
116 # Extract API class files from jar | 101 # Extract API class files from jar |
117 jar_cmd = ['jar', 'xf', os.path.abspath(opts.api_jar)] | 102 jar_cmd = ['jar', 'xf', os.path.abspath(opts.api_jar)] |
118 build_utils.CheckOutput(jar_cmd, cwd=temp_dir) | 103 build_utils.CheckOutput(jar_cmd, cwd=temp_dir) |
119 shutil.rmtree(os.path.join(temp_dir, 'META-INF')) | 104 shutil.rmtree(os.path.join(temp_dir, 'META-INF')) |
120 | 105 |
121 # Collect names of API classes | 106 # Collect names of API classes |
122 api_classes = [] | 107 api_classes = [] |
123 for root, _, filenames in os.walk(temp_dir): | 108 for root, _, filenames in os.walk(temp_dir): |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 find_api_calls(dump, api_classes, api_calls) | 140 find_api_calls(dump, api_classes, api_calls) |
156 | 141 |
157 shutil.rmtree(temp_dir) | 142 shutil.rmtree(temp_dir) |
158 | 143 |
159 if api_calls: | 144 if api_calls: |
160 print 'ERROR: Found the following calls from implementation classes through' | 145 print 'ERROR: Found the following calls from implementation classes through' |
161 print ' API classes. These could fail if older API is used that' | 146 print ' API classes. These could fail if older API is used that' |
162 print ' does not contain newer methods. Please call through a' | 147 print ' does not contain newer methods. Please call through a' |
163 print ' wrapper class from VersionSafeCallbacks.' | 148 print ' wrapper class from VersionSafeCallbacks.' |
164 print '\n'.join(api_calls) | 149 print '\n'.join(api_calls) |
165 | |
166 if not api_calls and opts.stamp: | |
167 build_utils.Touch(opts.stamp) | |
168 return not api_calls | 150 return not api_calls |
169 | 151 |
170 | 152 |
| 153 def check_api_version(opts): |
| 154 if update_api.check_up_to_date(opts.api_jar): |
| 155 return True |
| 156 print 'ERROR: API file out of date. Please run this command:' |
| 157 print ' components/cronet/tools/update_api.py --api_jar %s' % ( |
| 158 os.path.abspath(opts.api_jar)) |
| 159 return False |
| 160 |
| 161 |
| 162 def main(args): |
| 163 parser = argparse.ArgumentParser( |
| 164 description='Enforce Cronet API requirements.') |
| 165 parser.add_argument('--api_jar', |
| 166 help='Path to API jar (i.e. cronet_api.jar)', |
| 167 required=True, |
| 168 metavar='path/to/cronet_api.jar') |
| 169 parser.add_argument('--impl_jar', |
| 170 help='Path to implementation jar ' |
| 171 '(i.e. cronet_impl_native_java.jar)', |
| 172 required=True, |
| 173 metavar='path/to/cronet_impl_native_java.jar', |
| 174 action='append') |
| 175 parser.add_argument('--stamp', help='Path to touch on success.') |
| 176 opts = parser.parse_args(args) |
| 177 |
| 178 ret = True |
| 179 ret = check_api_calls(opts) and ret |
| 180 ret = check_api_version(opts) and ret |
| 181 if ret and opts.stamp: |
| 182 build_utils.Touch(opts.stamp) |
| 183 return ret |
| 184 |
| 185 |
171 if __name__ == '__main__': | 186 if __name__ == '__main__': |
172 sys.exit(0 if main(sys.argv[1:]) != 0 else -1) | 187 sys.exit(0 if main(sys.argv[1:]) != 0 else -1) |
173 | 188 |
OLD | NEW |