|  | #!/usr/bin/env python3 | 
|  | # Copyright 2021 The Pigweed 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. | 
|  | """Example presubmit check script.""" | 
|  |  | 
|  | import argparse | 
|  | import logging | 
|  | import os | 
|  | from pathlib import Path | 
|  | import re | 
|  | import sys | 
|  | from typing import Callable | 
|  |  | 
|  | try: | 
|  | import pw_cli.log | 
|  | except ImportError: | 
|  | print( | 
|  | 'ERROR: Activate the environment before running presubmits!', | 
|  | file=sys.stderr, | 
|  | ) | 
|  | sys.exit(2) | 
|  |  | 
|  | import pw_presubmit | 
|  | from pw_presubmit import ( | 
|  | build, | 
|  | cli, | 
|  | cpp_checks, | 
|  | format_code, | 
|  | git_repo, | 
|  | inclusive_language, | 
|  | install_hook, | 
|  | keep_sorted, | 
|  | python_checks, | 
|  | ) | 
|  | from pw_presubmit.presubmit_context import PresubmitContext, PresubmitFailure | 
|  |  | 
|  | _LOG = logging.getLogger(__name__) | 
|  |  | 
|  | # Set up variables for key project paths. | 
|  | try: | 
|  | PROJECT_ROOT = Path(os.environ['PIGWEED_EXPERIMENTAL_ROOT']) | 
|  | except KeyError: | 
|  | print( | 
|  | 'ERROR: The presubmit checks must be run in the sample project\'s root' | 
|  | ' directory', | 
|  | file=sys.stderr, | 
|  | ) | 
|  | sys.exit(2) | 
|  |  | 
|  | PIGWEED_ROOT = PROJECT_ROOT / 'third_party' / 'pigweed' | 
|  | REPOS = ( | 
|  | PROJECT_ROOT, | 
|  | PIGWEED_ROOT, | 
|  | PROJECT_ROOT / 'third_party' / 'nanopb', | 
|  | ) | 
|  |  | 
|  | # Rerun the build if files with these extensions change. | 
|  | _BUILD_EXTENSIONS = frozenset( | 
|  | ['.rst', '.gn', '.gni', *format_code.C_FORMAT.extensions] | 
|  | ) | 
|  |  | 
|  |  | 
|  | # | 
|  | # Presubmit checks | 
|  | # | 
|  | def default_build(ctx: PresubmitContext): | 
|  | """Creates a default build.""" | 
|  | build.gn_gen(ctx) | 
|  | build.ninja(ctx) | 
|  |  | 
|  |  | 
|  | def _package_root_arg(name: str) -> Callable[[PresubmitContext], str]: | 
|  | def _format(ctx: PresubmitContext) -> str: | 
|  | return '"{}"'.format(ctx.package_root / name) | 
|  |  | 
|  | return _format | 
|  |  | 
|  |  | 
|  | teensy_build = build.GnGenNinja( | 
|  | name='teensy_build', | 
|  | packages=('teensy',), | 
|  | gn_args=dict( | 
|  | pw_arduino_build_CORE_PATH=lambda ctx: '"{}"'.format( | 
|  | str(ctx.package_root) | 
|  | ), | 
|  | pw_arduino_build_CORE_NAME='"teensy"', | 
|  | pw_arduino_build_PACKAGE_NAME='"avr/1.58.1"', | 
|  | pw_arduino_build_BOARD='"teensy41"', | 
|  | pw_arduino_build_MENU_OPTIONS=( | 
|  | '["menu.usb.serial", "menu.keys.en-us", "menu.opt.o2std"]' | 
|  | ), | 
|  | ), | 
|  | ) | 
|  |  | 
|  | pico_build = build.GnGenNinja( | 
|  | name='pico_build', | 
|  | packages=('pico_sdk',), | 
|  | gn_args=dict( | 
|  | PICO_SRC_DIR=_package_root_arg('pico_sdk'), | 
|  | dir_pw_third_party_freertos='"//third_party/freertos/Source"', | 
|  | ), | 
|  | ) | 
|  |  | 
|  | stm32cube_f4_build = build.GnGenNinja( | 
|  | name='stm32cube_f4_build', | 
|  | packages=('stm32cube_f4',), | 
|  | gn_args=dict( | 
|  | dir_pw_third_party_stm32cube_f4=_package_root_arg('stm32cube_f4'), | 
|  | dir_pw_third_party_freertos='"//third_party/freertos/Source"', | 
|  | ), | 
|  | ) | 
|  |  | 
|  | stm32cube_f7_build = build.GnGenNinja( | 
|  | name='stm32cube_f7_build', | 
|  | packages=('stm32cube_f7',), | 
|  | gn_args=dict( | 
|  | dir_pw_third_party_stm32cube_f7=_package_root_arg('stm32cube_f7'), | 
|  | dir_pw_third_party_freertos='"//third_party/freertos/Source"', | 
|  | ), | 
|  | ) | 
|  |  | 
|  | mimxrt595_evk_build = build.GnGenNinja( | 
|  | name='mimxrt595_evk_build', | 
|  | gn_args=dict( | 
|  | dir_pw_third_party_freertos='"//third_party/freertos/Source"', | 
|  | pw_MIMXRT595_EVK_SDK=_package_root_arg("SDK_2_12_1_EVK-MIMXRT595"), | 
|  | pw_target_mimxrt595_evk_MANIFEST=_package_root_arg( | 
|  | "SDK_2_12_1_EVK-MIMXRT595/EVK-MIMXRT595_manifest_v3_10.xml" | 
|  | ), | 
|  | pw_third_party_mcuxpresso_SDK="//targets/mimxrt595_evk:mimxrt595_sdk", | 
|  | ), | 
|  | ) | 
|  |  | 
|  | pw_graphics_host = build.GnGenNinja( | 
|  | name='pw_graphics_host', | 
|  | packages=('imgui', 'glfw'), | 
|  | gn_args=dict( | 
|  | dir_pw_third_party_glfw=_package_root_arg('glfw'), | 
|  | dir_pw_third_party_imgui=_package_root_arg('imgui'), | 
|  | ), | 
|  | ) | 
|  |  | 
|  |  | 
|  | def bazel_test(ctx: PresubmitContext): | 
|  | build.bazel(ctx, 'test', '//...') | 
|  |  | 
|  |  | 
|  | def check_for_git_changes(_: PresubmitContext): | 
|  | """Checks that repositories have all changes commited.""" | 
|  | checked_repos = (PIGWEED_ROOT, *REPOS) | 
|  | changes = [r for r in checked_repos if git_repo.has_uncommitted_changes(r)] | 
|  | for repo in changes: | 
|  | _LOG.error('There are uncommitted changes in the %s repo!', repo.name) | 
|  | if changes: | 
|  | _LOG.warning( | 
|  | 'Commit or stash pending changes before running the presubmit.' | 
|  | ) | 
|  | raise PresubmitFailure | 
|  |  | 
|  |  | 
|  | # Avoid running some checks on certain paths. | 
|  | PATH_EXCLUSIONS = ( | 
|  | re.compile(r'^external/'), | 
|  | re.compile(r'^third_party/'), | 
|  | re.compile(r'^vendor/'), | 
|  | ) | 
|  |  | 
|  | # | 
|  | # Presubmit check programs | 
|  | # | 
|  | OTHER_CHECKS = ( | 
|  | build.gn_gen_check, | 
|  | inclusive_language.presubmit_check.with_filter(exclude=PATH_EXCLUSIONS), | 
|  | pw_graphics_host, | 
|  | mimxrt595_evk_build, | 
|  | teensy_build, | 
|  | stm32cube_f7_build, | 
|  | ) | 
|  |  | 
|  | QUICK = ( | 
|  | # List some presubmit checks to run | 
|  | default_build, | 
|  | # Use the upstream formatting checks, with custom path filters applied. | 
|  | format_code.presubmit_checks(), | 
|  | ) | 
|  |  | 
|  | LINTFORMAT = ( | 
|  | # keep-sorted: start | 
|  | cpp_checks.pragma_once, | 
|  | format_code.presubmit_checks(), | 
|  | keep_sorted.presubmit_check, | 
|  | python_checks.gn_python_lint, | 
|  | # keep-sorted: end | 
|  | ) | 
|  |  | 
|  | FULL = ( | 
|  | cpp_checks.pragma_once, | 
|  | QUICK,  # Add all checks from the 'quick' program | 
|  | # Use the upstream Python checks, with custom path filters applied. | 
|  | python_checks.gn_python_check, | 
|  | # TODO: https://pwbug.dev/325649415 - Re-enable when rp2040 targets are | 
|  | # updated | 
|  | # pico_build, | 
|  | stm32cube_f4_build, | 
|  | stm32cube_f7_build, | 
|  | ) | 
|  |  | 
|  | CI_CQ = ( | 
|  | default_build, | 
|  | # TODO: https://pwbug.dev/325649415 - Re-enable when rp2040 targets are | 
|  | # updated | 
|  | # pico_build, | 
|  | stm32cube_f4_build, | 
|  | stm32cube_f7_build, | 
|  | bazel_test, | 
|  | ) | 
|  |  | 
|  | PROGRAMS = pw_presubmit.Programs( | 
|  | # keep-sorted: start | 
|  | ci_cq=CI_CQ, | 
|  | full=FULL, | 
|  | lintformat=LINTFORMAT, | 
|  | other_checks=OTHER_CHECKS, | 
|  | quick=QUICK, | 
|  | # keep-sorted: end | 
|  | ) | 
|  |  | 
|  |  | 
|  | def run(install: bool, exclude: list, **presubmit_args) -> int: | 
|  | """Process the --install argument then invoke pw_presubmit.""" | 
|  |  | 
|  | # Install the presubmit Git pre-push hook, if requested. | 
|  | if install: | 
|  | install_hook.install_git_hook( | 
|  | 'pre-push', | 
|  | [ | 
|  | 'python', | 
|  | '-m', | 
|  | 'pigweed_experimental_tools.presubmit_checks', | 
|  | '--base', | 
|  | 'origin/main..HEAD', | 
|  | '--program', | 
|  | 'quick', | 
|  | ], | 
|  | ) | 
|  | return 0 | 
|  |  | 
|  | exclude.extend(PATH_EXCLUSIONS) | 
|  | return cli.run(root=PROJECT_ROOT, exclude=exclude, **presubmit_args) | 
|  |  | 
|  |  | 
|  | def main() -> int: | 
|  | """Run the presubmit checks for this repository.""" | 
|  | parser = argparse.ArgumentParser(description=__doc__) | 
|  | cli.add_arguments(parser, PROGRAMS, 'quick') | 
|  |  | 
|  | # Define an option for installing a Git pre-push hook for this script. | 
|  | parser.add_argument( | 
|  | '--install', | 
|  | action='store_true', | 
|  | help='Install the presubmit as a Git pre-push hook and exit.', | 
|  | ) | 
|  |  | 
|  | return run(**vars(parser.parse_args())) | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | pw_cli.log.install(logging.INFO) | 
|  | sys.exit(main()) |