blob: 0de387a817ec0e27f125f52fe65824a0711582ab [file] [log] [blame]
Shahbaz Youssefi98a35502019-01-08 22:09:39 -05001# Copyright 2019 The ANGLE Project 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.
Shahbaz Youssefi98a35502019-01-08 22:09:39 -05004"""Top-level presubmit script for code generation.
5
6See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
7for more details on the presubmit API built into depot_tools.
8"""
9
Brian Sheedycc4d8332019-09-11 17:26:00 -070010import os
11import shutil
12import subprocess
13import sys
14import tempfile
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050015
James Darpinian4dff9952019-12-10 17:05:37 -080016# Fragment of a regular expression that matches C++ and Objective-C++ implementation files and headers.
17_IMPLEMENTATION_AND_HEADER_EXTENSIONS = r'\.(cc|cpp|cxx|mm|h|hpp|hxx)$'
Jamie Madill73397e82019-01-09 10:33:16 -050018
Jamie Madill73397e82019-01-09 10:33:16 -050019# Fragment of a regular expression that matches C++ and Objective-C++ header files.
20_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
21
Brian Sheedycc4d8332019-09-11 17:26:00 -070022_PRIMARY_EXPORT_TARGETS = [
23 '//:libEGL',
24 '//:libGLESv1_CM',
25 '//:libGLESv2',
26 '//:translator',
27]
28
Jamie Madill73397e82019-01-09 10:33:16 -050029
Jamie Madill9e438ee2019-07-05 08:44:23 -040030def _CheckChangeHasBugField(input_api, output_api):
31 """Requires that the changelist have a Bug: field."""
32 bugs = input_api.change.BugsFromDescription()
33 if not bugs:
34 return [
Alexis Hetu4210e492019-10-10 14:22:03 -040035 output_api.PresubmitError('Please ensure that your description contains:\n'
36 '"Bug: angleproject:[bug number]"\n'
37 'directly above the Change-Id tag.')
Jamie Madill9e438ee2019-07-05 08:44:23 -040038 ]
39 elif not all([' ' not in bug for bug in bugs]):
40 return [
41 output_api.PresubmitError(
42 'Check bug tag formatting. Ensure there are no spaces after the colon.')
43 ]
44 else:
45 return []
46
47
Jamie Madill73397e82019-01-09 10:33:16 -050048def _CheckCodeGeneration(input_api, output_api):
Jamie Madill04e9e552019-04-01 14:40:21 -040049
50 class Msg(output_api.PresubmitError):
Geoff Langd7d42392019-05-06 13:15:35 -040051 """Specialized error message"""
52
53 def __init__(self, message):
54 super(output_api.PresubmitError, self).__init__(
55 message,
Jamie Madill8dfc2b02019-11-25 15:12:58 -050056 long_text='Please ensure your ANGLE repositiory is synced to tip-of-tree\n'
Jamie Madill9e438ee2019-07-05 08:44:23 -040057 'and all ANGLE DEPS are fully up-to-date by running gclient sync.\n'
58 '\n'
Jamie Madill8dfc2b02019-11-25 15:12:58 -050059 'If that fails, run scripts/run_code_generation.py to refresh generated hashes.\n'
60 '\n'
Jamie Madill9e438ee2019-07-05 08:44:23 -040061 'If you are building ANGLE inside Chromium you must bootstrap ANGLE\n'
62 'before gclient sync. See the DevSetup documentation for more details.\n')
Jamie Madill04e9e552019-04-01 14:40:21 -040063
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050064 code_gen_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
65 'scripts/run_code_generation.py')
66 cmd_name = 'run_code_generation'
67 cmd = [input_api.python_executable, code_gen_path, '--verify-no-dirty']
Geoff Langd7d42392019-05-06 13:15:35 -040068 test_cmd = input_api.Command(name=cmd_name, cmd=cmd, kwargs={}, message=Msg)
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050069 if input_api.verbose:
70 print('Running ' + cmd_name)
71 return input_api.RunTests([test_cmd])
72
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050073
Jamie Madill73397e82019-01-09 10:33:16 -050074# Taken directly from Chromium's PRESUBMIT.py
75def _CheckNewHeaderWithoutGnChange(input_api, output_api):
Geoff Langd7d42392019-05-06 13:15:35 -040076 """Checks that newly added header files have corresponding GN changes.
Jamie Madill73397e82019-01-09 10:33:16 -050077 Note that this is only a heuristic. To be precise, run script:
78 build/check_gn_headers.py.
79 """
80
Geoff Langd7d42392019-05-06 13:15:35 -040081 def headers(f):
82 return input_api.FilterSourceFile(f, white_list=(r'.+%s' % _HEADER_EXTENSIONS,))
Jamie Madill73397e82019-01-09 10:33:16 -050083
Geoff Langd7d42392019-05-06 13:15:35 -040084 new_headers = []
85 for f in input_api.AffectedSourceFiles(headers):
86 if f.Action() != 'A':
87 continue
88 new_headers.append(f.LocalPath())
Jamie Madill73397e82019-01-09 10:33:16 -050089
Geoff Langd7d42392019-05-06 13:15:35 -040090 def gn_files(f):
91 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn',))
Jamie Madill73397e82019-01-09 10:33:16 -050092
Geoff Langd7d42392019-05-06 13:15:35 -040093 all_gn_changed_contents = ''
94 for f in input_api.AffectedSourceFiles(gn_files):
95 for _, line in f.ChangedContents():
96 all_gn_changed_contents += line
Jamie Madill73397e82019-01-09 10:33:16 -050097
Geoff Langd7d42392019-05-06 13:15:35 -040098 problems = []
99 for header in new_headers:
100 basename = input_api.os_path.basename(header)
101 if basename not in all_gn_changed_contents:
102 problems.append(header)
Jamie Madill73397e82019-01-09 10:33:16 -0500103
Geoff Langd7d42392019-05-06 13:15:35 -0400104 if problems:
105 return [
106 output_api.PresubmitPromptWarning(
107 'Missing GN changes for new header files',
108 items=sorted(problems),
109 long_text='Please double check whether newly added header files need '
110 'corresponding changes in gn or gni files.\nThis checking is only a '
111 'heuristic. Run build/check_gn_headers.py to be precise.\n'
112 'Read https://crbug.com/661774 for more info.')
113 ]
114 return []
Jamie Madill73397e82019-01-09 10:33:16 -0500115
116
Brian Sheedycc4d8332019-09-11 17:26:00 -0700117def _CheckExportValidity(input_api, output_api):
118 outdir = tempfile.mkdtemp()
119 # shell=True is necessary on Windows, as otherwise subprocess fails to find
120 # either 'gn' or 'vpython3' even if they are findable via PATH.
121 use_shell = input_api.is_windows
122 try:
123 try:
124 subprocess.check_output(['gn', 'gen', outdir], shell=use_shell)
125 except subprocess.CalledProcessError as e:
126 return [
127 output_api.PresubmitError(
128 'Unable to run gn gen for export_targets.py: %s' % e.output)
129 ]
130 export_target_script = os.path.join(input_api.PresubmitLocalPath(), 'scripts',
131 'export_targets.py')
132 try:
133 subprocess.check_output(
134 ['vpython3', export_target_script, outdir] + _PRIMARY_EXPORT_TARGETS,
135 stderr=subprocess.STDOUT,
136 shell=use_shell)
137 except subprocess.CalledProcessError as e:
138 if input_api.is_committing:
139 return [output_api.PresubmitError('export_targets.py failed: %s' % e.output)]
140 return [
141 output_api.PresubmitPromptWarning(
142 'export_targets.py failed, this may just be due to your local checkout: %s' %
143 e.output)
144 ]
145 return []
146 finally:
147 shutil.rmtree(outdir)
148
149
James Darpinian4dff9952019-12-10 17:05:37 -0800150def _CheckTabsInSourceFiles(input_api, output_api):
151 """Forbids tab characters in source files due to a WebKit repo requirement. """
152
153 def implementation_and_headers(f):
154 return input_api.FilterSourceFile(
155 f, white_list=(r'.+%s' % _IMPLEMENTATION_AND_HEADER_EXTENSIONS,))
156
157 files_with_tabs = []
158 for f in input_api.AffectedSourceFiles(implementation_and_headers):
159 for (num, line) in f.ChangedContents():
160 if '\t' in line:
161 files_with_tabs.append(f)
162 break
163
164 if files_with_tabs:
165 return [
166 output_api.PresubmitError(
167 'Tab characters in source files.',
168 items=sorted(files_with_tabs),
169 long_text=
170 'Tab characters are forbidden in ANGLE source files because WebKit\'s Subversion\n'
171 'repository does not allow tab characters in source files.\n'
172 'Please remove tab characters from these files.')
173 ]
174 return []
175
176
Jamie Madill73397e82019-01-09 10:33:16 -0500177def CheckChangeOnUpload(input_api, output_api):
178 results = []
James Darpinian4dff9952019-12-10 17:05:37 -0800179 results.extend(_CheckTabsInSourceFiles(input_api, output_api))
Jamie Madill73397e82019-01-09 10:33:16 -0500180 results.extend(_CheckCodeGeneration(input_api, output_api))
Jamie Madill9e438ee2019-07-05 08:44:23 -0400181 results.extend(_CheckChangeHasBugField(input_api, output_api))
Geoff Langd7d42392019-05-06 13:15:35 -0400182 results.extend(input_api.canned_checks.CheckChangeHasDescription(input_api, output_api))
Jamie Madill73397e82019-01-09 10:33:16 -0500183 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Brian Sheedycc4d8332019-09-11 17:26:00 -0700184 results.extend(_CheckExportValidity(input_api, output_api))
Jamie Madill9e438ee2019-07-05 08:44:23 -0400185 results.extend(
186 input_api.canned_checks.CheckPatchFormatted(
187 input_api, output_api, result_factory=output_api.PresubmitError))
Jamie Madill73397e82019-01-09 10:33:16 -0500188 return results
189
Shahbaz Youssefi98a35502019-01-08 22:09:39 -0500190
191def CheckChangeOnCommit(input_api, output_api):
Jamie Madill73397e82019-01-09 10:33:16 -0500192 results = []
Jamie Madill04e9e552019-04-01 14:40:21 -0400193 results.extend(_CheckCodeGeneration(input_api, output_api))
Jamie Madill9e438ee2019-07-05 08:44:23 -0400194 results.extend(
195 input_api.canned_checks.CheckPatchFormatted(
196 input_api, output_api, result_factory=output_api.PresubmitError))
197 results.extend(_CheckChangeHasBugField(input_api, output_api))
Brian Sheedycc4d8332019-09-11 17:26:00 -0700198 results.extend(_CheckExportValidity(input_api, output_api))
Geoff Langd7d42392019-05-06 13:15:35 -0400199 results.extend(input_api.canned_checks.CheckChangeHasDescription(input_api, output_api))
Jamie Madill73397e82019-01-09 10:33:16 -0500200 return results