| # Copyright 2025 The BoringSSL Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Presubmit checks for BoringSSL. |
| |
| Run by the presubmit API in depot_tools, e.g. by running `git cl presubmit`. |
| """ |
| |
| import shutil |
| |
| PRESUBMIT_VERSION = '2.0.0' |
| USE_PYTHON3 = True |
| |
| |
| def _PassResult(stdout, stderr, retcode): |
| del stdout, stderr, retcode # Function does nothing. |
| return [] # Check passed. |
| |
| |
| def _RunTool(input_api, |
| output_api, |
| command, |
| handle_result=_PassResult): |
| """ |
| Runs a command and processes its result. |
| |
| handle_result(stdout, stderr, retcode) and explain_error(error) should each |
| return a list of output_api.PresubmitResult. |
| |
| Args: |
| input_api: API to read CL contents. |
| output_api: API to generate presubmit errors/warning to return. |
| handle_result: function receiving (stdout, stderr, retcode) parsing the |
| command result and turning it into a list of output_api.PresubmitResult. |
| |
| Returns: |
| List of presubmit errors. |
| """ |
| try: |
| out, retcode = input_api.subprocess.communicate( |
| command, |
| stdout=input_api.subprocess.PIPE, |
| stderr=input_api.subprocess.PIPE, |
| encoding='utf-8') |
| return handle_result(out[0], out[1], retcode) |
| except input_api.subprocess.CalledProcessError as e: |
| return [ |
| output_api.PresubmitPromptOrNotify( |
| 'Command "%s" returned exit code %d. Output: \n\n%s' % |
| ' '.join(command), e.returncode, e.output) |
| ] |
| |
| |
| def CheckPregeneratedFiles(input_api, output_api): |
| """Checks that pregenerated files are properly updated.""" |
| # TODO(chlily): Make this compatible with the util/bot environment for CI/CQ. |
| # Check that `go` is available on the $PATH. |
| go_path = shutil.which('go') |
| if not go_path: |
| return [ |
| output_api.PresubmitPromptOrNotify( |
| 'Could not check pregenerated files: Command "go" not found.') |
| ] |
| |
| # Find `clang` path. If not found, turn off the clang steps in pregenerate. |
| clang_path = shutil.which('clang') |
| |
| pregenerate_script_path = input_api.os_path.join( |
| input_api.change.RepositoryRoot(), 'util', 'pregenerate') |
| command = [go_path, 'run', pregenerate_script_path, |
| '-check', f'-clang={clang_path if clang_path is not None else ""}'] |
| |
| def HandlePregenerateResult(stdout, stderr, retcode): |
| del stdout # All output we care for is in stderr. |
| results = [] |
| if not clang_path: |
| results.append(output_api.PresubmitPromptOrNotify( |
| ('Ran `go run ./util/pregenerate -check` but could not find "clang": ' |
| 'CheckPregeneratedFiles results may not be complete.'))) |
| if retcode: |
| results.append(output_api.PresubmitError( |
| ('Found out-of-date generated files. ' |
| 'Run `go run ./util/pregenerate` to update them.'), |
| stderr.splitlines())) |
| return results |
| |
| return _RunTool(input_api, |
| output_api, |
| command, |
| handle_result=HandlePregenerateResult) |
| |
| |
| def CheckBuildifier(input_api, output_api): |
| """ |
| Runs Buildifier formatting check if the affected files include |
| *.bazel or *.bzl files. |
| |
| Args: |
| input_api: API to read CL contents. |
| output_api: API to generate presubmit errors/warning to return. |
| |
| Returns: |
| List of presubmit errors. |
| """ |
| file_paths = [] |
| for affected_file in input_api.AffectedFiles(include_deletes=False): |
| affected_file_path = affected_file.LocalPath() |
| if not affected_file_path.endswith(('.bzl', '.bazel')): |
| continue |
| if 'third_party' in affected_file_path or 'gen' in affected_file_path: |
| continue |
| file_paths.append(affected_file_path) |
| if not file_paths: |
| return [] # Check passed. |
| |
| # Check that `buildifier` is available on the $PATH. |
| # TODO(chlily): Make this compatible with the util/bot environment for CI/CQ. |
| buildifier_path = shutil.which('buildifier') |
| if not buildifier_path: |
| return [ |
| output_api.PresubmitPromptOrNotify( |
| 'Could not check *.bzl and *.bazel formatting: ' |
| 'Command "buildifier" not found. You can download buildifier from ' |
| 'https://github.com/bazelbuild/buildtools/releases') |
| ] |
| |
| def HandleBuildifierResult(stdout, stderr, retcode): |
| del stderr # This only parses stdout, as nothing failed. |
| if retcode == 4: # check mode failed (reformat is needed). |
| return [ |
| output_api.PresubmitError( |
| ('Found incorrectly formatted *.bzl or *.bazel files. ' |
| 'Run `buildifier` to update them.'), stdout.splitlines()) |
| ] |
| return [] # Check passed. |
| |
| return _RunTool(input_api, |
| output_api, [buildifier_path, '--mode=check'] + file_paths, |
| handle_result=HandleBuildifierResult) |