Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(689)

Side by Side Diff: components/cronet/tools/api_static_checks.py

Issue 2544043002: [Cronet] Enforce Cronet API never modified, only grown (Closed)
Patch Set: add more tests Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
17 REPOSITORY_ROOT = os.path.abspath(os.path.join( 15 REPOSITORY_ROOT = os.path.abspath(os.path.join(
18 os.path.dirname(__file__), '..', '..', '..')) 16 os.path.dirname(__file__), '..', '..', '..'))
19 17
20 sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util')) 18 sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util'))
21 import build_utils 19 import build_utils
22 20
21 sys.path.append(os.path.join(REPOSITORY_ROOT, 'components/cronet'))
22 from tools import update_api
23
24
23 # These regular expressions catch the beginning of lines that declare classes 25 # These regular expressions catch the beginning of lines that declare classes
24 # and methods. The first group returned by a match is the class or method name. 26 # and methods. The first group returned by a match is the class or method name.
25 CLASS_RE = re.compile(r'.*class ([^ ]*) .*\{') 27 from tools.update_api import CLASS_RE
26 METHOD_RE = re.compile(r'.* ([^ ]*)\(.*\);') 28 METHOD_RE = re.compile(r'.* ([^ ]*)\(.*\);')
27 29
28 # Allowed exceptions. Adding anything to this list is dangerous and should be 30 # 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 31 # avoided if possible. For now these exceptions are for APIs that existed in
30 # the first version of Cronet and will be supported forever. 32 # the first version of Cronet and will be supported forever.
31 # TODO(pauljensen): Remove these. 33 # TODO(pauljensen): Remove these.
32 ALLOWED_EXCEPTIONS = [ 34 ALLOWED_EXCEPTIONS = [
33 'org.chromium.net.impl.CronetEngineBuilderImpl/build ->' 35 'org.chromium.net.impl.CronetEngineBuilderImpl/build ->'
34 ' org/chromium/net/ExperimentalCronetEngine/getVersionString:' 36 ' org/chromium/net/ExperimentalCronetEngine/getVersionString:'
35 '()Ljava/lang/String;', 37 '()Ljava/lang/String;',
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 # Ignore VersionSafe calls 96 # Ignore VersionSafe calls
95 if 'VersionSafeCallbacks' in caller_class: 97 if 'VersionSafeCallbacks' in caller_class:
96 continue 98 continue
97 bad_call = '%s/%s -> %s/%s' % (caller_class, caller_method, 99 bad_call = '%s/%s -> %s/%s' % (caller_class, caller_method,
98 callee_class, callee_method) 100 callee_class, callee_method)
99 if bad_call in ALLOWED_EXCEPTIONS: 101 if bad_call in ALLOWED_EXCEPTIONS:
100 continue 102 continue
101 bad_calls += [bad_call] 103 bad_calls += [bad_call]
102 104
103 105
104 def main(args): 106 def check_api_calls(opts):
105 # Returns True if no calls through API classes in implementation. 107 # Returns True if no calls through API classes in implementation.
106 108
107 parser = argparse.ArgumentParser(
108 description='Check modules do not contain ARM Neon instructions.')
109 parser.add_argument('--api_jar',
110 help='Path to API jar (i.e. cronet_api.jar)',
111 required=True,
112 metavar='path/to/cronet_api.jar')
113 parser.add_argument('--impl_jar',
114 help='Path to implementation jar '
115 '(i.e. cronet_impl_native_java.jar)',
116 required=True,
117 metavar='path/to/cronet_impl_native_java.jar',
118 action='append')
119 parser.add_argument('--stamp', help='Path to touch on success.')
120 opts = parser.parse_args(args)
121
122 temp_dir = tempfile.mkdtemp() 109 temp_dir = tempfile.mkdtemp()
123 110
124 # Extract API class files from jar 111 # Extract API class files from jar
125 jar_cmd = ['jar', 'xf', os.path.abspath(opts.api_jar)] 112 jar_cmd = ['jar', 'xf', os.path.abspath(opts.api_jar)]
126 build_utils.CheckOutput(jar_cmd, cwd=temp_dir) 113 build_utils.CheckOutput(jar_cmd, cwd=temp_dir)
127 shutil.rmtree(os.path.join(temp_dir, 'META-INF')) 114 shutil.rmtree(os.path.join(temp_dir, 'META-INF'))
128 115
129 # Collect names of API classes 116 # Collect names of API classes
130 api_classes = [] 117 api_classes = []
131 for dirpath, _, filenames in os.walk(temp_dir): 118 for dirpath, _, filenames in os.walk(temp_dir):
132 if not filenames: 119 if not filenames:
133 continue 120 continue
134 package = dirpath[len(temp_dir + '/'):] 121 package = dirpath[len(temp_dir + '/'):]
kapishnikov 2016/12/28 20:37:35 You probably can use package = os.path.relpath(di
pauljensen 2017/01/03 15:01:48 Done.
135 if package: 122 if package:
136 package += '/' 123 package += '/'
137 for filename in filenames: 124 for filename in filenames:
138 if filename.endswith('.class'): 125 if filename.endswith('.class'):
139 classname = filename[:-len('.class')] 126 classname = filename[:-len('.class')]
140 api_classes += [package + classname] 127 api_classes += [package + classname]
kapishnikov 2016/12/28 20:37:35 It is better to use os.path.join(package, classnam
pauljensen 2017/01/03 15:01:48 Done, I had to wrap it in os.path.normpath() becau
141 128
142 shutil.rmtree(temp_dir) 129 shutil.rmtree(temp_dir)
143 temp_dir = tempfile.mkdtemp() 130 temp_dir = tempfile.mkdtemp()
144 131
145 # Extract impl class files from jars 132 # Extract impl class files from jars
146 for impl_jar in opts.impl_jar: 133 for impl_jar in opts.impl_jar:
147 jar_cmd = ['jar', 'xf', os.path.abspath(impl_jar)] 134 jar_cmd = ['jar', 'xf', os.path.abspath(impl_jar)]
148 build_utils.CheckOutput(jar_cmd, cwd=temp_dir) 135 build_utils.CheckOutput(jar_cmd, cwd=temp_dir)
149 shutil.rmtree(os.path.join(temp_dir, 'META-INF')) 136 shutil.rmtree(os.path.join(temp_dir, 'META-INF'))
150 137
(...skipping 15 matching lines...) Expand all
166 find_api_calls(dump, api_classes, bad_api_calls) 153 find_api_calls(dump, api_classes, bad_api_calls)
167 154
168 shutil.rmtree(temp_dir) 155 shutil.rmtree(temp_dir)
169 156
170 if bad_api_calls: 157 if bad_api_calls:
171 print 'ERROR: Found the following calls from implementation classes through' 158 print 'ERROR: Found the following calls from implementation classes through'
172 print ' API classes. These could fail if older API is used that' 159 print ' API classes. These could fail if older API is used that'
173 print ' does not contain newer methods. Please call through a' 160 print ' does not contain newer methods. Please call through a'
174 print ' wrapper class from VersionSafeCallbacks.' 161 print ' wrapper class from VersionSafeCallbacks.'
175 print '\n'.join(bad_api_calls) 162 print '\n'.join(bad_api_calls)
176
177 if not bad_api_calls and opts.stamp:
178 build_utils.Touch(opts.stamp)
179 return not bad_api_calls 163 return not bad_api_calls
180 164
181 165
166 def check_api_version(opts):
167 if update_api.check_up_to_date(opts.api_jar):
168 return True
169 print 'ERROR: API file out of date. Please run this command:'
170 print ' components/cronet/tools/update_api.py --api_jar %s' % (
171 os.path.abspath(opts.api_jar))
172 return False
173
174
175 def main(args):
176 parser = argparse.ArgumentParser(
177 description='Enforce Cronet API requirements.')
178 parser.add_argument('--api_jar',
179 help='Path to API jar (i.e. cronet_api.jar)',
180 required=True,
181 metavar='path/to/cronet_api.jar')
182 parser.add_argument('--impl_jar',
183 help='Path to implementation jar '
184 '(i.e. cronet_impl_native_java.jar)',
185 required=True,
186 metavar='path/to/cronet_impl_native_java.jar',
187 action='append')
188 parser.add_argument('--stamp', help='Path to touch on success.')
189 opts = parser.parse_args(args)
190
191 ret = True
192 ret = check_api_calls(opts) and ret
193 ret = check_api_version(opts) and ret
194 if ret and opts.stamp:
195 build_utils.Touch(opts.stamp)
196 return ret
197
198
182 if __name__ == '__main__': 199 if __name__ == '__main__':
183 sys.exit(0 if main(sys.argv[1:]) else -1) 200 sys.exit(0 if main(sys.argv[1:]) else -1)
OLDNEW
« no previous file with comments | « components/cronet/android/api_version.txt ('k') | components/cronet/tools/api_static_checks_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698