blob: facd82067891804f098f9dd3a037480fb096d331 [file] [edit]
# Copyright 2011 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Presubmit script for changes affecting chrome/
See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into depot_tools.
"""
import re
INCLUDE_CPP_FILES_ONLY = (
r'.*\.(cc|h)$',
)
INCLUDE_SOURCE_FILES_ONLY = (
r'.*\.(c|cc|cpp|h|m|mm)$',
)
EXCLUDE = (
# Objective C confuses everything.
r'.*cocoa.*',
r'.*_mac\.(cc|h)$',
r'.*_mac_.*',
# All the messages files do weird multiple include trickery
r'.*_messages.*\.h$',
# Autogenerated window resources files are off limits
r'.*resource.h$',
# Header trickery
r'.*-inl\.h$',
# Has safe printf usage that cpplint complains about
r'safe_browsing_util\.cc$',
)
def _CheckChangeLintsClean(input_api, output_api):
"""Makes sure that the chrome/ code is cpplint clean."""
files_to_skip = input_api.DEFAULT_FILES_TO_SKIP + EXCLUDE
sources = lambda x: input_api.FilterSourceFile(
x, files_to_check=INCLUDE_CPP_FILES_ONLY, files_to_skip=files_to_skip)
return input_api.canned_checks.CheckChangeLintsClean(
input_api, output_api, sources)
def _CheckNoContentUnitTestsInChrome(input_api, output_api):
"""Makes sure that unit_tests does not include unit tests from content/."""
problems = []
for f in input_api.AffectedFiles():
if not f.LocalPath().endswith('BUILD.gn'):
continue
for line_num, line in f.ChangedContents():
m = re.search(r"'(.*\/content\/.*unittest.*)'", line)
if m:
problems.append(m.group(1))
if not problems:
return []
return [
output_api.PresubmitPromptWarning(
'Unit tests located in content/ should be added to the ' +
'content_unittests target.',
items=problems)
]
def _CheckNoIsAppleBuildFlagsInChromeFile(input_api, f):
"""Check for IS_APPLE in a given file in chrome/."""
preprocessor_statement = input_api.re.compile(r'^\s*#')
apple_buildflag = input_api.re.compile(r'BUILDFLAG\(IS_APPLE\)')
results = []
for lnum, line in f.ChangedContents():
if preprocessor_statement.search(line) and apple_buildflag.search(
line):
results.append(' %s:%d' % (f.LocalPath(), lnum))
return results
def _CheckNoIsAppleBuildFlagsInChrome(input_api, output_api):
"""Check for IS_APPLE which isn't used in chrome/."""
apple_buildflags = []
def SourceFilter(affected_file):
return input_api.FilterSourceFile(affected_file,
INCLUDE_SOURCE_FILES_ONLY,
input_api.DEFAULT_FILES_TO_SKIP)
for f in input_api.AffectedSourceFiles(SourceFilter):
apple_buildflags.extend(
_CheckNoIsAppleBuildFlagsInChromeFile(input_api, f))
if not apple_buildflags:
return []
return [
output_api.PresubmitError(
'IS_APPLE is not used in chrome/ but found in:\n',
apple_buildflags)
]
def _CheckNoIsFuchsiaBuildFlagsInChromeFile(input_api, f):
"""Check for IS_FUCHSIA in a given file in chrome/."""
preprocessor_statement = input_api.re.compile(r'^\s*#')
fuchsia_buildflag = input_api.re.compile(r'BUILDFLAG\(IS_FUCHSIA\)')
results = []
for lnum, line in f.ChangedContents():
if preprocessor_statement.search(line) and fuchsia_buildflag.search(
line):
results.append(' %s:%d' % (f.LocalPath(), lnum))
return results
def _CheckNoIsFuchsiaBuildFlagsInChrome(input_api, output_api):
"""Check for IS_FUCHSIA which isn't used in chrome/."""
fuchsia_buildflags = []
def SourceFilter(affected_file):
return input_api.FilterSourceFile(affected_file,
INCLUDE_SOURCE_FILES_ONLY,
input_api.DEFAULT_FILES_TO_SKIP)
for f in input_api.AffectedSourceFiles(SourceFilter):
fuchsia_buildflags.extend(
_CheckNoIsFuchsiaBuildFlagsInChromeFile(input_api, f))
if not fuchsia_buildflags:
return []
return [
output_api.PresubmitError(
'IS_FUCHSIA is not used in chrome/ but found in:\n',
fuchsia_buildflags)
]
def _CheckNoIsIOSBuildFlagsInChromeFile(input_api, f):
"""Check for IS_IOS in a given file in chrome/."""
preprocessor_statement = input_api.re.compile(r'^\s*#')
ios_buildflag = input_api.re.compile(r'BUILDFLAG\(IS_IOS\)')
results = []
for lnum, line in f.ChangedContents():
if preprocessor_statement.search(line) and ios_buildflag.search(line):
results.append(' %s:%d' % (f.LocalPath(), lnum))
return results
def _CheckNoIsIOSBuildFlagsInChrome(input_api, output_api):
"""Check for IS_IOS which isn't used in chrome/."""
ios_buildflags = []
def SourceFilter(affected_file):
return input_api.FilterSourceFile(affected_file,
INCLUDE_SOURCE_FILES_ONLY,
input_api.DEFAULT_FILES_TO_SKIP)
for f in input_api.AffectedSourceFiles(SourceFilter):
ios_buildflags.extend(_CheckNoIsIOSBuildFlagsInChromeFile(
input_api, f))
if not ios_buildflags:
return []
return [
output_api.PresubmitError(
'IS_IOS is not used in chrome/ but found in:\n', ios_buildflags)
]
def _CheckBreakingInstallerVersionBumpNeeded(input_api, output_api):
files = []
breaking_version_installer_updated = False
def _FilterFile(affected_file):
return input_api.FilterSourceFile(
affected_file,
files_to_check=input_api.DEFAULT_FILES_TO_CHECK +
(r'.*\.release', ))
for f in input_api.AffectedSourceFiles(_FilterFile):
# Normalize the local path to Linux-style path separators so that the
# path comparisons work on Windows as well.
local_path = f.LocalPath().replace('\\', '/')
breaking_version_installer_updated |= (
local_path ==
'chrome/installer/setup/last_breaking_installer_version.cc')
if (local_path == 'chrome/installer/mini_installer/chrome.release'
or local_path.startswith('chrome/test/mini_installer')):
files.append(local_path)
if files and not breaking_version_installer_updated:
return [
output_api.PresubmitPromptWarning('''
Update chrome/installer/setup/last_breaking_installer_version.cc if the changes
found in the following files might break make downgrades not possible beyond
this browser's version.''',
items=files)
]
if not files and breaking_version_installer_updated:
return [
output_api.PresubmitPromptWarning('''
No installer breaking changes detected but
chrome/installer/setup/last_breaking_installer_version.cc was updated. Please
update chrome/installer/PRESUBMIT.py if more files need to be watched for
breaking installer changes.''')
]
return []
def _CheckNoBaseRunLoopInChrome(input_api, output_api):
"""Check for base::RunLoop usage in chrome/ (production code only)."""
# These are files in //chrome that currently use base::RunLoop and are
# grandfathered in. New usages should be avoided.
allowed_files = [
'chrome/app_shim/app_shim_main_delegate.mm',
'chrome/browser/app_controller_mac.mm',
'chrome/browser/apps/app_service/app_registry_cache_waiter.h',
'chrome/browser/apps/app_service/browser_app_launcher.cc',
'chrome/browser/ash/accessibility/speech_monitor.cc',
'chrome/browser/ash/arc/session/arc_session_manager.cc',
'chrome/browser/ash/system_web_apps/system_web_app_manager.cc',
'chrome/browser/browser_process_impl.cc',
'chrome/browser/browser_switcher/ieem_sitelist_parser_fuzzer.cc',
'chrome/browser/btm/btm_browser_signin_detector_factory.h',
'chrome/browser/chrome_browser_main.cc',
'chrome/browser/chrome_browser_main.h',
'chrome/browser/enterprise/connectors/device_trust/key_management/installer/management_service/rotate_util.cc',
'chrome/browser/extensions/blocked_action_waiter.h',
'chrome/browser/extensions/load_error_waiter.h',
'chrome/browser/extensions/startup_helper.cc',
'chrome/browser/first_run/first_run.cc',
'chrome/browser/first_run/first_run_internal_linux.cc',
'chrome/browser/lifetime/browser_shutdown.cc',
'chrome/browser/notifications/stub_notification_display_service.cc',
'chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade.cc',
'chrome/browser/policy/chrome_browser_cloud_management_register_watcher.h',
'chrome/browser/policy/extension_force_install_mixin.cc',
'chrome/browser/printing/print_job.cc',
'chrome/browser/printing/print_view_manager_base.cc',
'chrome/browser/profiles/keep_alive/profile_keep_alive_waiter.h',
'chrome/browser/profiles/profile_manager.cc',
'chrome/browser/sessions/session_restore.cc',
'chrome/browser/sessions/tab_restore_service_load_waiter.h',
'chrome/browser/ssl/ssl_client_auth_requestor_mock.h',
'chrome/browser/sync_file_system/local/canned_syncable_file_system.cc',
'chrome/browser/ui/ash/login/login_display_host.h',
'chrome/browser/ui/cocoa/first_run_dialog_cocoa.mm',
'chrome/browser/ui/cocoa/share_menu_controller.mm',
'chrome/browser/ui/global_error/global_error_waiter.h',
'chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_initialized_observer.h',
'chrome/browser/ui/views/accessibility/uia_accessibility_event_waiter.cc',
'chrome/browser/ui/views/accessibility/uia_accessibility_event_waiter.h',
'chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc',
'chrome/browser/ui/views/first_run_dialog.cc',
'chrome/browser/ui/views/message_box_dialog.cc',
'chrome/browser/ui/views/process_singleton_dialog_linux.cc',
'chrome/browser/ui/views/uninstall_view.cc',
'chrome/browser/web_applications/os_integration/mac/app_shim_launch.mm',
'chrome/browser/web_applications/os_integration/mac/web_app_shortcut_copier_mac.mm',
'chrome/browser/web_applications/web_app_command_manager.cc',
'chrome/browser/web_applications/web_app_command_manager.h',
'chrome/browser/web_applications/web_app_provider.cc',
'chrome/browser/webauthn/enclave_keys_waiter.h',
'chrome/credential_provider/extension/service.cc',
'chrome/enterprise_companion/app/app.cc',
'chrome/tools/service_discovery_sniffer/service_discovery_sniffer.cc',
'chrome/updater/app/app.cc',
'chrome/updater/app/app_server.cc',
]
test_patterns = [
r'.*test.*',
r'.*fake.*',
r'.*mock.*',
r'.*fuzz.*',
]
test_re = input_api.re.compile('|'.join(test_patterns))
def SourceFilter(affected_file):
return input_api.FilterSourceFile(affected_file,
INCLUDE_SOURCE_FILES_ONLY,
input_api.DEFAULT_FILES_TO_SKIP)
run_loop_re = input_api.re.compile(r'\bbase::RunLoop\b')
problems = []
for f in input_api.AffectedSourceFiles(SourceFilter):
local_path = f.LocalPath().replace('\\', '/')
if local_path in allowed_files or test_re.match(local_path):
continue
for line_num, line in f.ChangedContents():
if run_loop_re.search(line):
problems.append(' %s:%d' % (local_path, line_num))
if not problems:
return []
return [
output_api.PresubmitError(
'base::RunLoop is disallowed in production code in //chrome. '
'Please email chrome-directory-owners@chromium.org if you '
'believe a RunLoop is necessary. It could be necessary for '
'integration with OS APIs.',
items=problems)
]
def _CommonChecks(input_api, output_api):
"""Checks common to both upload and commit."""
results = []
results.extend(_CheckNoContentUnitTestsInChrome(input_api, output_api))
results.extend(_CheckNoIsAppleBuildFlagsInChrome(input_api, output_api))
results.extend(_CheckNoIsIOSBuildFlagsInChrome(input_api, output_api))
results.extend(
_CheckBreakingInstallerVersionBumpNeeded(input_api, output_api))
results.extend(_CheckNoBaseRunLoopInChrome(input_api, output_api))
return results
def CheckChangeOnUpload(input_api, output_api):
results = []
results.extend(_CommonChecks(input_api, output_api))
results.extend(_CheckChangeLintsClean(input_api, output_api))
return results
def CheckChangeOnCommit(input_api, output_api):
results = []
results.extend(_CommonChecks(input_api, output_api))
return results