"""Top-level presubmit script for Blink.
See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into gcl.
"""
import importlib
import inspect
import os
import re
try:
module_name = 'audit_non_blink_usage'
module_path = os.path.join(
os.path.dirname(inspect.stack()[0][1]),
'tools/blinkpy/presubmit/audit_non_blink_usage.py')
audit_non_blink_usage = importlib.machinery.SourceFileLoader(
module_name, module_path).load_module()
except IOError:
pass
_EXCLUDED_PATHS = (
r'^third_party[\\/]blink[\\/]tools[\\/]blinkpy[\\/]third_party[\\/]wpt[\\/]wpt[\\/].*',
r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]resources[\\/]webidl2[\\/].*',
)
def _CheckForWrongMojomIncludes(input_api, output_api):
def source_file_filter(path):
return input_api.FilterSourceFile(
path,
files_to_skip=[
r'.*_test.*\.(cc|h)$',
r'.*_unittest.*\.(cc|h)$',
r'third_party[\\/]blink[\\/]common[\\/]',
r'third_party[\\/]blink[\\/]public[\\/]common[\\/]',
r'third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]loader[\\/]fetch[\\/]url_loader[\\/]',
r'third_party[\\/]blink[\\/]renderer[\\/]core[\\/]frame[\\/]web_view_impl.*\.(cc|h)$',
r'third_party[\\/]blink[\\/]renderer[\\/]core[\\/]frame[\\/]web.*frame.*\.(cc|h)$',
])
pattern = input_api.re.compile(r'#include\s+[<"](.+)\.mojom(.*)\.h[>"]')
public_folder = input_api.os_path.normpath('third_party/blink/public/')
non_blink_mojom_errors = []
public_blink_mojom_errors = []
allowed_interfaces = (
'services/network/public/mojom/cross_origin_embedder_policy',
'services/network/public/mojom/document_isolation_policy',
'services/network/public/mojom/early_hints',
'services/network/public/mojom/fetch_api',
'services/network/public/mojom/load_timing_info',
'services/network/public/mojom/url_loader',
'services/network/public/mojom/url_loader_factory',
'services/network/public/mojom/url_response_head',
'third_party/blink/public/mojom/blob/blob',
'third_party/blink/public/mojom/blob/serialized_blob',
'third_party/blink/public/mojom/browser_interface_broker',
'third_party/blink/public/mojom/fetch/fetch_api_request',
'third_party/blink/public/mojom/loader/code_cache',
'third_party/blink/public/mojom/loader/fetch_later',
'third_party/blink/public/mojom/loader/local_resource_loader_config',
'third_party/blink/public/mojom/loader/resource_load_info',
'third_party/blink/public/mojom/loader/resource_load_info_notifier',
'third_party/blink/public/mojom/loader/transferrable_url_loader',
'third_party/blink/public/mojom/navigation/renderer_content_settings',
'third_party/blink/public/mojom/page/prerender_page_param',
'third_party/blink/public/mojom/worker/subresource_loader_updater',
'third_party/blink/public/mojom/worker/worklet_global_scope_creation_params',
'media/mojo/mojom/interface_factory', 'media/mojo/mojom/audio_decoder',
'media/mojo/mojom/audio_encoder', 'media/mojo/mojom/video_decoder',
'media/mojo/mojom/media_metrics_provider')
for f in input_api.AffectedFiles(file_filter=source_file_filter):
for line_num, line in f.ChangedContents():
error_list = None
match = pattern.match(line)
if (match and match.group(1) not in allowed_interfaces):
if match.group(2) not in ('-shared', '-forward'):
if f.LocalPath().startswith(public_folder):
error_list = public_blink_mojom_errors
elif match.group(2) not in ('-blink', '-blink-forward',
'-blink-test-utils'):
error_list = non_blink_mojom_errors
if error_list is not None:
error_list.append(' %s:%d %s' %
(f.LocalPath(), line_num, line))
results = []
if non_blink_mojom_errors:
results.append(
output_api.PresubmitError(
'Files that include non-Blink variant mojoms found. '
'You must include .mojom-blink.h, .mojom-forward.h or '
'.mojom-shared.h instead:', non_blink_mojom_errors))
if public_blink_mojom_errors:
results.append(
output_api.PresubmitError(
'Public blink headers using Blink variant mojoms found. '
'You must include .mojom-forward.h or .mojom-shared.h '
'instead:', public_blink_mojom_errors))
return results
def _CommonChecks(input_api, output_api):
"""Checks common to both upload and commit."""
license_header = r'.*'
results = []
results.extend(
input_api.canned_checks.PanProjectChecks(
input_api,
output_api,
excluded_paths=_EXCLUDED_PATHS,
owners_check=False,
maxlen=800,
license_header=license_header,
global_checks=False))
results.extend(_CheckForWrongMojomIncludes(input_api, output_api))
return results
def FilterPaths(input_api):
"""Returns input files with certain paths removed."""
files = []
for f in input_api.AffectedFiles():
file_path = f.AbsoluteLocalPath()
if 'web_tests' + input_api.os_path.sep in file_path:
continue
if input_api.os_path.sep + 'PRESUBMIT' in file_path:
continue
if re.search(
'third_party.blink.renderer.'
'core.xml.xpath_grammar_generated\.(cc|h)$', file_path):
continue
files.append(file_path)
return files
def _CheckStyle(input_api, output_api):
files = FilterPaths(input_api)
if not files:
return []
style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
'tools',
'check_blink_style.py')
files_per_command = 40 if input_api.is_windows else 1000
results = []
for i in range(0, len(files), files_per_command):
args = [
input_api.python3_executable, style_checker_path, '--diff-files'
]
args += files[i:i + files_per_command]
try:
child = input_api.subprocess.Popen(
args, stderr=input_api.subprocess.PIPE)
_, stderrdata = child.communicate()
if child.returncode != 0:
results.append(
output_api.PresubmitError('check_blink_style.py failed',
[stderrdata.decode('utf-8')]))
except Exception as e:
results.append(
output_api.PresubmitNotifyResult(
'Could not run check_blink_style.py', [str(e)]))
affected_python_files = [
input_api.os_path.relpath(file_path, input_api.PresubmitLocalPath())
for file_path in files if input_api.fnmatch.fnmatch(file_path, '*.py')
]
if affected_python_files:
pylintrc = input_api.os_path.join('tools', 'blinkpy', 'pylintrc')
results.extend(
input_api.RunTests(
input_api.canned_checks.GetPylint(
input_api,
output_api,
files_to_check=[
re.escape(path) for path in affected_python_files
],
pylintrc=pylintrc)))
return results
def _CheckForPrintfDebugging(input_api, output_api):
"""Generally speaking, we'd prefer not to land patches that printf
debug output.
"""
printf_re = input_api.re.compile(r'^\s*(printf\(|fprintf\(stderr,)')
errors = input_api.canned_checks._FindNewViolationsOfRule(
lambda _, x: not printf_re.search(x), input_api, None)
errors = [' * %s' % violation for violation in errors]
if errors:
return [
output_api.PresubmitPromptOrNotify(
'printf debugging is best debugging! That said, it might '
'be a good idea to drop the following occurences from '
'your patch before uploading:\n%s' % '\n'.join(errors))
]
return []
def _CheckForForbiddenChromiumCode(input_api, output_api):
"""Checks that Blink uses Chromium classes and namespaces only in
permitted code.
"""
results = []
for f in input_api.AffectedFiles():
path = f.LocalPath()
errors = audit_non_blink_usage.check(
path, [(i + 1, l) for i, l in enumerate(f.NewContents())])
if errors:
errors = audit_non_blink_usage.check(path, f.ChangedContents())
if errors:
for error in errors:
if not results:
results.append(
output_api.PresubmitNotifyResult(
'Non-Blink usage violations detected. Please '
'check if there are usable Blink equivalents; '
'if none exist, please allowlist the new uses '
'in third_party/blink/tools/blinkpy/presubmit/'
'audit_non_blink_usage.py'))
msg = '%s:%d uses disallowed identifier %s' % (
path, error.line, error.identifier)
if error.advice:
msg += ". Advice: %s" % "\n".join(error.advice)
if error.warning:
results.append(output_api.PresubmitPromptWarning(msg))
else:
results.append(output_api.PresubmitError(msg))
return results
def CheckChangeOnUpload(input_api, output_api):
results = []
results.extend(_CommonChecks(input_api, output_api))
results.extend(_CheckStyle(input_api, output_api))
results.extend(_CheckForPrintfDebugging(input_api, output_api))
results.extend(_CheckForForbiddenChromiumCode(input_api, output_api))
return results
def CheckChangeOnCommit(input_api, output_api):
results = []
results.extend(_CommonChecks(input_api, output_api))
return results