blob: 0009bcc2ec9ee093bdcd2015a325f99a5045f6aa [file] [log] [blame]
# Copyright (c) 2013 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.
"""Top-level presubmit script for Blink.
for more details about the presubmit API built into gcl.
import imp
import inspect
import os
import re
# pylint: disable=C0103
audit_non_blink_usage = imp.load_source(
os.path.join(os.path.dirname(inspect.stack()[0][1]), 'Tools/Scripts/'))
except IOError:
# One of the presubmit upload tests tries to exec this script, which doesn't interact so well
# with the import hack... just ignore the exception here and hope for the best.
# This directory is created and updated via a script.
def _CheckForWrongMojomIncludes(input_api, output_api):
# In blink the code should either use -blink.h or -shared.h mojom
# headers, except in public where only -shared.h headers should be
# used to avoid exporting Blink types outside Blink.
def source_file_filter(path):
return input_api.FilterSourceFile(path,
pattern ='#include\s+.+\.mojom(.*)\.h[>"]')
public_folder = input_api.os_path.normpath('third_party/WebKit/public/')
non_blink_mojom_errors = []
public_blink_mojom_errors = []
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:
if != '-shared':
if f.LocalPath().startswith(public_folder):
error_list = public_blink_mojom_errors
elif != '-blink':
# Neither -shared.h, nor -blink.h.
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:
'Files that include non-Blink variant mojoms found. '
'You must include .mojom-blink.h or .mojom-shared.h instead:',
if public_blink_mojom_errors:
'Public blink headers using Blink variant mojoms found. '
'You must include .mojom-shared.h instead:',
return results
def _CommonChecks(input_api, output_api):
"""Checks common to both upload and commit."""
# We should figure out what license checks we actually want to use.
license_header = r'.*'
results = []
input_api, output_api, excluded_paths=_EXCLUDED_PATHS,
maxlen=800, license_header=license_header))
results.extend(_CheckForWrongMojomIncludes(input_api, output_api))
return results
def _CheckStyle(input_api, output_api):
# Files that follow Chromium's coding style do not include capital letters.
re_chromium_style_file = re.compile(r'\b[a-z_]+\.(cc|h)$')
style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
'Tools', 'Scripts', 'check-webkit-style')
args = [input_api.python_executable, style_checker_path, '--diff-files']
files = [input_api.os_path.join('..', '..', f.LocalPath())
for f in input_api.AffectedFiles()
# Filter out files that follow Chromium's coding style.
if not]
# Do not call check-webkit-style with empty affected file list if all
# input_api.AffectedFiles got filtered.
if not files:
return []
args += files
results = []
child = input_api.subprocess.Popen(args,
_, stderrdata = child.communicate()
if child.returncode != 0:
'check-webkit-style failed', [stderrdata]))
except Exception as e:
'Could not run check-webkit-style', [str(e)]))
return results
def _CheckForPrintfDebugging(input_api, output_api):
"""Generally speaking, we'd prefer not to land patches that printf
debug output.
printf_re ='^\s*(printf\(|fprintf\(stderr,)')
errors = input_api.canned_checks._FindNewViolationsOfRule(
lambda _, x: not,
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."""
# TODO(dcheng): This is pretty similar to _FindNewViolationsOfRule. Unfortunately, that can;'t
# be used directly because it doesn't give the callable enough information (namely the path to
# the file), so we duplicate the logic here...
results = []
for f in input_api.AffectedFiles():
path = f.LocalPath()
_, ext = os.path.splitext(path)
if ext not in ('.cc', '.cpp', '.h', '.mm'):
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 line_number, disallowed_identifier in errors:
'%s:%d uses disallowed identifier %s' % (path, line_number, disallowed_identifier)))
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))
input_api, output_api,
input_api, output_api))
return results
def _ArePaintOrCompositingDirectoriesModified(change): # pylint: disable=C0103
"""Checks whether CL has changes to paint or compositing directories."""
paint_or_compositing_paths = [
os.path.join('third_party', 'WebKit', 'Source', 'platform', 'graphics'),
os.path.join('third_party', 'WebKit', 'Source', 'core', 'layout',
os.path.join('third_party', 'WebKit', 'Source', 'core', 'svg'),
os.path.join('third_party', 'WebKit', 'Source', 'core', 'paint'),
os.path.join('third_party', 'WebKit', 'LayoutTests', 'FlagExpectations',
os.path.join('third_party', 'WebKit', 'LayoutTests', 'flag-specific',
os.path.join('third_party', 'WebKit', 'LayoutTests', 'FlagExpectations',
os.path.join('third_party', 'WebKit', 'LayoutTests', 'flag-specific',
for affected_file in change.AffectedFiles():
file_path = affected_file.LocalPath()
if any(x in file_path for x in paint_or_compositing_paths):
return True
return False
def _AreLayoutNGDirectoriesModified(change): # pylint: disable=C0103
"""Checks whether CL has changes to a layout ng directory."""
layout_ng_paths = [
os.path.join('third_party', 'WebKit', 'Source', 'core', 'layout',
for affected_file in change.AffectedFiles():
file_path = affected_file.LocalPath()
if any(x in file_path for x in layout_ng_paths):
return True
return False
def PostUploadHook(cl, change, output_api): # pylint: disable=C0103
"""git cl upload will call this hook after the issue is created/modified.
This hook adds extra try bots to the CL description in order to run slimming
paint v2 tests or LayoutNG tests in addition to the CQ try bots if the
change contains changes in a relevant direcotry (see:
_ArePaintOrCompositingDirectoriesModified and
_AreLayoutNGDirectoriesModified). For more information about
slimming-paint-v2 tests see and for information
about the LayoutNG tests see
results = []
if _ArePaintOrCompositingDirectoriesModified(change):
'Automatically added slimming-paint-v2 tests to run on CQ due to '
'changes in paint or compositing directories.'))
if _AreLayoutNGDirectoriesModified(change):
'Automatically added linux_layout_tests_layout_ng to run on CQ due '
'to changes in LayoutNG directories.'))
return results