1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177

chrome / PRESUBMIT.py [blame]

# 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 no unit tests from content/ are included in unit_tests."""
  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 _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 _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))
  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