Additional fixes to new notification docs
[chromium-blink-merge.git] / ppapi / PRESUBMIT.py
blob9b6f716f050cbb4de11a681a91b2c43a53d4df68
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import os
6 import re
7 import sys
8 import subprocess
11 def RunCmdAndCheck(cmd, err_string, output_api, cwd=None):
12 results = []
13 p = subprocess.Popen(cmd, cwd=cwd,
14 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
24 def 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 != []:
34 cmd = [ sys.executable, 'idl_tests.py']
35 ppapi_dir = input_api.PresubmitLocalPath()
36 results.extend(RunCmdAndCheck(cmd,
37 'PPAPI IDL unittests failed.',
38 output_api,
39 os.path.join(ppapi_dir, 'generators')))
40 return results
43 # Verify that the files do not contain a 'TODO' in them.
44 RE_TODO = re.compile(r'\WTODO\W', flags=re.I)
45 def CheckTODO(input_api, output_api):
46 files = input_api.LocalPaths()
47 todo = []
49 for filename in files:
50 name, ext = os.path.splitext(filename)
51 name_parts = name.split(os.sep)
53 # Only check normal build sources.
54 if ext not in ['.h', '.idl']:
55 continue
57 # Only examine the ppapi directory.
58 if name_parts[0] != 'ppapi':
59 continue
61 # Only examine public plugin facing directories.
62 if name_parts[1] not in ['api', 'c', 'cpp', 'utility']:
63 continue
65 # Only examine public stable interfaces.
66 if name_parts[2] in ['dev', 'private', 'trusted']:
67 continue
69 filepath = os.path.join('..', filename)
70 if RE_TODO.search(open(filepath, 'rb').read()):
71 todo.append(filename)
73 if todo:
74 return [output_api.PresubmitError(
75 'TODOs found in stable public PPAPI files:',
76 long_text='\n'.join(todo))]
77 return []
79 # Verify that no CPP wrappers use un-versioned PPB interface name macros.
80 RE_UNVERSIONED_PPB = re.compile(r'\bPPB_\w+_INTERFACE\b')
81 def CheckUnversionedPPB(input_api, output_api):
82 files = input_api.LocalPaths()
83 todo = []
85 for filename in files:
86 name, ext = os.path.splitext(filename)
87 name_parts = name.split(os.sep)
89 # Only check C++ sources.
90 if ext not in ['.cc']:
91 continue
93 # Only examine the public plugin facing ppapi/cpp directory.
94 if name_parts[0:2] != ['ppapi', 'cpp']:
95 continue
97 # Only examine public stable and trusted interfaces.
98 if name_parts[2] in ['dev', 'private']:
99 continue
101 filepath = os.path.join('..', filename)
102 if RE_UNVERSIONED_PPB.search(open(filepath, 'rb').read()):
103 todo.append(filename)
105 if todo:
106 return [output_api.PresubmitError(
107 'Unversioned PPB interface references found in PPAPI C++ wrappers:',
108 long_text='\n'.join(todo))]
109 return []
111 def CheckChange(input_api, output_api):
112 results = []
114 results.extend(RunUnittests(input_api, output_api))
116 results.extend(CheckTODO(input_api, output_api))
118 results.extend(CheckUnversionedPPB(input_api, output_api))
120 # Verify all modified *.idl have a matching *.h
121 files = input_api.LocalPaths()
122 h_files = []
123 idl_files = []
125 # Find all relevant .h and .idl files.
126 for filename in files:
127 name, ext = os.path.splitext(filename)
128 name_parts = name.split(os.sep)
129 if name_parts[0:2] == ['ppapi', 'c'] and ext == '.h':
130 h_files.append('/'.join(name_parts[2:]))
131 if name_parts[0:2] == ['ppapi', 'api'] and ext == '.idl':
132 idl_files.append('/'.join(name_parts[2:]))
134 # Generate a list of all appropriate *.h and *.idl changes in this CL.
135 both = h_files + idl_files
137 # If there aren't any, we are done checking.
138 if not both: return results
140 missing = []
141 for filename in idl_files:
142 if filename not in set(h_files):
143 missing.append('ppapi/api/%s.idl' % filename)
145 # An IDL change that includes [generate_thunk] doesn't need to have
146 # an update to the corresponding .h file.
147 new_thunk_files = []
148 for filename in missing:
149 lines = input_api.RightHandSideLines(lambda f: f.LocalPath() == filename)
150 for line in lines:
151 if line[2].strip() == '[generate_thunk]':
152 new_thunk_files.append(filename)
153 for filename in new_thunk_files:
154 missing.remove(filename)
156 if missing:
157 results.append(
158 output_api.PresubmitPromptWarning(
159 'Missing PPAPI header, no change or skipped generation?',
160 long_text='\n '.join(missing)))
162 missing_dev = []
163 missing_stable = []
164 missing_priv = []
165 for filename in h_files:
166 if filename not in set(idl_files):
167 name_parts = filename.split(os.sep)
169 if name_parts[-1] == 'pp_macros':
170 # The C header generator adds a PPAPI_RELEASE macro based on all the
171 # IDL files, so pp_macros.h may change while its IDL does not.
172 lines = input_api.RightHandSideLines(
173 lambda f: f.LocalPath() == 'ppapi/c/%s.h' % filename)
174 releaseChanged = False
175 for line in lines:
176 if line[2].split()[:2] == ['#define', 'PPAPI_RELEASE']:
177 results.append(
178 output_api.PresubmitNotifyResult(
179 'PPAPI_RELEASE has changed', long_text=line[2]))
180 releaseChanged = True
181 break
182 if releaseChanged:
183 continue
185 if 'trusted' in name_parts:
186 missing_priv.append(' ppapi/c/%s.h' % filename)
187 continue
189 if 'private' in name_parts:
190 missing_priv.append(' ppapi/c/%s.h' % filename)
191 continue
193 if 'dev' in name_parts:
194 missing_dev.append(' ppapi/c/%s.h' % filename)
195 continue
197 missing_stable.append(' ppapi/c/%s.h' % filename)
199 if missing_priv:
200 results.append(
201 output_api.PresubmitPromptWarning(
202 'Missing PPAPI IDL for private interface, please generate IDL:',
203 long_text='\n'.join(missing_priv)))
205 if missing_dev:
206 results.append(
207 output_api.PresubmitPromptWarning(
208 'Missing PPAPI IDL for DEV, required before moving to stable:',
209 long_text='\n'.join(missing_dev)))
211 if missing_stable:
212 results.append(
213 output_api.PresubmitError(
214 'Missing PPAPI IDL for stable interface:',
215 long_text='\n'.join(missing_stable)))
217 # Verify all *.h files match *.idl definitions, use:
218 # --test to prevent output to disk
219 # --diff to generate a unified diff
220 # --out to pick which files to examine (only the ones in the CL)
221 ppapi_dir = input_api.PresubmitLocalPath()
222 cmd = [sys.executable, 'generator.py',
223 '--wnone', '--diff', '--test','--cgen', '--range=start,end']
225 # Only generate output for IDL files references (as *.h or *.idl) in this CL
226 cmd.append('--out=' + ','.join([name + '.idl' for name in both]))
227 cmd_results = RunCmdAndCheck(cmd,
228 'PPAPI IDL Diff detected: Run the generator.',
229 output_api,
230 os.path.join(ppapi_dir, 'generators'))
231 if cmd_results:
232 results.extend(cmd_results)
234 return results
237 def CheckChangeOnUpload(input_api, output_api):
238 return CheckChange(input_api, output_api)
241 def CheckChangeOnCommit(input_api, output_api):
242 return CheckChange(input_api, output_api)