| # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import re |
| import sys |
| import subprocess |
| |
| |
| def RunCmdAndCheck(cmd, err_string, output_api, cwd=None): |
| results = [] |
| p = subprocess.Popen(cmd, cwd=cwd, |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE) |
| (p_stdout, p_stderr) = p.communicate() |
| if p.returncode: |
| results.append( |
| output_api.PresubmitError(err_string, |
| long_text=p_stderr)) |
| return results |
| |
| |
| def RunUnittests(input_api, output_api): |
| # Run some Generator unittests if the generator source was changed. |
| results = [] |
| files = input_api.LocalPaths() |
| generator_files = [] |
| for filename in files: |
| name_parts = filename.split(os.sep) |
| if name_parts[0:2] == ['ppapi', 'generators']: |
| generator_files.append(filename) |
| if generator_files != []: |
| cmd = [ sys.executable, 'idl_gen_pnacl.py', '--wnone', '--test'] |
| ppapi_dir = input_api.PresubmitLocalPath() |
| results.extend(RunCmdAndCheck(cmd, |
| 'PPAPI IDL Pnacl unittest failed.', |
| output_api, |
| os.path.join(ppapi_dir, 'generators'))) |
| return results |
| |
| |
| # If any .srpc files were changed, run run_srpcgen.py --diff_mode. |
| def CheckSrpcChange(input_api, output_api): |
| if [True for filename in input_api.LocalPaths() if |
| os.path.splitext(filename)[1] == '.srpc']: |
| return RunCmdAndCheck([sys.executable, |
| os.path.join(input_api.PresubmitLocalPath(), |
| 'native_client', 'src', |
| 'shared', 'ppapi_proxy', |
| 'run_srpcgen.py'), |
| '--diff_mode'], |
| 'PPAPI SRPC Diff detected: Run run_srpcgen.py.', |
| output_api) |
| return [] |
| |
| |
| # Verify that the files do not contain a 'TODO' in them. |
| RE_TODO = re.compile(r'\WTODO\W', flags=re.I) |
| def CheckTODO(input_api, output_api): |
| files = input_api.LocalPaths() |
| todo = [] |
| |
| for filename in files: |
| name, ext = os.path.splitext(filename) |
| name_parts = name.split(os.sep) |
| |
| # Only check normal build sources. |
| if ext not in ['.h', '.cc', '.idl']: |
| continue |
| |
| # Only examine the ppapi directory. |
| if name_parts[0] != 'ppapi': |
| continue |
| |
| # Only examine public plugin facing directories. |
| if name_parts[1] not in ['api', 'c', 'cpp', 'utility']: |
| continue |
| |
| # Only examine public stable interfaces. |
| if name_parts[2] in ['dev', 'private', 'trusted']: |
| continue |
| |
| filepath = os.path.join('..', filename) |
| if RE_TODO.search(open(filepath, 'rb').read()): |
| todo.append(filename) |
| |
| if todo: |
| return [output_api.PresubmitError( |
| 'TODOs found in stable public PPAPI files:', |
| long_text='\n'.join(todo))] |
| return [] |
| |
| # Verify that no CPP wrappers use un-versioned PPB interface name macros. |
| RE_UNVERSIONED_PPB = re.compile(r'\bPPB_\w+_INTERFACE\b') |
| def CheckUnversionedPPB(input_api, output_api): |
| files = input_api.LocalPaths() |
| todo = [] |
| |
| for filename in files: |
| name, ext = os.path.splitext(filename) |
| name_parts = name.split(os.sep) |
| |
| # Only check C++ sources. |
| if ext not in ['.cc']: |
| continue |
| |
| # Only examine the public plugin facing ppapi/cpp directory. |
| if name_parts[0:2] != ['ppapi', 'cpp']: |
| continue |
| |
| # Only examine public stable and trusted interfaces. |
| if name_parts[2] in ['dev', 'private']: |
| continue |
| |
| filepath = os.path.join('..', filename) |
| if RE_UNVERSIONED_PPB.search(open(filepath, 'rb').read()): |
| todo.append(filename) |
| |
| if todo: |
| return [output_api.PresubmitError( |
| 'Unversioned PPB interface references found in PPAPI C++ wrappers:', |
| long_text='\n'.join(todo))] |
| return [] |
| |
| def CheckChange(input_api, output_api): |
| results = [] |
| |
| results.extend(CheckSrpcChange(input_api, output_api)) |
| |
| results.extend(RunUnittests(input_api, output_api)) |
| |
| results.extend(CheckTODO(input_api, output_api)) |
| |
| results.extend(CheckUnversionedPPB(input_api, output_api)) |
| |
| # Verify all modified *.idl have a matching *.h |
| files = input_api.LocalPaths() |
| h_files = [] |
| idl_files = [] |
| |
| # Find all relevant .h and .idl files. |
| for filename in files: |
| name, ext = os.path.splitext(filename) |
| name_parts = name.split(os.sep) |
| if name_parts[0:2] == ['ppapi', 'c'] and ext == '.h': |
| h_files.append('/'.join(name_parts[2:])) |
| if name_parts[0:2] == ['ppapi', 'api'] and ext == '.idl': |
| idl_files.append('/'.join(name_parts[2:])) |
| |
| # Generate a list of all appropriate *.h and *.idl changes in this CL. |
| both = h_files + idl_files |
| |
| # If there aren't any, we are done checking. |
| if not both: return results |
| |
| missing = [] |
| for filename in idl_files: |
| if filename not in set(h_files): |
| missing.append(' ppapi/c/%s.idl' % filename) |
| |
| if missing: |
| results.append( |
| output_api.PresubmitPromptWarning( |
| 'Missing PPAPI header, no change or skipped generation?', |
| long_text='\n'.join(missing))) |
| |
| missing_dev = [] |
| missing_stable = [] |
| missing_priv = [] |
| for filename in h_files: |
| if filename not in set(idl_files): |
| name_parts = filename.split(os.sep) |
| |
| if 'trusted' in name_parts: |
| missing_priv.append(' ppapi/c/%s.h' % filename) |
| continue |
| |
| if 'private' in name_parts: |
| missing_priv.append(' ppapi/c/%s.h' % filename) |
| continue |
| |
| if 'dev' in name_parts: |
| missing_dev.append(' ppapi/c/%s.h' % filename) |
| continue |
| |
| missing_stable.append(' ppapi/c/%s.h' % filename) |
| |
| if missing_priv: |
| results.append( |
| output_api.PresubmitPromptWarning( |
| 'Missing PPAPI IDL for private interface, please generate IDL:', |
| long_text='\n'.join(missing_priv))) |
| |
| if missing_dev: |
| results.append( |
| output_api.PresubmitPromptWarning( |
| 'Missing PPAPI IDL for DEV, required before moving to stable:', |
| long_text='\n'.join(missing_dev))) |
| |
| if missing_stable: |
| results.append( |
| output_api.PresubmitError( |
| 'Missing PPAPI IDL for stable interface:', |
| long_text='\n'.join(missing_stable))) |
| |
| # Verify all *.h files match *.idl definitions, use: |
| # --test to prevent output to disk |
| # --diff to generate a unified diff |
| # --out to pick which files to examine (only the ones in the CL) |
| ppapi_dir = input_api.PresubmitLocalPath() |
| cmd = [sys.executable, 'generator.py', |
| '--wnone', '--diff', '--test','--cgen', '--range=start,end'] |
| |
| # Only generate output for IDL files references (as *.h or *.idl) in this CL |
| cmd.append('--out=' + ','.join([name + '.idl' for name in both])) |
| cmd_results = RunCmdAndCheck(cmd, |
| 'PPAPI IDL Diff detected: Run the generator.', |
| output_api, |
| os.path.join(ppapi_dir, 'generators')) |
| if cmd_results: |
| results.extend(cmd_results) |
| |
| return results |
| |
| |
| def CheckChangeOnUpload(input_api, output_api): |
| return CheckChange(input_api, output_api) |
| |
| |
| def CheckChangeOnCommit(input_api, output_api): |
| return CheckChange(input_api, output_api) |