Shahbaz Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 1 | # 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 Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 4 | """Top-level presubmit script for code generation. |
| 5 | |
| 6 | See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts |
| 7 | for more details on the presubmit API built into depot_tools. |
| 8 | """ |
| 9 | |
Brian Sheedy | cc4d833 | 2019-09-11 17:26:00 -0700 | [diff] [blame] | 10 | import os |
Shahbaz Youssefi | 634ee43 | 2019-12-16 11:39:10 -0500 | [diff] [blame] | 11 | import re |
Brian Sheedy | cc4d833 | 2019-09-11 17:26:00 -0700 | [diff] [blame] | 12 | import shutil |
| 13 | import subprocess |
| 14 | import sys |
| 15 | import tempfile |
Shahbaz Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 16 | |
James Darpinian | b6ea6ed | 2020-12-29 16:30:29 -0800 | [diff] [blame] | 17 | # Fragment of a regular expression that matches C/C++ and Objective-C++ implementation files and headers. |
| 18 | _IMPLEMENTATION_AND_HEADER_EXTENSIONS = r'\.(c|cc|cpp|cxx|mm|h|hpp|hxx)$' |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 19 | |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 20 | # Fragment of a regular expression that matches C++ and Objective-C++ header files. |
| 21 | _HEADER_EXTENSIONS = r'\.(h|hpp|hxx)$' |
| 22 | |
Brian Sheedy | cc4d833 | 2019-09-11 17:26:00 -0700 | [diff] [blame] | 23 | _PRIMARY_EXPORT_TARGETS = [ |
| 24 | '//:libEGL', |
| 25 | '//:libGLESv1_CM', |
| 26 | '//:libGLESv2', |
| 27 | '//:translator', |
| 28 | ] |
| 29 | |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 30 | |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 31 | def _CheckCommitMessageFormatting(input_api, output_api): |
| 32 | |
| 33 | def _IsLineBlank(line): |
| 34 | return line.isspace() or line == "" |
| 35 | |
| 36 | def _PopBlankLines(lines, reverse=False): |
| 37 | if reverse: |
| 38 | while len(lines) > 0 and _IsLineBlank(lines[-1]): |
| 39 | lines.pop() |
| 40 | else: |
| 41 | while len(lines) > 0 and _IsLineBlank(lines[0]): |
| 42 | lines.pop(0) |
| 43 | |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 44 | def _IsTagLine(line): |
| 45 | return ":" in line |
| 46 | |
Manh Nguyen | cb8eea2 | 2020-07-01 23:17:43 -0400 | [diff] [blame] | 47 | def _SplitIntoMultipleCommits(description_text): |
| 48 | paragraph_split_pattern = r"((?m)^\s*$\n)" |
| 49 | multiple_paragraphs = re.split(paragraph_split_pattern, description_text) |
| 50 | multiple_commits = [""] |
| 51 | change_id_pattern = re.compile(r"(?m)^Change-Id: [a-zA-Z0-9]*$") |
| 52 | for paragraph in multiple_paragraphs: |
| 53 | multiple_commits[-1] += paragraph |
| 54 | if change_id_pattern.search(paragraph): |
| 55 | multiple_commits.append("") |
| 56 | if multiple_commits[-1] == "": |
| 57 | multiple_commits.pop() |
| 58 | return multiple_commits |
| 59 | |
| 60 | def _CheckTabInCommit(lines): |
| 61 | return all([line.find("\t") == -1 for line in lines]) |
| 62 | |
Trevor David Black | e815afb | 2020-09-07 22:09:22 +0000 | [diff] [blame] | 63 | allowlist_strings = ['Revert "', 'Roll ', 'Reland ', 'Re-land '] |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 64 | summary_linelength_warning_lower_limit = 65 |
| 65 | summary_linelength_warning_upper_limit = 70 |
Shahbaz Youssefi | 462e40f | 2020-06-04 14:15:59 -0400 | [diff] [blame] | 66 | description_linelength_limit = 72 |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 67 | |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 68 | git_output = input_api.change.DescriptionText() |
| 69 | |
Manh Nguyen | cb8eea2 | 2020-07-01 23:17:43 -0400 | [diff] [blame] | 70 | multiple_commits = _SplitIntoMultipleCommits(git_output) |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 71 | errors = [] |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 72 | |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 73 | for k in range(len(multiple_commits)): |
Manh Nguyen | cb8eea2 | 2020-07-01 23:17:43 -0400 | [diff] [blame] | 74 | commit_msg_lines = multiple_commits[k].splitlines() |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 75 | commit_number = len(multiple_commits) - k |
| 76 | commit_tag = "Commit " + str(commit_number) + ":" |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 77 | commit_msg_line_numbers = {} |
| 78 | for i in range(len(commit_msg_lines)): |
| 79 | commit_msg_line_numbers[commit_msg_lines[i]] = i + 1 |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 80 | _PopBlankLines(commit_msg_lines, True) |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 81 | _PopBlankLines(commit_msg_lines, False) |
Trevor David Black | e815afb | 2020-09-07 22:09:22 +0000 | [diff] [blame] | 82 | allowlisted = False |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 83 | if len(commit_msg_lines) > 0: |
Trevor David Black | e815afb | 2020-09-07 22:09:22 +0000 | [diff] [blame] | 84 | for allowlist_string in allowlist_strings: |
| 85 | if commit_msg_lines[0].startswith(allowlist_string): |
| 86 | allowlisted = True |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 87 | break |
Trevor David Black | e815afb | 2020-09-07 22:09:22 +0000 | [diff] [blame] | 88 | if allowlisted: |
Manh Nguyen | 505b6eb | 2020-06-04 09:11:21 -0400 | [diff] [blame] | 89 | continue |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 90 | |
Manh Nguyen | cb8eea2 | 2020-07-01 23:17:43 -0400 | [diff] [blame] | 91 | if not _CheckTabInCommit(commit_msg_lines): |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 92 | errors.append( |
| 93 | output_api.PresubmitError(commit_tag + "Tabs are not allowed in commit message.")) |
| 94 | |
| 95 | # the tags paragraph is at the end of the message |
| 96 | # the break between the tags paragraph is the first line without ":" |
| 97 | # this is sufficient because if a line is blank, it will not have ":" |
| 98 | last_paragraph_line_count = 0 |
| 99 | while len(commit_msg_lines) > 0 and _IsTagLine(commit_msg_lines[-1]): |
| 100 | last_paragraph_line_count += 1 |
| 101 | commit_msg_lines.pop() |
| 102 | if last_paragraph_line_count == 0: |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 103 | errors.append( |
| 104 | output_api.PresubmitError( |
Manh Nguyen | 31bbe1b | 2020-06-11 10:46:55 -0400 | [diff] [blame] | 105 | commit_tag + |
| 106 | "Please ensure that there are tags (e.g., Bug:, Test:) in your description.")) |
| 107 | if len(commit_msg_lines) > 0: |
| 108 | if not _IsLineBlank(commit_msg_lines[-1]): |
| 109 | output_api.PresubmitError(commit_tag + |
| 110 | "Please ensure that there exists 1 blank line " + |
| 111 | "between tags and description body.") |
| 112 | else: |
| 113 | # pop the blank line between tag paragraph and description body |
| 114 | commit_msg_lines.pop() |
| 115 | if len(commit_msg_lines) > 0 and _IsLineBlank(commit_msg_lines[-1]): |
| 116 | errors.append( |
| 117 | output_api.PresubmitError( |
| 118 | commit_tag + 'Please ensure that there exists only 1 blank line ' |
| 119 | 'between tags and description body.')) |
| 120 | # pop all the remaining blank lines between tag and description body |
| 121 | _PopBlankLines(commit_msg_lines, True) |
| 122 | if len(commit_msg_lines) == 0: |
| 123 | errors.append( |
| 124 | output_api.PresubmitError(commit_tag + |
| 125 | 'Please ensure that your description summary' |
| 126 | ' and description body are not blank.')) |
| 127 | continue |
| 128 | |
| 129 | if summary_linelength_warning_lower_limit <= len(commit_msg_lines[0]) \ |
| 130 | <= summary_linelength_warning_upper_limit: |
| 131 | errors.append( |
| 132 | output_api.PresubmitPromptWarning( |
| 133 | commit_tag + "Your description summary should be on one line of " + |
| 134 | str(summary_linelength_warning_lower_limit - 1) + " or less characters.")) |
| 135 | elif len(commit_msg_lines[0]) > summary_linelength_warning_upper_limit: |
| 136 | errors.append( |
| 137 | output_api.PresubmitError( |
| 138 | commit_tag + "Please ensure that your description summary is on one line of " + |
| 139 | str(summary_linelength_warning_lower_limit - 1) + " or less characters.")) |
| 140 | commit_msg_lines.pop(0) # get rid of description summary |
| 141 | if len(commit_msg_lines) == 0: |
| 142 | continue |
| 143 | if not _IsLineBlank(commit_msg_lines[0]): |
| 144 | errors.append( |
| 145 | output_api.PresubmitError(commit_tag + |
| 146 | 'Please ensure the summary is only 1 line and ' |
| 147 | 'there is 1 blank line between the summary ' |
| 148 | 'and description body.')) |
| 149 | else: |
| 150 | commit_msg_lines.pop(0) # pop first blank line |
| 151 | if len(commit_msg_lines) == 0: |
| 152 | continue |
| 153 | if _IsLineBlank(commit_msg_lines[0]): |
| 154 | errors.append( |
| 155 | output_api.PresubmitError(commit_tag + |
| 156 | 'Please ensure that there exists only 1 blank line ' |
| 157 | 'between description summary and description body.')) |
| 158 | # pop all the remaining blank lines between |
| 159 | # description summary and description body |
| 160 | _PopBlankLines(commit_msg_lines) |
| 161 | |
| 162 | # loop through description body |
| 163 | while len(commit_msg_lines) > 0: |
| 164 | line = commit_msg_lines.pop(0) |
| 165 | # lines starting with 4 spaces or lines without space(urls) |
| 166 | # are exempt from length check |
| 167 | if line.startswith(" ") or " " not in line: |
| 168 | continue |
| 169 | if len(line) > description_linelength_limit: |
| 170 | errors.append( |
| 171 | output_api.PresubmitError( |
| 172 | commit_tag + 'Line ' + str(commit_msg_line_numbers[line]) + |
| 173 | ' is too long.\n' + '"' + line + '"\n' + 'Please wrap it to ' + |
| 174 | str(description_linelength_limit) + ' characters. ' + |
| 175 | "Lines without spaces or lines starting with 4 spaces are exempt.")) |
| 176 | break |
Manh Nguyen | ebc6d0a | 2020-05-27 18:21:30 -0400 | [diff] [blame] | 177 | return errors |
| 178 | |
| 179 | |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 180 | def _CheckChangeHasBugField(input_api, output_api): |
Shahbaz Youssefi | 634ee43 | 2019-12-16 11:39:10 -0500 | [diff] [blame] | 181 | """Requires that the changelist have a Bug: field from a known project.""" |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 182 | bugs = input_api.change.BugsFromDescription() |
| 183 | if not bugs: |
| 184 | return [ |
Alexis Hetu | 4210e49 | 2019-10-10 14:22:03 -0400 | [diff] [blame] | 185 | output_api.PresubmitError('Please ensure that your description contains:\n' |
| 186 | '"Bug: angleproject:[bug number]"\n' |
| 187 | 'directly above the Change-Id tag.') |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 188 | ] |
Shahbaz Youssefi | 634ee43 | 2019-12-16 11:39:10 -0500 | [diff] [blame] | 189 | |
| 190 | # The bug must be in the form of "project:number". None is also accepted, which is used by |
| 191 | # rollers as well as in very minor changes. |
| 192 | if len(bugs) == 1 and bugs[0] == 'None': |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 193 | return [] |
| 194 | |
Corentin Wallez | 2753f20 | 2021-04-06 14:04:02 +0200 | [diff] [blame] | 195 | projects = [ |
| 196 | 'angleproject:', 'chromium:', 'dawn:', 'fuchsia:', 'skia:', 'swiftshader:', 'tint:', 'b/' |
| 197 | ] |
Geoff Lang | 13e4cdb | 2020-04-16 14:35:54 -0400 | [diff] [blame] | 198 | bug_regex = re.compile(r"([a-z]+[:/])(\d+)") |
Shahbaz Youssefi | 634ee43 | 2019-12-16 11:39:10 -0500 | [diff] [blame] | 199 | errors = [] |
| 200 | extra_help = None |
| 201 | |
| 202 | for bug in bugs: |
| 203 | if bug == 'None': |
| 204 | errors.append( |
| 205 | output_api.PresubmitError('Invalid bug tag "None" in presence of other bug tags.')) |
| 206 | continue |
| 207 | |
| 208 | match = re.match(bug_regex, bug) |
| 209 | if match == None or bug != match.group(0) or match.group(1) not in projects: |
| 210 | errors.append(output_api.PresubmitError('Incorrect bug tag "' + bug + '".')) |
| 211 | if not extra_help: |
| 212 | extra_help = output_api.PresubmitError('Acceptable format is:\n\n' |
| 213 | ' Bug: project:bugnumber\n\n' |
| 214 | 'Acceptable projects are:\n\n ' + |
| 215 | '\n '.join(projects)) |
| 216 | |
| 217 | if extra_help: |
| 218 | errors.append(extra_help) |
| 219 | |
| 220 | return errors |
| 221 | |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 222 | |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 223 | def _CheckCodeGeneration(input_api, output_api): |
Jamie Madill | 04e9e55 | 2019-04-01 14:40:21 -0400 | [diff] [blame] | 224 | |
| 225 | class Msg(output_api.PresubmitError): |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 226 | """Specialized error message""" |
| 227 | |
| 228 | def __init__(self, message): |
| 229 | super(output_api.PresubmitError, self).__init__( |
| 230 | message, |
Jamie Madill | 8dfc2b0 | 2019-11-25 15:12:58 -0500 | [diff] [blame] | 231 | long_text='Please ensure your ANGLE repositiory is synced to tip-of-tree\n' |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 232 | 'and all ANGLE DEPS are fully up-to-date by running gclient sync.\n' |
| 233 | '\n' |
Jamie Madill | 8dfc2b0 | 2019-11-25 15:12:58 -0500 | [diff] [blame] | 234 | 'If that fails, run scripts/run_code_generation.py to refresh generated hashes.\n' |
| 235 | '\n' |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 236 | 'If you are building ANGLE inside Chromium you must bootstrap ANGLE\n' |
| 237 | 'before gclient sync. See the DevSetup documentation for more details.\n') |
Jamie Madill | 04e9e55 | 2019-04-01 14:40:21 -0400 | [diff] [blame] | 238 | |
Shahbaz Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 239 | code_gen_path = input_api.os_path.join(input_api.PresubmitLocalPath(), |
| 240 | 'scripts/run_code_generation.py') |
| 241 | cmd_name = 'run_code_generation' |
| 242 | cmd = [input_api.python_executable, code_gen_path, '--verify-no-dirty'] |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 243 | test_cmd = input_api.Command(name=cmd_name, cmd=cmd, kwargs={}, message=Msg) |
Shahbaz Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 244 | if input_api.verbose: |
| 245 | print('Running ' + cmd_name) |
| 246 | return input_api.RunTests([test_cmd]) |
| 247 | |
Shahbaz Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 248 | |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 249 | # Taken directly from Chromium's PRESUBMIT.py |
| 250 | def _CheckNewHeaderWithoutGnChange(input_api, output_api): |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 251 | """Checks that newly added header files have corresponding GN changes. |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 252 | Note that this is only a heuristic. To be precise, run script: |
| 253 | build/check_gn_headers.py. |
| 254 | """ |
| 255 | |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 256 | def headers(f): |
Trevor David Black | f69aaf6 | 2020-10-05 21:50:10 +0000 | [diff] [blame] | 257 | return input_api.FilterSourceFile(f, files_to_check=(r'.+%s' % _HEADER_EXTENSIONS,)) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 258 | |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 259 | new_headers = [] |
| 260 | for f in input_api.AffectedSourceFiles(headers): |
| 261 | if f.Action() != 'A': |
| 262 | continue |
| 263 | new_headers.append(f.LocalPath()) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 264 | |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 265 | def gn_files(f): |
Trevor David Black | f69aaf6 | 2020-10-05 21:50:10 +0000 | [diff] [blame] | 266 | return input_api.FilterSourceFile(f, files_to_check=(r'.+\.gn',)) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 267 | |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 268 | all_gn_changed_contents = '' |
| 269 | for f in input_api.AffectedSourceFiles(gn_files): |
| 270 | for _, line in f.ChangedContents(): |
| 271 | all_gn_changed_contents += line |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 272 | |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 273 | problems = [] |
| 274 | for header in new_headers: |
| 275 | basename = input_api.os_path.basename(header) |
| 276 | if basename not in all_gn_changed_contents: |
| 277 | problems.append(header) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 278 | |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 279 | if problems: |
| 280 | return [ |
| 281 | output_api.PresubmitPromptWarning( |
| 282 | 'Missing GN changes for new header files', |
| 283 | items=sorted(problems), |
| 284 | long_text='Please double check whether newly added header files need ' |
| 285 | 'corresponding changes in gn or gni files.\nThis checking is only a ' |
| 286 | 'heuristic. Run build/check_gn_headers.py to be precise.\n' |
| 287 | 'Read https://crbug.com/661774 for more info.') |
| 288 | ] |
| 289 | return [] |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 290 | |
| 291 | |
Brian Sheedy | cc4d833 | 2019-09-11 17:26:00 -0700 | [diff] [blame] | 292 | def _CheckExportValidity(input_api, output_api): |
| 293 | outdir = tempfile.mkdtemp() |
| 294 | # shell=True is necessary on Windows, as otherwise subprocess fails to find |
| 295 | # either 'gn' or 'vpython3' even if they are findable via PATH. |
| 296 | use_shell = input_api.is_windows |
| 297 | try: |
| 298 | try: |
| 299 | subprocess.check_output(['gn', 'gen', outdir], shell=use_shell) |
| 300 | except subprocess.CalledProcessError as e: |
| 301 | return [ |
| 302 | output_api.PresubmitError( |
| 303 | 'Unable to run gn gen for export_targets.py: %s' % e.output) |
| 304 | ] |
| 305 | export_target_script = os.path.join(input_api.PresubmitLocalPath(), 'scripts', |
| 306 | 'export_targets.py') |
| 307 | try: |
| 308 | subprocess.check_output( |
| 309 | ['vpython3', export_target_script, outdir] + _PRIMARY_EXPORT_TARGETS, |
| 310 | stderr=subprocess.STDOUT, |
| 311 | shell=use_shell) |
| 312 | except subprocess.CalledProcessError as e: |
| 313 | if input_api.is_committing: |
| 314 | return [output_api.PresubmitError('export_targets.py failed: %s' % e.output)] |
| 315 | return [ |
| 316 | output_api.PresubmitPromptWarning( |
| 317 | 'export_targets.py failed, this may just be due to your local checkout: %s' % |
| 318 | e.output) |
| 319 | ] |
| 320 | return [] |
| 321 | finally: |
| 322 | shutil.rmtree(outdir) |
| 323 | |
| 324 | |
James Darpinian | 4dff995 | 2019-12-10 17:05:37 -0800 | [diff] [blame] | 325 | def _CheckTabsInSourceFiles(input_api, output_api): |
| 326 | """Forbids tab characters in source files due to a WebKit repo requirement. """ |
| 327 | |
James Darpinian | b6ea6ed | 2020-12-29 16:30:29 -0800 | [diff] [blame] | 328 | def implementation_and_headers_including_third_party(f): |
| 329 | # Check third_party files too, because WebKit's checks don't make exceptions. |
James Darpinian | 4dff995 | 2019-12-10 17:05:37 -0800 | [diff] [blame] | 330 | return input_api.FilterSourceFile( |
James Darpinian | b6ea6ed | 2020-12-29 16:30:29 -0800 | [diff] [blame] | 331 | f, |
| 332 | files_to_check=(r'.+%s' % _IMPLEMENTATION_AND_HEADER_EXTENSIONS,), |
| 333 | files_to_skip=[f for f in input_api.DEFAULT_FILES_TO_SKIP if not "third_party" in f]) |
James Darpinian | 4dff995 | 2019-12-10 17:05:37 -0800 | [diff] [blame] | 334 | |
| 335 | files_with_tabs = [] |
James Darpinian | b6ea6ed | 2020-12-29 16:30:29 -0800 | [diff] [blame] | 336 | for f in input_api.AffectedSourceFiles(implementation_and_headers_including_third_party): |
James Darpinian | 4dff995 | 2019-12-10 17:05:37 -0800 | [diff] [blame] | 337 | for (num, line) in f.ChangedContents(): |
| 338 | if '\t' in line: |
| 339 | files_with_tabs.append(f) |
| 340 | break |
| 341 | |
| 342 | if files_with_tabs: |
| 343 | return [ |
| 344 | output_api.PresubmitError( |
| 345 | 'Tab characters in source files.', |
| 346 | items=sorted(files_with_tabs), |
| 347 | long_text= |
| 348 | 'Tab characters are forbidden in ANGLE source files because WebKit\'s Subversion\n' |
| 349 | 'repository does not allow tab characters in source files.\n' |
| 350 | 'Please remove tab characters from these files.') |
| 351 | ] |
| 352 | return [] |
| 353 | |
| 354 | |
Tim Van Patten | f7d4473 | 2020-04-29 16:55:01 -0600 | [diff] [blame] | 355 | # https://stackoverflow.com/a/196392 |
| 356 | def is_ascii(s): |
| 357 | return all(ord(c) < 128 for c in s) |
| 358 | |
| 359 | |
| 360 | def _CheckNonAsciiInSourceFiles(input_api, output_api): |
| 361 | """Forbids non-ascii characters in source files. """ |
| 362 | |
| 363 | def implementation_and_headers(f): |
| 364 | return input_api.FilterSourceFile( |
Trevor David Black | f69aaf6 | 2020-10-05 21:50:10 +0000 | [diff] [blame] | 365 | f, files_to_check=(r'.+%s' % _IMPLEMENTATION_AND_HEADER_EXTENSIONS,)) |
Tim Van Patten | f7d4473 | 2020-04-29 16:55:01 -0600 | [diff] [blame] | 366 | |
| 367 | files_with_non_ascii = [] |
| 368 | for f in input_api.AffectedSourceFiles(implementation_and_headers): |
| 369 | for (num, line) in f.ChangedContents(): |
| 370 | if not is_ascii(line): |
Jamie Madill | a89750e | 2020-04-30 18:00:00 -0400 | [diff] [blame] | 371 | files_with_non_ascii.append("%s: %s" % (f, line)) |
Tim Van Patten | f7d4473 | 2020-04-29 16:55:01 -0600 | [diff] [blame] | 372 | break |
| 373 | |
| 374 | if files_with_non_ascii: |
| 375 | return [ |
| 376 | output_api.PresubmitError( |
| 377 | 'Non-ASCII characters in source files.', |
| 378 | items=sorted(files_with_non_ascii), |
| 379 | long_text='Non-ASCII characters are forbidden in ANGLE source files.\n' |
| 380 | 'Please remove non-ASCII characters from these files.') |
| 381 | ] |
| 382 | return [] |
| 383 | |
| 384 | |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 385 | def CheckChangeOnUpload(input_api, output_api): |
| 386 | results = [] |
James Darpinian | 4dff995 | 2019-12-10 17:05:37 -0800 | [diff] [blame] | 387 | results.extend(_CheckTabsInSourceFiles(input_api, output_api)) |
Tim Van Patten | f7d4473 | 2020-04-29 16:55:01 -0600 | [diff] [blame] | 388 | results.extend(_CheckNonAsciiInSourceFiles(input_api, output_api)) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 389 | results.extend(_CheckCodeGeneration(input_api, output_api)) |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 390 | results.extend(_CheckChangeHasBugField(input_api, output_api)) |
Geoff Lang | d7d4239 | 2019-05-06 13:15:35 -0400 | [diff] [blame] | 391 | results.extend(input_api.canned_checks.CheckChangeHasDescription(input_api, output_api)) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 392 | results.extend(_CheckNewHeaderWithoutGnChange(input_api, output_api)) |
Brian Sheedy | cc4d833 | 2019-09-11 17:26:00 -0700 | [diff] [blame] | 393 | results.extend(_CheckExportValidity(input_api, output_api)) |
Jamie Madill | 9e438ee | 2019-07-05 08:44:23 -0400 | [diff] [blame] | 394 | results.extend( |
| 395 | input_api.canned_checks.CheckPatchFormatted( |
| 396 | input_api, output_api, result_factory=output_api.PresubmitError)) |
Manh Nguyen | 2df3bf5 | 2020-06-17 17:07:47 -0400 | [diff] [blame] | 397 | results.extend(_CheckCommitMessageFormatting(input_api, output_api)) |
Jamie Madill | 73397e8 | 2019-01-09 10:33:16 -0500 | [diff] [blame] | 398 | return results |
| 399 | |
Shahbaz Youssefi | 98a3550 | 2019-01-08 22:09:39 -0500 | [diff] [blame] | 400 | |
| 401 | def CheckChangeOnCommit(input_api, output_api): |
Jamie Madill | a89750e | 2020-04-30 18:00:00 -0400 | [diff] [blame] | 402 | return CheckChangeOnUpload(input_api, output_api) |