PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/third_party/blink/PRESUBMIT.py

https://github.com/chromium/chromium
Python | 262 lines | 189 code | 25 blank | 48 comment | 25 complexity | 8513d6294276e124d4240aea8012ec1d MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  1. # Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """Top-level presubmit script for Blink.
  5. See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
  6. for more details about the presubmit API built into gcl.
  7. """
  8. import imp
  9. import inspect
  10. import os
  11. import re
  12. USE_PYTHON3 = True
  13. try:
  14. # pylint: disable=C0103
  15. audit_non_blink_usage = imp.load_source(
  16. 'audit_non_blink_usage',
  17. os.path.join(os.path.dirname(inspect.stack()[0][1]),
  18. 'tools/blinkpy/presubmit/audit_non_blink_usage.py'))
  19. except IOError:
  20. # One of the presubmit upload tests tries to exec this script, which
  21. # doesn't interact so well with the import hack... just ignore the
  22. # exception here and hope for the best.
  23. pass
  24. _EXCLUDED_PATHS = (
  25. # These are third-party dependencies that we don't directly control.
  26. r'^third_party[\\/]blink[\\/]tools[\\/]blinkpy[\\/]third_party[\\/]wpt[\\/]wpt[\\/].*',
  27. r'^third_party[\\/]blink[\\/]web_tests[\\/]external[\\/]wpt[\\/]resources[\\/]webidl2[\\/].*',
  28. )
  29. def _CheckForWrongMojomIncludes(input_api, output_api):
  30. # In blink the code should either use -blink.h or -shared.h mojom
  31. # headers, except in public where only -shared.h headers should be
  32. # used to avoid exporting Blink types outside Blink.
  33. def source_file_filter(path):
  34. return input_api.FilterSourceFile(
  35. path,
  36. files_to_skip=[
  37. r'.*_test\.(cc|h)$',
  38. r'third_party[\\/]blink[\\/]common[\\/]',
  39. r'third_party[\\/]blink[\\/]public[\\/]common[\\/]',
  40. r'third_party[\\/]blink[\\/]renderer[\\/]platform[\\/]loader[\\/]fetch[\\/]url_loader[\\/]',
  41. ])
  42. pattern = input_api.re.compile(r'#include\s+[<"](.+)\.mojom(.*)\.h[>"]')
  43. public_folder = input_api.os_path.normpath('third_party/blink/public/')
  44. non_blink_mojom_errors = []
  45. public_blink_mojom_errors = []
  46. # Allow including specific non-blink interfaces that are used in the
  47. # public C++ API. Adding to these allowed interfaces should meet the
  48. # following conditions:
  49. # - Its pros/cons is discussed and have consensus on
  50. # platform-architecture-dev@ and/or
  51. # - It uses POD types that will not import STL (or base string) types into
  52. # blink (such as no strings or vectors).
  53. #
  54. # So far, non-blink interfaces are allowed only for loading / loader and
  55. # media interfaces so that we don't need type conversions to get through
  56. # the boundary between Blink and non-Blink.
  57. allowed_interfaces = (
  58. 'services/network/public/mojom/cross_origin_embedder_policy',
  59. 'services/network/public/mojom/early_hints',
  60. 'services/network/public/mojom/fetch_api',
  61. 'services/network/public/mojom/load_timing_info',
  62. 'services/network/public/mojom/url_loader',
  63. 'services/network/public/mojom/url_loader_factory',
  64. 'services/network/public/mojom/url_response_head',
  65. 'third_party/blink/public/mojom/blob/serialized_blob',
  66. 'third_party/blink/public/mojom/fetch/fetch_api_request',
  67. 'third_party/blink/public/mojom/loader/resource_load_info',
  68. 'third_party/blink/public/mojom/loader/resource_load_info_notifier',
  69. 'third_party/blink/public/mojom/worker/subresource_loader_updater',
  70. 'third_party/blink/public/mojom/loader/transferrable_url_loader',
  71. 'third_party/blink/public/mojom/loader/code_cache',
  72. 'media/mojo/mojom/interface_factory', 'media/mojo/mojom/audio_decoder',
  73. 'media/mojo/mojom/audio_encoder', 'media/mojo/mojom/video_decoder',
  74. 'media/mojo/mojom/media_metrics_provider')
  75. for f in input_api.AffectedFiles(file_filter=source_file_filter):
  76. for line_num, line in f.ChangedContents():
  77. error_list = None
  78. match = pattern.match(line)
  79. if (match and match.group(1) not in allowed_interfaces):
  80. if match.group(2) not in ('-shared', '-forward'):
  81. if f.LocalPath().startswith(public_folder):
  82. error_list = public_blink_mojom_errors
  83. elif match.group(2) not in ('-blink', '-blink-forward',
  84. '-blink-test-utils'):
  85. # Neither -shared.h, -blink.h, -blink-forward.h nor
  86. # -blink-test-utils.h.
  87. error_list = non_blink_mojom_errors
  88. if error_list is not None:
  89. error_list.append(' %s:%d %s' %
  90. (f.LocalPath(), line_num, line))
  91. results = []
  92. if non_blink_mojom_errors:
  93. results.append(
  94. output_api.PresubmitError(
  95. 'Files that include non-Blink variant mojoms found. '
  96. 'You must include .mojom-blink.h, .mojom-forward.h or '
  97. '.mojom-shared.h instead:', non_blink_mojom_errors))
  98. if public_blink_mojom_errors:
  99. results.append(
  100. output_api.PresubmitError(
  101. 'Public blink headers using Blink variant mojoms found. '
  102. 'You must include .mojom-forward.h or .mojom-shared.h '
  103. 'instead:', public_blink_mojom_errors))
  104. return results
  105. def _CommonChecks(input_api, output_api):
  106. """Checks common to both upload and commit."""
  107. # We should figure out what license checks we actually want to use.
  108. license_header = r'.*'
  109. results = []
  110. results.extend(
  111. input_api.canned_checks.PanProjectChecks(
  112. input_api,
  113. output_api,
  114. excluded_paths=_EXCLUDED_PATHS,
  115. maxlen=800,
  116. license_header=license_header,
  117. global_checks=False))
  118. results.extend(_CheckForWrongMojomIncludes(input_api, output_api))
  119. return results
  120. def _FilterPaths(input_api):
  121. """Returns input files with certain paths removed."""
  122. files = []
  123. for f in input_api.AffectedFiles():
  124. file_path = f.LocalPath()
  125. # Filter out changes in web_tests/.
  126. if ('web_tests' + input_api.os_path.sep in file_path
  127. and 'TestExpectations' not in file_path):
  128. continue
  129. if '/PRESUBMIT' in file_path:
  130. continue
  131. # Skip files that were generated by bison.
  132. if re.search(
  133. 'third_party/blink/renderer/' +
  134. 'core/xml/xpath_grammar_generated\.(cc|h)$', file_path):
  135. continue
  136. files.append(input_api.os_path.join('..', '..', file_path))
  137. return files
  138. def _CheckStyle(input_api, output_api):
  139. files = _FilterPaths(input_api)
  140. # Do not call check_blink_style.py with empty affected file list if all
  141. # input_api.AffectedFiles got filtered.
  142. if not files:
  143. return []
  144. style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
  145. 'tools',
  146. 'check_blink_style.py')
  147. # When running git cl presubmit --all this presubmit may be asked to check
  148. # ~260 files, leading to a command line that is about 17,000 characters.
  149. # This goes past the Windows 8191 character cmd.exe limit and causes cryptic
  150. # failures. To avoid these we break the command up into smaller pieces.
  151. # Depending on how long the command is on Windows the error may be:
  152. # The command line is too long.
  153. # Or it may be:
  154. # OSError: Execution failed with error: [WinError 206] The filename or
  155. # extension is too long.
  156. # The latter error comes from CreateProcess hitting its 32768 character
  157. # limit.
  158. files_per_command = 70 if input_api.is_windows else 1000
  159. results = []
  160. for i in range(0, len(files), files_per_command):
  161. args = [
  162. input_api.python_executable, style_checker_path, '--diff-files'
  163. ]
  164. args += files[i:i + files_per_command]
  165. try:
  166. child = input_api.subprocess.Popen(
  167. args, stderr=input_api.subprocess.PIPE)
  168. _, stderrdata = child.communicate()
  169. if child.returncode != 0:
  170. results.append(
  171. output_api.PresubmitError('check_blink_style.py failed',
  172. [stderrdata]))
  173. except Exception as e:
  174. results.append(
  175. output_api.PresubmitNotifyResult(
  176. 'Could not run check_blink_style.py', [str(e)]))
  177. return results
  178. def _CheckForPrintfDebugging(input_api, output_api):
  179. """Generally speaking, we'd prefer not to land patches that printf
  180. debug output.
  181. """
  182. printf_re = input_api.re.compile(r'^\s*(printf\(|fprintf\(stderr,)')
  183. errors = input_api.canned_checks._FindNewViolationsOfRule(
  184. lambda _, x: not printf_re.search(x), input_api, None)
  185. errors = [' * %s' % violation for violation in errors]
  186. if errors:
  187. return [
  188. output_api.PresubmitPromptOrNotify(
  189. 'printf debugging is best debugging! That said, it might '
  190. 'be a good idea to drop the following occurences from '
  191. 'your patch before uploading:\n%s' % '\n'.join(errors))
  192. ]
  193. return []
  194. def _CheckForForbiddenChromiumCode(input_api, output_api):
  195. """Checks that Blink uses Chromium classes and namespaces only in
  196. permitted code.
  197. """
  198. # TODO(dcheng): This is pretty similar to _FindNewViolationsOfRule.
  199. # Unfortunately, that can't be used directly because it doesn't give the
  200. # callable enough information (namely the path to the file), so we
  201. # duplicate the logic here...
  202. results = []
  203. for f in input_api.AffectedFiles():
  204. path = f.LocalPath()
  205. errors = audit_non_blink_usage.check(
  206. path, [(i + 1, l) for i, l in enumerate(f.NewContents())])
  207. if errors:
  208. errors = audit_non_blink_usage.check(path, f.ChangedContents())
  209. if errors:
  210. for error in errors:
  211. msg = '%s:%d uses disallowed identifier %s' % (
  212. path, error.line, error.identifier)
  213. if error.advice:
  214. msg += ". Advice: %s" % "\n".join(error.advice)
  215. if error.warning:
  216. results.append(output_api.PresubmitPromptWarning(msg))
  217. else:
  218. results.append(output_api.PresubmitError(msg))
  219. return results
  220. def CheckChangeOnUpload(input_api, output_api):
  221. results = []
  222. results.extend(_CommonChecks(input_api, output_api))
  223. results.extend(_CheckStyle(input_api, output_api))
  224. results.extend(_CheckForPrintfDebugging(input_api, output_api))
  225. results.extend(_CheckForForbiddenChromiumCode(input_api, output_api))
  226. return results
  227. def CheckChangeOnCommit(input_api, output_api):
  228. results = []
  229. results.extend(_CommonChecks(input_api, output_api))
  230. return results