blob: 9ffc53a1f0957aa0641b1ce8bd6736ee72362928 [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
Shahbaz Youssefi634ee432019-12-16 11:39:10 -050011import re
Brian Sheedycc4d8332019-09-11 17:26:00 -070012import shutil
13import subprocess
14import sys
15import tempfile
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050016
James Darpinian4dff9952019-12-10 17:05:37 -080017# Fragment of a regular expression that matches C++ and Objective-C++ implementation files and headers.
18_IMPLEMENTATION_AND_HEADER_EXTENSIONS = r'\.(cc|cpp|cxx|mm|h|hpp|hxx)$'
Jamie Madill73397e82019-01-09 10:33:16 -050019
Jamie Madill73397e82019-01-09 10:33:16 -050020# Fragment of a regular expression that matches C++ and Objective-C++ header files.
21_HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$'
22
Brian Sheedycc4d8332019-09-11 17:26:00 -070023_PRIMARY_EXPORT_TARGETS = [
24 '//:libEGL',
25 '//:libGLESv1_CM',
26 '//:libGLESv2',
27 '//:translator',
28]
29
Jamie Madill73397e82019-01-09 10:33:16 -050030
Jamie Madill9e438ee2019-07-05 08:44:23 -040031def _CheckChangeHasBugField(input_api, output_api):
Shahbaz Youssefi634ee432019-12-16 11:39:10 -050032 """Requires that the changelist have a Bug: field from a known project."""
Jamie Madill9e438ee2019-07-05 08:44:23 -040033 bugs = input_api.change.BugsFromDescription()
34 if not bugs:
35 return [
Alexis Hetu4210e492019-10-10 14:22:03 -040036 output_api.PresubmitError('Please ensure that your description contains:\n'
37 '"Bug: angleproject:[bug number]"\n'
38 'directly above the Change-Id tag.')
Jamie Madill9e438ee2019-07-05 08:44:23 -040039 ]
Shahbaz Youssefi634ee432019-12-16 11:39:10 -050040
41 # The bug must be in the form of "project:number". None is also accepted, which is used by
42 # rollers as well as in very minor changes.
43 if len(bugs) == 1 and bugs[0] == 'None':
Jamie Madill9e438ee2019-07-05 08:44:23 -040044 return []
45
Geoff Lang13e4cdb2020-04-16 14:35:54 -040046 projects = ['angleproject:', 'chromium:', 'dawn:', 'fuchsia:', 'skia:', 'swiftshader:', 'b/']
47 bug_regex = re.compile(r"([a-z]+[:/])(\d+)")
Shahbaz Youssefi634ee432019-12-16 11:39:10 -050048 errors = []
49 extra_help = None
50
51 for bug in bugs:
52 if bug == 'None':
53 errors.append(
54 output_api.PresubmitError('Invalid bug tag "None" in presence of other bug tags.'))
55 continue
56
57 match = re.match(bug_regex, bug)
58 if match == None or bug != match.group(0) or match.group(1) not in projects:
59 errors.append(output_api.PresubmitError('Incorrect bug tag "' + bug + '".'))
60 if not extra_help:
61 extra_help = output_api.PresubmitError('Acceptable format is:\n\n'
62 ' Bug: project:bugnumber\n\n'
63 'Acceptable projects are:\n\n ' +
64 '\n '.join(projects))
65
66 if extra_help:
67 errors.append(extra_help)
68
69 return errors
70
Jamie Madill9e438ee2019-07-05 08:44:23 -040071
Jamie Madill73397e82019-01-09 10:33:16 -050072def _CheckCodeGeneration(input_api, output_api):
Jamie Madill04e9e552019-04-01 14:40:21 -040073
74 class Msg(output_api.PresubmitError):
Geoff Langd7d42392019-05-06 13:15:35 -040075 """Specialized error message"""
76
77 def __init__(self, message):
78 super(output_api.PresubmitError, self).__init__(
79 message,
Jamie Madill8dfc2b02019-11-25 15:12:58 -050080 long_text='Please ensure your ANGLE repositiory is synced to tip-of-tree\n'
Jamie Madill9e438ee2019-07-05 08:44:23 -040081 'and all ANGLE DEPS are fully up-to-date by running gclient sync.\n'
82 '\n'
Jamie Madill8dfc2b02019-11-25 15:12:58 -050083 'If that fails, run scripts/run_code_generation.py to refresh generated hashes.\n'
84 '\n'
Jamie Madill9e438ee2019-07-05 08:44:23 -040085 'If you are building ANGLE inside Chromium you must bootstrap ANGLE\n'
86 'before gclient sync. See the DevSetup documentation for more details.\n')
Jamie Madill04e9e552019-04-01 14:40:21 -040087
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050088 code_gen_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
89 'scripts/run_code_generation.py')
90 cmd_name = 'run_code_generation'
91 cmd = [input_api.python_executable, code_gen_path, '--verify-no-dirty']
Geoff Langd7d42392019-05-06 13:15:35 -040092 test_cmd = input_api.Command(name=cmd_name, cmd=cmd, kwargs={}, message=Msg)
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050093 if input_api.verbose:
94 print('Running ' + cmd_name)
95 return input_api.RunTests([test_cmd])
96
Shahbaz Youssefi98a35502019-01-08 22:09:39 -050097
Jamie Madill73397e82019-01-09 10:33:16 -050098# Taken directly from Chromium's PRESUBMIT.py
99def _CheckNewHeaderWithoutGnChange(input_api, output_api):
Geoff Langd7d42392019-05-06 13:15:35 -0400100 """Checks that newly added header files have corresponding GN changes.
Jamie Madill73397e82019-01-09 10:33:16 -0500101 Note that this is only a heuristic. To be precise, run script:
102 build/check_gn_headers.py.
103 """
104
Geoff Langd7d42392019-05-06 13:15:35 -0400105 def headers(f):
106 return input_api.FilterSourceFile(f, white_list=(r'.+%s' % _HEADER_EXTENSIONS,))
Jamie Madill73397e82019-01-09 10:33:16 -0500107
Geoff Langd7d42392019-05-06 13:15:35 -0400108 new_headers = []
109 for f in input_api.AffectedSourceFiles(headers):
110 if f.Action() != 'A':
111 continue
112 new_headers.append(f.LocalPath())
Jamie Madill73397e82019-01-09 10:33:16 -0500113
Geoff Langd7d42392019-05-06 13:15:35 -0400114 def gn_files(f):
115 return input_api.FilterSourceFile(f, white_list=(r'.+\.gn',))
Jamie Madill73397e82019-01-09 10:33:16 -0500116
Geoff Langd7d42392019-05-06 13:15:35 -0400117 all_gn_changed_contents = ''
118 for f in input_api.AffectedSourceFiles(gn_files):
119 for _, line in f.ChangedContents():
120 all_gn_changed_contents += line
Jamie Madill73397e82019-01-09 10:33:16 -0500121
Geoff Langd7d42392019-05-06 13:15:35 -0400122 problems = []
123 for header in new_headers:
124 basename = input_api.os_path.basename(header)
125 if basename not in all_gn_changed_contents:
126 problems.append(header)
Jamie Madill73397e82019-01-09 10:33:16 -0500127
Geoff Langd7d42392019-05-06 13:15:35 -0400128 if problems:
129 return [
130 output_api.PresubmitPromptWarning(
131 'Missing GN changes for new header files',
132 items=sorted(problems),
133 long_text='Please double check whether newly added header files need '
134 'corresponding changes in gn or gni files.\nThis checking is only a '
135 'heuristic. Run build/check_gn_headers.py to be precise.\n'
136 'Read https://crbug.com/661774 for more info.')
137 ]
138 return []
Jamie Madill73397e82019-01-09 10:33:16 -0500139
140
Brian Sheedycc4d8332019-09-11 17:26:00 -0700141def _CheckExportValidity(input_api, output_api):
142 outdir = tempfile.mkdtemp()
143 # shell=True is necessary on Windows, as otherwise subprocess fails to find
144 # either 'gn' or 'vpython3' even if they are findable via PATH.
145 use_shell = input_api.is_windows
146 try:
147 try:
148 subprocess.check_output(['gn', 'gen', outdir], shell=use_shell)
149 except subprocess.CalledProcessError as e:
150 return [
151 output_api.PresubmitError(
152 'Unable to run gn gen for export_targets.py: %s' % e.output)
153 ]
154 export_target_script = os.path.join(input_api.PresubmitLocalPath(), 'scripts',
155 'export_targets.py')
156 try:
157 subprocess.check_output(
158 ['vpython3', export_target_script, outdir] + _PRIMARY_EXPORT_TARGETS,
159 stderr=subprocess.STDOUT,
160 shell=use_shell)
161 except subprocess.CalledProcessError as e:
162 if input_api.is_committing:
163 return [output_api.PresubmitError('export_targets.py failed: %s' % e.output)]
164 return [
165 output_api.PresubmitPromptWarning(
166 'export_targets.py failed, this may just be due to your local checkout: %s' %
167 e.output)
168 ]
169 return []
170 finally:
171 shutil.rmtree(outdir)
172
173
James Darpinian4dff9952019-12-10 17:05:37 -0800174def _CheckTabsInSourceFiles(input_api, output_api):
175 """Forbids tab characters in source files due to a WebKit repo requirement. """
176
177 def implementation_and_headers(f):
178 return input_api.FilterSourceFile(
179 f, white_list=(r'.+%s' % _IMPLEMENTATION_AND_HEADER_EXTENSIONS,))
180
181 files_with_tabs = []
182 for f in input_api.AffectedSourceFiles(implementation_and_headers):
183 for (num, line) in f.ChangedContents():
184 if '\t' in line:
185 files_with_tabs.append(f)
186 break
187
188 if files_with_tabs:
189 return [
190 output_api.PresubmitError(
191 'Tab characters in source files.',
192 items=sorted(files_with_tabs),
193 long_text=
194 'Tab characters are forbidden in ANGLE source files because WebKit\'s Subversion\n'
195 'repository does not allow tab characters in source files.\n'
196 'Please remove tab characters from these files.')
197 ]
198 return []
199
200
Jamie Madill73397e82019-01-09 10:33:16 -0500201def CheckChangeOnUpload(input_api, output_api):
202 results = []
James Darpinian4dff9952019-12-10 17:05:37 -0800203 results.extend(_CheckTabsInSourceFiles(input_api, output_api))
Jamie Madill73397e82019-01-09 10:33:16 -0500204 results.extend(_CheckCodeGeneration(input_api, output_api))
Jamie Madill9e438ee2019-07-05 08:44:23 -0400205 results.extend(_CheckChangeHasBugField(input_api, output_api))
Geoff Langd7d42392019-05-06 13:15:35 -0400206 results.extend(input_api.canned_checks.CheckChangeHasDescription(input_api, output_api))
Jamie Madill73397e82019-01-09 10:33:16 -0500207 results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api))
Brian Sheedycc4d8332019-09-11 17:26:00 -0700208 results.extend(_CheckExportValidity(input_api, output_api))
Jamie Madill9e438ee2019-07-05 08:44:23 -0400209 results.extend(
210 input_api.canned_checks.CheckPatchFormatted(
211 input_api, output_api, result_factory=output_api.PresubmitError))
Jamie Madill73397e82019-01-09 10:33:16 -0500212 return results
213
Shahbaz Youssefi98a35502019-01-08 22:09:39 -0500214
215def CheckChangeOnCommit(input_api, output_api):
Jamie Madill73397e82019-01-09 10:33:16 -0500216 results = []
Jamie Madill04e9e552019-04-01 14:40:21 -0400217 results.extend(_CheckCodeGeneration(input_api, output_api))
Jamie Madill9e438ee2019-07-05 08:44:23 -0400218 results.extend(
219 input_api.canned_checks.CheckPatchFormatted(
220 input_api, output_api, result_factory=output_api.PresubmitError))
221 results.extend(_CheckChangeHasBugField(input_api, output_api))
Brian Sheedycc4d8332019-09-11 17:26:00 -0700222 results.extend(_CheckExportValidity(input_api, output_api))
Geoff Langd7d42392019-05-06 13:15:35 -0400223 results.extend(input_api.canned_checks.CheckChangeHasDescription(input_api, output_api))
Jamie Madill73397e82019-01-09 10:33:16 -0500224 return results