blob: 72672e9d6615f34dbd73db3c48aecef966fe9a21 [file] [log] [blame]
[email protected]e4f373e2012-01-10 23:18:241# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]39375782011-09-14 16:55:092# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import os
[email protected]c7db6e92012-03-14 06:58:146import re
[email protected]39375782011-09-14 16:55:097import sys
8import subprocess
9
[email protected]c7db6e92012-03-14 06:58:1410
[email protected]e4f373e2012-01-10 23:18:2411def RunCmdAndCheck(cmd, err_string, output_api, cwd=None):
[email protected]2978339a72011-11-30 17:59:1412 results = []
[email protected]e4f373e2012-01-10 23:18:2413 p = subprocess.Popen(cmd, cwd=cwd,
[email protected]2978339a72011-11-30 17:59:1414 stdout=subprocess.PIPE,
15 stderr=subprocess.PIPE)
16 (p_stdout, p_stderr) = p.communicate()
17 if p.returncode:
18 results.append(
19 output_api.PresubmitError(err_string,
20 long_text=p_stderr))
21 return results
22
23
24def RunUnittests(input_api, output_api):
25 # Run some Generator unittests if the generator source was changed.
26 results = []
27 files = input_api.LocalPaths()
28 generator_files = []
29 for filename in files:
30 name_parts = filename.split(os.sep)
31 if name_parts[0:2] == ['ppapi', 'generators']:
32 generator_files.append(filename)
33 if generator_files != []:
[email protected]6faeb202012-12-06 15:43:0534 cmd = [ sys.executable, 'idl_tests.py']
[email protected]2978339a72011-11-30 17:59:1435 ppapi_dir = input_api.PresubmitLocalPath()
36 results.extend(RunCmdAndCheck(cmd,
[email protected]6faeb202012-12-06 15:43:0537 'PPAPI IDL unittests failed.',
[email protected]e4f373e2012-01-10 23:18:2438 output_api,
39 os.path.join(ppapi_dir, 'generators')))
[email protected]2978339a72011-11-30 17:59:1440 return results
41
42
[email protected]c7db6e92012-03-14 06:58:1443# Verify that the files do not contain a 'TODO' in them.
44RE_TODO = re.compile(r'\WTODO\W', flags=re.I)
45def CheckTODO(input_api, output_api):
46 files = input_api.LocalPaths()
47 todo = []
48
49 for filename in files:
50 name, ext = os.path.splitext(filename)
51 name_parts = name.split(os.sep)
52
53 # Only check normal build sources.
[email protected]620446f72012-12-12 22:21:0354 if ext not in ['.h', '.idl']:
[email protected]c7db6e92012-03-14 06:58:1455 continue
56
57 # Only examine the ppapi directory.
58 if name_parts[0] != 'ppapi':
59 continue
60
61 # Only examine public plugin facing directories.
62 if name_parts[1] not in ['api', 'c', 'cpp', 'utility']:
63 continue
64
65 # Only examine public stable interfaces.
66 if name_parts[2] in ['dev', 'private', 'trusted']:
67 continue
[email protected]b5e916a2013-04-08 21:17:0768 if name_parts[2] == 'extensions' and name_parts[3] == 'dev':
69 continue
[email protected]c7db6e92012-03-14 06:58:1470
71 filepath = os.path.join('..', filename)
72 if RE_TODO.search(open(filepath, 'rb').read()):
73 todo.append(filename)
74
75 if todo:
76 return [output_api.PresubmitError(
77 'TODOs found in stable public PPAPI files:',
78 long_text='\n'.join(todo))]
79 return []
80
[email protected]1594f572012-06-01 18:33:1481# Verify that no CPP wrappers use un-versioned PPB interface name macros.
82RE_UNVERSIONED_PPB = re.compile(r'\bPPB_\w+_INTERFACE\b')
83def CheckUnversionedPPB(input_api, output_api):
84 files = input_api.LocalPaths()
85 todo = []
86
87 for filename in files:
88 name, ext = os.path.splitext(filename)
89 name_parts = name.split(os.sep)
90
91 # Only check C++ sources.
92 if ext not in ['.cc']:
93 continue
94
95 # Only examine the public plugin facing ppapi/cpp directory.
96 if name_parts[0:2] != ['ppapi', 'cpp']:
97 continue
98
99 # Only examine public stable and trusted interfaces.
100 if name_parts[2] in ['dev', 'private']:
101 continue
102
103 filepath = os.path.join('..', filename)
104 if RE_UNVERSIONED_PPB.search(open(filepath, 'rb').read()):
105 todo.append(filename)
106
107 if todo:
108 return [output_api.PresubmitError(
109 'Unversioned PPB interface references found in PPAPI C++ wrappers:',
110 long_text='\n'.join(todo))]
111 return []
[email protected]c7db6e92012-03-14 06:58:14112
[email protected]39375782011-09-14 16:55:09113def CheckChange(input_api, output_api):
114 results = []
115
[email protected]2978339a72011-11-30 17:59:14116 results.extend(RunUnittests(input_api, output_api))
117
[email protected]c7db6e92012-03-14 06:58:14118 results.extend(CheckTODO(input_api, output_api))
[email protected]1594f572012-06-01 18:33:14119
120 results.extend(CheckUnversionedPPB(input_api, output_api))
121
[email protected]39375782011-09-14 16:55:09122 # Verify all modified *.idl have a matching *.h
123 files = input_api.LocalPaths()
124 h_files = []
125 idl_files = []
126
[email protected]c7db6e92012-03-14 06:58:14127 # Find all relevant .h and .idl files.
[email protected]39375782011-09-14 16:55:09128 for filename in files:
129 name, ext = os.path.splitext(filename)
130 name_parts = name.split(os.sep)
131 if name_parts[0:2] == ['ppapi', 'c'] and ext == '.h':
132 h_files.append('/'.join(name_parts[2:]))
133 if name_parts[0:2] == ['ppapi', 'api'] and ext == '.idl':
134 idl_files.append('/'.join(name_parts[2:]))
135
136 # Generate a list of all appropriate *.h and *.idl changes in this CL.
137 both = h_files + idl_files
138
139 # If there aren't any, we are done checking.
140 if not both: return results
141
142 missing = []
143 for filename in idl_files:
144 if filename not in set(h_files):
[email protected]8c311f02012-11-17 16:01:32145 missing.append('ppapi/api/%s.idl' % filename)
146
147 # An IDL change that includes [generate_thunk] doesn't need to have
148 # an update to the corresponding .h file.
149 new_thunk_files = []
150 for filename in missing:
151 lines = input_api.RightHandSideLines(lambda f: f.LocalPath() == filename)
152 for line in lines:
153 if line[2].strip() == '[generate_thunk]':
154 new_thunk_files.append(filename)
155 for filename in new_thunk_files:
156 missing.remove(filename)
[email protected]39375782011-09-14 16:55:09157
158 if missing:
159 results.append(
[email protected]c7db6e92012-03-14 06:58:14160 output_api.PresubmitPromptWarning(
161 'Missing PPAPI header, no change or skipped generation?',
[email protected]8c311f02012-11-17 16:01:32162 long_text='\n '.join(missing)))
[email protected]c7db6e92012-03-14 06:58:14163
164 missing_dev = []
165 missing_stable = []
166 missing_priv = []
167 for filename in h_files:
168 if filename not in set(idl_files):
169 name_parts = filename.split(os.sep)
170
[email protected]e12f4cc2013-02-21 03:24:34171 if name_parts[-1] == 'pp_macros':
172 # The C header generator adds a PPAPI_RELEASE macro based on all the
173 # IDL files, so pp_macros.h may change while its IDL does not.
174 lines = input_api.RightHandSideLines(
175 lambda f: f.LocalPath() == 'ppapi/c/%s.h' % filename)
176 releaseChanged = False
177 for line in lines:
178 if line[2].split()[:2] == ['#define', 'PPAPI_RELEASE']:
179 results.append(
[email protected]f7051d52013-04-02 18:31:42180 output_api.PresubmitPromptOrNotify(
[email protected]e12f4cc2013-02-21 03:24:34181 'PPAPI_RELEASE has changed', long_text=line[2]))
182 releaseChanged = True
183 break
184 if releaseChanged:
185 continue
186
[email protected]c7db6e92012-03-14 06:58:14187 if 'trusted' in name_parts:
188 missing_priv.append(' ppapi/c/%s.h' % filename)
189 continue
190
191 if 'private' in name_parts:
192 missing_priv.append(' ppapi/c/%s.h' % filename)
193 continue
194
195 if 'dev' in name_parts:
196 missing_dev.append(' ppapi/c/%s.h' % filename)
197 continue
198
199 missing_stable.append(' ppapi/c/%s.h' % filename)
200
201 if missing_priv:
202 results.append(
203 output_api.PresubmitPromptWarning(
204 'Missing PPAPI IDL for private interface, please generate IDL:',
205 long_text='\n'.join(missing_priv)))
206
207 if missing_dev:
208 results.append(
209 output_api.PresubmitPromptWarning(
210 'Missing PPAPI IDL for DEV, required before moving to stable:',
211 long_text='\n'.join(missing_dev)))
212
213 if missing_stable:
214 results.append(
215 output_api.PresubmitError(
216 'Missing PPAPI IDL for stable interface:',
217 long_text='\n'.join(missing_stable)))
[email protected]39375782011-09-14 16:55:09218
219 # Verify all *.h files match *.idl definitions, use:
220 # --test to prevent output to disk
221 # --diff to generate a unified diff
222 # --out to pick which files to examine (only the ones in the CL)
223 ppapi_dir = input_api.PresubmitLocalPath()
[email protected]c7db6e92012-03-14 06:58:14224 cmd = [sys.executable, 'generator.py',
225 '--wnone', '--diff', '--test','--cgen', '--range=start,end']
[email protected]39375782011-09-14 16:55:09226
227 # Only generate output for IDL files references (as *.h or *.idl) in this CL
228 cmd.append('--out=' + ','.join([name + '.idl' for name in both]))
[email protected]c7db6e92012-03-14 06:58:14229 cmd_results = RunCmdAndCheck(cmd,
230 'PPAPI IDL Diff detected: Run the generator.',
231 output_api,
232 os.path.join(ppapi_dir, 'generators'))
233 if cmd_results:
234 results.extend(cmd_results)
235
[email protected]39375782011-09-14 16:55:09236 return results
237
[email protected]c7db6e92012-03-14 06:58:14238
[email protected]39375782011-09-14 16:55:09239def CheckChangeOnUpload(input_api, output_api):
[email protected]39375782011-09-14 16:55:09240 return CheckChange(input_api, output_api)
241
[email protected]c7db6e92012-03-14 06:58:14242
[email protected]39375782011-09-14 16:55:09243def CheckChangeOnCommit(input_api, output_api):
[email protected]39375782011-09-14 16:55:09244 return CheckChange(input_api, output_api)