123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- # Copyright (c) 2021, Google Inc. All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are
- # met:
- #
- # * Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- #
- # * Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in
- # the documentation and/or other materials provided with the
- # distribution.
- #
- # * Neither the name of Google nor the names of its contributors may
- # be used to endorse or promote products derived from this software
- # without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- """Top-level presubmit script for libwebp.
- See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
- details on the presubmit API built into depot_tools.
- """
- import re
- import subprocess2
- USE_PYTHON3 = True
- _BASH_INDENTATION = "2"
- _GIT_COMMIT_SUBJECT_LENGTH = 65
- _INCLUDE_BASH_FILES_ONLY = [r".*\.sh$"]
- _INCLUDE_MAN_FILES_ONLY = [r"man/.+\.1$"]
- _LIBWEBP_MAX_LINE_LENGTH = 80
- def _CheckCommitSubjectLength(input_api, output_api):
- """Ensures commit's subject length is no longer than 65 chars."""
- name = "git-commit subject"
- cmd = ["git", "log", "-1", "--pretty=%s"]
- start = input_api.time.time()
- proc = subprocess2.Popen(
- cmd,
- stderr=subprocess2.PIPE,
- stdout=subprocess2.PIPE,
- universal_newlines=True)
- stdout, _ = proc.communicate()
- duration = input_api.time.time() - start
- if not re.match(r"^Revert",
- stdout) and (len(stdout) - 1) > _GIT_COMMIT_SUBJECT_LENGTH:
- failure_msg = (
- "The commit subject: %s is too long (%d chars)\n"
- "Try to keep this to 50 or less (up to 65 is permitted for "
- "non-reverts).\n"
- "https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-"
- "Project#_commit_guidelines") % (stdout, len(stdout) - 1)
- return output_api.PresubmitError("%s\n (%4.2fs) failed\n%s" %
- (name, duration, failure_msg))
- return output_api.PresubmitResult("%s\n (%4.2fs) success" % (name, duration))
- def _GetFilesToSkip(input_api):
- return list(input_api.DEFAULT_FILES_TO_SKIP) + [
- r"swig/.*\.py$",
- r"\.pylintrc$",
- ]
- def _RunManCmd(input_api, output_api, man_file):
- """man command wrapper."""
- cmd = ["man", "--warnings", "-EUTF-8", "-l", "-Tutf8", "-Z", man_file]
- name = "Check %s file." % man_file
- start = input_api.time.time()
- output, _ = subprocess2.communicate(
- cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
- duration = input_api.time.time() - start
- if output[1]:
- return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
- (name, " ".join(cmd), duration, output[1]))
- return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
- (name, " ".join(cmd), duration))
- def _RunShellCheckCmd(input_api, output_api, bash_file):
- """shellcheck command wrapper."""
- cmd = ["shellcheck", "-x", "-oall", "-sbash", bash_file]
- name = "Check %s file." % bash_file
- start = input_api.time.time()
- output, rc = subprocess2.communicate(
- cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
- duration = input_api.time.time() - start
- if rc == 0:
- return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
- (name, " ".join(cmd), duration))
- return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
- (name, " ".join(cmd), duration, output[1]))
- def _RunShfmtCheckCmd(input_api, output_api, bash_file):
- """shfmt command wrapper."""
- cmd = [
- "shfmt", "-i", _BASH_INDENTATION, "-bn", "-ci", "-sr", "-kp", "-d",
- bash_file
- ]
- name = "Check %s file." % bash_file
- start = input_api.time.time()
- output, rc = subprocess2.communicate(
- cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
- duration = input_api.time.time() - start
- if rc == 0:
- return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
- (name, " ".join(cmd), duration))
- return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
- (name, " ".join(cmd), duration, output[1]))
- def _RunCmdOnCheckedFiles(input_api, output_api, run_cmd, files_to_check):
- """Ensure that libwebp/ files are clean."""
- file_filter = lambda x: input_api.FilterSourceFile(
- x, files_to_check=files_to_check, files_to_skip=None)
- affected_files = input_api.change.AffectedFiles(file_filter=file_filter)
- results = [
- run_cmd(input_api, output_api, f.AbsoluteLocalPath())
- for f in affected_files
- ]
- return results
- def _CommonChecks(input_api, output_api):
- """Ensures this patch does not have trailing spaces, extra EOLs,
- or long lines.
- """
- results = []
- results.extend(
- input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
- input_api, output_api))
- results.extend(
- input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api))
- results.extend(
- input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
- input_api, output_api))
- results.append(_CheckCommitSubjectLength(input_api, output_api))
- source_file_filter = lambda x: input_api.FilterSourceFile(
- x, files_to_skip=_GetFilesToSkip(input_api))
- results.extend(
- input_api.canned_checks.CheckLongLines(
- input_api,
- output_api,
- maxlen=_LIBWEBP_MAX_LINE_LENGTH,
- source_file_filter=source_file_filter))
- results.extend(
- input_api.canned_checks.CheckPatchFormatted(
- input_api,
- output_api,
- check_clang_format=False,
- check_python=True,
- result_factory=output_api.PresubmitError))
- results.extend(
- _RunCmdOnCheckedFiles(input_api, output_api, _RunManCmd,
- _INCLUDE_MAN_FILES_ONLY))
- # Run pylint.
- results.extend(
- input_api.canned_checks.RunPylint(
- input_api,
- output_api,
- files_to_skip=_GetFilesToSkip(input_api),
- pylintrc=".pylintrc",
- version="2.7"))
- # Binaries shellcheck and shfmt are not installed in depot_tools.
- # Installation is needed
- try:
- subprocess2.communicate(["shellcheck", "--version"])
- results.extend(
- _RunCmdOnCheckedFiles(input_api, output_api, _RunShellCheckCmd,
- _INCLUDE_BASH_FILES_ONLY))
- print("shfmt")
- subprocess2.communicate(["shfmt", "-version"])
- results.extend(
- _RunCmdOnCheckedFiles(input_api, output_api, _RunShfmtCheckCmd,
- _INCLUDE_BASH_FILES_ONLY))
- except OSError as os_error:
- results.append(
- output_api.PresubmitPromptWarning(
- "%s\nPlease install missing binaries locally." % os_error.args[0]))
- return results
- def CheckChangeOnUpload(input_api, output_api):
- results = []
- results.extend(_CommonChecks(input_api, output_api))
- return results
- def CheckChangeOnCommit(input_api, output_api):
- results = []
- results.extend(_CommonChecks(input_api, output_api))
- return results
|