PageRenderTime 24ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/WebKit/PRESUBMIT.py

https://gitlab.com/0072016/Facebook-SDK-
Python | 291 lines | 247 code | 30 blank | 14 comment | 23 complexity | 17e0eba3bb4b86fd02b8649a1a8b37ce MD5 | raw file
  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 http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
  6. for more details about the presubmit API built into gcl.
  7. """
  8. import re
  9. import sys
  10. _EXCLUDED_PATHS = ()
  11. def _CheckForVersionControlConflictsInFile(input_api, f):
  12. pattern = input_api.re.compile('^(?:<<<<<<<|>>>>>>>) |^=======$')
  13. errors = []
  14. for line_num, line in f.ChangedContents():
  15. if pattern.match(line):
  16. errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
  17. return errors
  18. def _CheckForVersionControlConflicts(input_api, output_api):
  19. """Usually this is not intentional and will cause a compile failure."""
  20. errors = []
  21. for f in input_api.AffectedFiles():
  22. errors.extend(_CheckForVersionControlConflictsInFile(input_api, f))
  23. results = []
  24. if errors:
  25. results.append(output_api.PresubmitError(
  26. 'Version control conflict markers found, please resolve.', errors))
  27. return results
  28. def _CheckWatchlist(input_api, output_api):
  29. """Check that the WATCHLIST file parses correctly."""
  30. errors = []
  31. for f in input_api.AffectedFiles():
  32. if f.LocalPath() != 'WATCHLISTS':
  33. continue
  34. import StringIO
  35. import logging
  36. import watchlists
  37. log_buffer = StringIO.StringIO()
  38. log_handler = logging.StreamHandler(log_buffer)
  39. log_handler.setFormatter(
  40. logging.Formatter('%(levelname)s: %(message)s'))
  41. logger = logging.getLogger()
  42. logger.addHandler(log_handler)
  43. wl = watchlists.Watchlists(input_api.change.RepositoryRoot())
  44. logger.removeHandler(log_handler)
  45. log_handler.flush()
  46. log_buffer.flush()
  47. if log_buffer.getvalue():
  48. errors.append(output_api.PresubmitError(
  49. 'Cannot parse WATCHLISTS file, please resolve.',
  50. log_buffer.getvalue().splitlines()))
  51. return errors
  52. def _CommonChecks(input_api, output_api):
  53. """Checks common to both upload and commit."""
  54. # We should figure out what license checks we actually want to use.
  55. license_header = r'.*'
  56. results = []
  57. results.extend(input_api.canned_checks.PanProjectChecks(
  58. input_api, output_api, excluded_paths=_EXCLUDED_PATHS,
  59. maxlen=800, license_header=license_header))
  60. results.extend(_CheckForVersionControlConflicts(input_api, output_api))
  61. results.extend(_CheckPatchFiles(input_api, output_api))
  62. results.extend(_CheckTestExpectations(input_api, output_api))
  63. results.extend(_CheckChromiumPlatformMacros(input_api, output_api))
  64. results.extend(_CheckWatchlist(input_api, output_api))
  65. results.extend(_CheckFilePermissions(input_api, output_api))
  66. return results
  67. def _CheckPatchFiles(input_api, output_api):
  68. problems = [f.LocalPath() for f in input_api.AffectedFiles()
  69. if f.LocalPath().endswith(('.orig', '.rej'))]
  70. if problems:
  71. return [output_api.PresubmitError(
  72. "Don't commit .rej and .orig files.", problems)]
  73. else:
  74. return []
  75. def _CheckTestExpectations(input_api, output_api):
  76. local_paths = [f.LocalPath() for f in input_api.AffectedFiles()]
  77. if any('LayoutTests' in path for path in local_paths):
  78. lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
  79. 'Tools', 'Scripts', 'lint-test-expectations')
  80. _, errs = input_api.subprocess.Popen(
  81. [input_api.python_executable, lint_path],
  82. stdout=input_api.subprocess.PIPE,
  83. stderr=input_api.subprocess.PIPE).communicate()
  84. if not errs:
  85. return [output_api.PresubmitError(
  86. "lint-test-expectations failed "
  87. "to produce output; check by hand. ")]
  88. if errs.strip() != 'Lint succeeded.':
  89. return [output_api.PresubmitError(errs)]
  90. return []
  91. def _CheckStyle(input_api, output_api):
  92. # Files that follow Chromium's coding style do not include capital letters.
  93. re_chromium_style_file = re.compile(r'\b[a-z_]+\.(cc|h)$')
  94. style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
  95. 'Tools', 'Scripts', 'check-webkit-style')
  96. args = ([input_api.python_executable, style_checker_path, '--diff-files']
  97. + [input_api.os_path.join('..', '..', f.LocalPath())
  98. for f in input_api.AffectedFiles()
  99. # Filter out files that follow Chromium's coding style.
  100. if not re_chromium_style_file.search(f.LocalPath())])
  101. results = []
  102. try:
  103. child = input_api.subprocess.Popen(args,
  104. stderr=input_api.subprocess.PIPE)
  105. _, stderrdata = child.communicate()
  106. if child.returncode != 0:
  107. results.append(output_api.PresubmitError(
  108. 'check-webkit-style failed', [stderrdata]))
  109. except Exception as e:
  110. results.append(output_api.PresubmitNotifyResult(
  111. 'Could not run check-webkit-style', [str(e)]))
  112. return results
  113. def _CheckChromiumPlatformMacros(input_api, output_api, source_file_filter=None):
  114. """Ensures that Blink code uses WTF's platform macros instead of
  115. Chromium's. Using the latter has resulted in at least one subtle
  116. build breakage."""
  117. os_macro_re = input_api.re.compile(r'^\s*#(el)?if.*\bOS_')
  118. errors = input_api.canned_checks._FindNewViolationsOfRule(
  119. lambda _, x: not os_macro_re.search(x),
  120. input_api, source_file_filter)
  121. errors = ['Found use of Chromium OS_* macro in %s. '
  122. 'Use WTF platform macros instead.' % violation for violation in errors]
  123. if errors:
  124. return [output_api.PresubmitPromptWarning('\n'.join(errors))]
  125. return []
  126. def _CheckForPrintfDebugging(input_api, output_api):
  127. """Generally speaking, we'd prefer not to land patches that printf
  128. debug output."""
  129. printf_re = input_api.re.compile(r'^\s*(printf\(|fprintf\(stderr,)')
  130. errors = input_api.canned_checks._FindNewViolationsOfRule(
  131. lambda _, x: not printf_re.search(x),
  132. input_api, None)
  133. errors = [' * %s' % violation for violation in errors]
  134. if errors:
  135. return [output_api.PresubmitPromptOrNotify(
  136. 'printf debugging is best debugging! That said, it might '
  137. 'be a good idea to drop the following occurances from '
  138. 'your patch before uploading:\n%s' % '\n'.join(errors))]
  139. return []
  140. def _CheckForFailInFile(input_api, f):
  141. pattern = input_api.re.compile('^FAIL')
  142. errors = []
  143. for line_num, line in f.ChangedContents():
  144. if pattern.match(line):
  145. errors.append(' %s:%d %s' % (f.LocalPath(), line_num, line))
  146. return errors
  147. def _CheckFilePermissions(input_api, output_api):
  148. """Check that all files have their permissions properly set."""
  149. if input_api.platform == 'win32':
  150. return []
  151. args = [input_api.python_executable,
  152. input_api.os_path.join(
  153. input_api.change.RepositoryRoot(),
  154. 'tools/checkperms/checkperms.py'),
  155. '--root', input_api.change.RepositoryRoot()]
  156. for f in input_api.AffectedFiles():
  157. args += ['--file', f.LocalPath()]
  158. try:
  159. input_api.subprocess.check_output(args)
  160. return []
  161. except input_api.subprocess.CalledProcessError as error:
  162. return [output_api.PresubmitError(
  163. 'checkperms.py failed:',
  164. long_text=error.output)]
  165. def _CheckForInvalidPreferenceError(input_api, output_api):
  166. pattern = input_api.re.compile('Invalid name for preference: (.+)')
  167. results = []
  168. for f in input_api.AffectedFiles():
  169. if not f.LocalPath().endswith('-expected.txt'):
  170. continue
  171. for line_num, line in f.ChangedContents():
  172. error = pattern.search(line)
  173. if error:
  174. results.append(output_api.PresubmitError('Found an invalid preference %s in expected result %s:%s' % (error.group(1), f, line_num)))
  175. return results
  176. def _CheckForForbiddenNamespace(input_api, output_api):
  177. """Checks that Blink uses Chromium namespaces only in permitted code."""
  178. # This list is not exhaustive, but covers likely ones.
  179. chromium_namespaces = ["base", "cc", "content", "gfx", "net", "ui"]
  180. chromium_classes = ["scoped_refptr"]
  181. def source_file_filter(path):
  182. return input_api.FilterSourceFile(path,
  183. white_list=[r'third_party/WebKit/Source/.*\.(h|cpp)$'],
  184. black_list=[r'third_party/WebKit/Source/(platform|wtf|web)/'])
  185. comment_re = input_api.re.compile(r'^\s*//')
  186. result = []
  187. for namespace in chromium_namespaces:
  188. namespace_re = input_api.re.compile(r'\b{0}::|^\s*using namespace {0};|^\s*namespace {0} \{{'.format(input_api.re.escape(namespace)))
  189. uses_namespace_outside_comments = lambda line: namespace_re.search(line) and not comment_re.search(line)
  190. errors = input_api.canned_checks._FindNewViolationsOfRule(lambda _, line: not uses_namespace_outside_comments(line),
  191. input_api, source_file_filter)
  192. if errors:
  193. result += [output_api.PresubmitError('Do not use Chromium namespace {} inside Blink core:\n{}'.format(namespace, '\n'.join(errors)))]
  194. for class_name in chromium_classes:
  195. class_re = input_api.re.compile(r'\b{0}\b'.format(input_api.re.escape(class_name)))
  196. uses_class_outside_comments = lambda line: class_re.search(line) and not comment_re.search(line)
  197. errors = input_api.canned_checks._FindNewViolationsOfRule(lambda _, line: not uses_class_outside_comments(line),
  198. input_api, source_file_filter)
  199. if errors:
  200. result += [output_api.PresubmitError('Do not use Chromium class {} inside Blink core:\n{}'.format(class_name, '\n'.join(errors)))]
  201. return result
  202. def CheckChangeOnUpload(input_api, output_api):
  203. results = []
  204. results.extend(_CommonChecks(input_api, output_api))
  205. results.extend(_CheckStyle(input_api, output_api))
  206. results.extend(_CheckForPrintfDebugging(input_api, output_api))
  207. results.extend(_CheckForInvalidPreferenceError(input_api, output_api))
  208. results.extend(_CheckForForbiddenNamespace(input_api, output_api))
  209. return results
  210. def CheckChangeOnCommit(input_api, output_api):
  211. results = []
  212. results.extend(_CommonChecks(input_api, output_api))
  213. results.extend(input_api.canned_checks.CheckTreeIsOpen(
  214. input_api, output_api,
  215. json_url='http://chromium-status.appspot.com/current?format=json'))
  216. results.extend(input_api.canned_checks.CheckChangeHasDescription(
  217. input_api, output_api))
  218. return results
  219. def GetPreferredTryMasters(project, change):
  220. import json
  221. import os.path
  222. import platform
  223. import subprocess
  224. cq_config_path = os.path.join(
  225. change.RepositoryRoot(), 'infra', 'config', 'cq.cfg')
  226. # commit_queue.py below is a script in depot_tools directory, which has a
  227. # 'builders' command to retrieve a list of CQ builders from the CQ config.
  228. is_win = platform.system() == 'Windows'
  229. masters = json.loads(subprocess.check_output(
  230. ['commit_queue', 'builders', cq_config_path], shell=is_win))
  231. try_config = {}
  232. for master in masters:
  233. try_config.setdefault(master, {})
  234. for builder in masters[master]:
  235. # Do not trigger presubmit builders, since they're likely to fail
  236. # (e.g. OWNERS checks before finished code review), and we're
  237. # running local presubmit anyway.
  238. if 'presubmit' not in builder:
  239. try_config[master][builder] = ['defaulttests']
  240. return try_config