xref: /aosp_15_r20/external/libwebm/PRESUBMIT.py (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1# Copyright (c) 2021, Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7#   * Redistributions of source code must retain the above copyright
8#     notice, this list of conditions and the following disclaimer.
9#
10#   * Redistributions in binary form must reproduce the above copyright
11#     notice, this list of conditions and the following disclaimer in
12#     the documentation and/or other materials provided with the
13#     distribution.
14#
15#   * Neither the name of Google nor the names of its contributors may
16#     be used to endorse or promote products derived from this software
17#     without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30"""Top-level presubmit script for libwebm.
31
32See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
33details on the presubmit API built into depot_tools.
34"""
35import re
36import subprocess2
37
38USE_PYTHON3 = True
39_BASH_INDENTATION = "2"
40_GIT_COMMIT_SUBJECT_LENGTH = 65
41_INCLUDE_BASH_FILES_ONLY = [r".*\.sh$"]
42_INCLUDE_SOURCE_FILES_ONLY = [r".*\.(c|cc|[hc]pp|h)$"]
43_LIBWEBM_MAX_LINE_LENGTH = 80
44
45
46def _CheckCommitSubjectLength(input_api, output_api):
47  """Ensures commit's subject length is no longer than 65 chars."""
48  name = "git-commit subject"
49  cmd = ["git", "log", "-1", "--pretty=%s"]
50  start = input_api.time.time()
51  proc = subprocess2.Popen(
52      cmd,
53      stderr=subprocess2.PIPE,
54      stdout=subprocess2.PIPE,
55      universal_newlines=True)
56
57  stdout, _ = proc.communicate()
58  duration = input_api.time.time() - start
59
60  if not re.match(r"^Revert",
61                  stdout) and (len(stdout) - 1) > _GIT_COMMIT_SUBJECT_LENGTH:
62    failure_msg = (
63        "The commit subject: %s is too long (%d chars)\n"
64        "Try to keep this to 50 or less (up to 65 is permitted for "
65        "non-reverts).\n"
66        "https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-"
67        "Project#_commit_guidelines") % (stdout, len(stdout) - 1)
68    return output_api.PresubmitError("%s\n (%4.2fs) failed\n%s" %
69                                     (name, duration, failure_msg))
70
71  return output_api.PresubmitResult("%s\n (%4.2fs) success" % (name, duration))
72
73
74def _GetFilesToSkip(input_api):
75  """Skips libwebm-specific files."""
76  return list(input_api.DEFAULT_FILES_TO_SKIP) + [
77      r"\.pylintrc$",
78  ]
79
80
81def _CheckChangeLintsClean(input_api, output_api):
82  """Makes sure that libwebm/ code is cpplint clean."""
83  sources = lambda x: input_api.FilterSourceFile(
84      x, files_to_check=_INCLUDE_SOURCE_FILES_ONLY, files_to_skip=None)
85  return input_api.canned_checks.CheckChangeLintsClean(input_api, output_api,
86                                                       sources)
87
88
89def _RunShellCheckCmd(input_api, output_api, bash_file):
90  """shellcheck command wrapper."""
91  cmd = ["shellcheck", "-x", "-oall", "-sbash", bash_file]
92  name = "Check %s file." % bash_file
93  start = input_api.time.time()
94  output, rc = subprocess2.communicate(
95      cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
96  duration = input_api.time.time() - start
97  if rc == 0:
98    return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
99                                      (name, " ".join(cmd), duration))
100  return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
101                                   (name, " ".join(cmd), duration, output[1]))
102
103
104def _RunShfmtCheckCmd(input_api, output_api, bash_file):
105  """shfmt command wrapper."""
106  cmd = [
107      "shfmt", "-i", _BASH_INDENTATION, "-bn", "-ci", "-sr", "-kp", "-d",
108      bash_file
109  ]
110  name = "Check %s file." % bash_file
111  start = input_api.time.time()
112  output, rc = subprocess2.communicate(
113      cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
114  duration = input_api.time.time() - start
115  if rc == 0:
116    return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
117                                      (name, " ".join(cmd), duration))
118  return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
119                                   (name, " ".join(cmd), duration, output[1]))
120
121
122def _RunCmdOnCheckedFiles(input_api, output_api, run_cmd, files_to_check):
123  """Ensure that libwebm/ files are clean."""
124  file_filter = lambda x: input_api.FilterSourceFile(
125      x, files_to_check=files_to_check, files_to_skip=None)
126
127  affected_files = input_api.change.AffectedFiles(file_filter=file_filter)
128  results = [
129      run_cmd(input_api, output_api, f.AbsoluteLocalPath())
130      for f in affected_files
131  ]
132  return results
133
134
135def _CommonChecks(input_api, output_api):
136  results = []
137  results.extend(
138      input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
139          input_api, output_api))
140  results.extend(
141      input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api))
142  results.extend(
143      input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
144          input_api, output_api))
145  results.append(_CheckCommitSubjectLength(input_api, output_api))
146
147  source_file_filter = lambda x: input_api.FilterSourceFile(
148      x, files_to_skip=_GetFilesToSkip(input_api))
149  results.extend(
150      input_api.canned_checks.CheckLongLines(
151          input_api,
152          output_api,
153          maxlen=_LIBWEBM_MAX_LINE_LENGTH,
154          source_file_filter=source_file_filter))
155
156  results.extend(
157      input_api.canned_checks.CheckPatchFormatted(
158          input_api,
159          output_api,
160          check_clang_format=True,
161          check_python=True,
162          result_factory=output_api.PresubmitError))
163  results.extend(_CheckChangeLintsClean(input_api, output_api))
164
165  # Run pylint.
166  results.extend(
167      input_api.canned_checks.RunPylint(
168          input_api,
169          output_api,
170          files_to_skip=_GetFilesToSkip(input_api),
171          pylintrc=".pylintrc",
172          version="2.7"))
173
174  # Binaries shellcheck and shfmt are not installed in depot_tools.
175  # Installation is needed
176  try:
177    subprocess2.communicate(["shellcheck", "--version"])
178    results.extend(
179        _RunCmdOnCheckedFiles(input_api, output_api, _RunShellCheckCmd,
180                              _INCLUDE_BASH_FILES_ONLY))
181    print("shfmt")
182    subprocess2.communicate(["shfmt", "-version"])
183    results.extend(
184        _RunCmdOnCheckedFiles(input_api, output_api, _RunShfmtCheckCmd,
185                              _INCLUDE_BASH_FILES_ONLY))
186  except OSError as os_error:
187    results.append(
188        output_api.PresubmitPromptWarning(
189            "%s\nPlease install missing binaries locally." % os_error.args[0]))
190  return results
191
192
193def CheckChangeOnUpload(input_api, output_api):
194  results = []
195  results.extend(_CommonChecks(input_api, output_api))
196  return results
197
198
199def CheckChangeOnCommit(input_api, output_api):
200  results = []
201  results.extend(_CommonChecks(input_api, output_api))
202  return results
203