PRESUBMIT.py revision f2e7bc6b6ac3ec7761a6a164a41c8d708bc1ef33
1# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
2#
3# Use of this source code is governed by a BSD-style license
4# that can be found in the LICENSE file in the root of the source
5# tree. An additional intellectual property rights grant can be found
6# in the file PATENTS.  All contributing project authors may
7# be found in the AUTHORS file in the root of the source tree.
8
9def _LicenseHeader(input_api):
10  """Returns the license header regexp."""
11  # Accept any year number from 2011 to the current year
12  current_year = int(input_api.time.strftime('%Y'))
13  allowed_years = (str(s) for s in reversed(xrange(2011, current_year + 1)))
14  years_re = '(' + '|'.join(allowed_years) + ')'
15  license_header = (
16      r'.*? Copyright \(c\) %(year)s The WebRTC project authors\. '
17        r'All Rights Reserved\.\n'
18      r'.*?\n'
19      r'.*? Use of this source code is governed by a BSD-style license\n'
20      r'.*? that can be found in the LICENSE file in the root of the source\n'
21      r'.*? tree\. An additional intellectual property rights grant can be '
22        r'found\n'
23      r'.*? in the file PATENTS\.  All contributing project authors may\n'
24      r'.*? be found in the AUTHORS file in the root of the source tree\.\n'
25  ) % {
26      'year': years_re,
27  }
28  return license_header
29
30def _CheckNoIOStreamInHeaders(input_api, output_api):
31  """Checks to make sure no .h files include <iostream>."""
32  files = []
33  pattern = input_api.re.compile(r'^#include\s*<iostream>',
34                                 input_api.re.MULTILINE)
35  for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
36    if not f.LocalPath().endswith('.h'):
37      continue
38    contents = input_api.ReadFile(f)
39    if pattern.search(contents):
40      files.append(f)
41
42  if len(files):
43    return [ output_api.PresubmitError(
44        'Do not #include <iostream> in header files, since it inserts static ' +
45        'initialization into every file including the header. Instead, ' +
46        '#include <ostream>. See http://crbug.com/94794',
47        files) ]
48  return []
49
50def _CheckNoFRIEND_TEST(input_api, output_api):
51  """Make sure that gtest's FRIEND_TEST() macro is not used, the
52  FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be
53  used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes."""
54  problems = []
55
56  file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h'))
57  for f in input_api.AffectedFiles(file_filter=file_filter):
58    for line_num, line in f.ChangedContents():
59      if 'FRIEND_TEST(' in line:
60        problems.append('    %s:%d' % (f.LocalPath(), line_num))
61
62  if not problems:
63    return []
64  return [output_api.PresubmitPromptWarning('WebRTC\'s code should not use '
65      'gtest\'s FRIEND_TEST() macro. Include testsupport/gtest_prod_util.h and '
66      'use FRIEND_TEST_ALL_PREFIXES() instead.\n' + '\n'.join(problems))]
67
68def _CheckApprovedFilesLintClean(input_api, output_api,
69                                 source_file_filter=None):
70  """Checks that all new or whitelisted .cc and .h files pass cpplint.py.
71  This check is based on _CheckChangeLintsClean in
72  depot_tools/presubmit_canned_checks.py but has less filters and only checks
73  added files."""
74  result = []
75
76  # Initialize cpplint.
77  import cpplint
78  # Access to a protected member _XX of a client class
79  # pylint: disable=W0212
80  cpplint._cpplint_state.ResetErrorCounts()
81
82  # Justifications for each filter:
83  #
84  # - build/header_guard  : WebRTC coding style says they should be prefixed
85  #                         with WEBRTC_, which is not possible to configure in
86  #                         cpplint.py.
87  cpplint._SetFilters('-build/header_guard')
88
89  # Use the strictest verbosity level for cpplint.py (level 1) which is the
90  # default when running cpplint.py from command line.
91  # To make it possible to work with not-yet-converted code, we're only applying
92  # it to new (or moved/renamed) files and files listed in LINT_FOLDERS.
93  verbosity_level = 1
94  files = []
95  for f in input_api.AffectedSourceFiles(source_file_filter):
96    # Note that moved/renamed files also count as added for svn.
97    if (f.Action() == 'A'):
98      files.append(f.AbsoluteLocalPath())
99
100  for file_name in files:
101    cpplint.ProcessFile(file_name, verbosity_level)
102
103  if cpplint._cpplint_state.error_count > 0:
104    if input_api.is_committing:
105      # TODO(kjellander): Change back to PresubmitError below when we're
106      # confident with the lint settings.
107      res_type = output_api.PresubmitPromptWarning
108    else:
109      res_type = output_api.PresubmitPromptWarning
110    result = [res_type('Changelist failed cpplint.py check.')]
111
112  return result
113
114def _CommonChecks(input_api, output_api):
115  """Checks common to both upload and commit."""
116  # TODO(kjellander): Use presubmit_canned_checks.PanProjectChecks too.
117  results = []
118  results.extend(input_api.canned_checks.RunPylint(input_api, output_api,
119      black_list=(r'^.*gviz_api\.py$',
120                  r'^.*gaeunit\.py$',
121                  r'^third_party/.*\.py$',
122                  r'^testing/.*\.py$',
123                  r'^tools/gyp/.*\.py$',
124                  r'^tools/perf_expectations/.*\.py$',
125                  r'^tools/python/.*\.py$',
126                  r'^tools/python_charts/data/.*\.py$',
127                  r'^tools/refactoring.*\.py$',
128                  # TODO(phoglund): should arguably be checked.
129                  r'^tools/valgrind-webrtc/.*\.py$',
130                  r'^tools/valgrind/.*\.py$',
131                  # TODO(phoglund): should arguably be checked.
132                  r'^webrtc/build/.*\.py$',
133                  r'^build/.*\.py$',
134                  r'^out/.*\.py$',),
135      disabled_warnings=['F0401',  # Failed to import x
136                         'E0611',  # No package y in x
137                         'W0232',  # Class has no __init__ method
138                        ]))
139  results.extend(input_api.canned_checks.CheckLongLines(
140      input_api, output_api, maxlen=80))
141  results.extend(input_api.canned_checks.CheckChangeHasNoTabs(
142      input_api, output_api))
143  results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
144      input_api, output_api))
145  results.extend(input_api.canned_checks.CheckChangeTodoHasOwner(
146      input_api, output_api))
147  results.extend(_CheckApprovedFilesLintClean(input_api, output_api))
148  results.extend(input_api.canned_checks.CheckLicense(
149      input_api, output_api, _LicenseHeader(input_api)))
150  results.extend(_CheckNoIOStreamInHeaders(input_api, output_api))
151  results.extend(_CheckNoFRIEND_TEST(input_api, output_api))
152  return results
153
154def CheckChangeOnUpload(input_api, output_api):
155  results = []
156  results.extend(_CommonChecks(input_api, output_api))
157  return results
158
159def CheckChangeOnCommit(input_api, output_api):
160  results = []
161  results.extend(_CommonChecks(input_api, output_api))
162  results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
163  results.extend(input_api.canned_checks.CheckChangeWasUploaded(
164      input_api, output_api))
165  results.extend(input_api.canned_checks.CheckChangeHasDescription(
166      input_api, output_api))
167  results.extend(input_api.canned_checks.CheckChangeHasBugField(
168      input_api, output_api))
169  results.extend(input_api.canned_checks.CheckChangeHasTestField(
170      input_api, output_api))
171  return results
172
173