# 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)