| #!/usr/bin/env python3 | 
 | # Copyright 2020 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 | 
 |  | 
 | 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['SAMPLE_PROJECT_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' | 
 |  | 
 | # 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 check_for_git_changes(ctx: PresubmitContext): | 
 |     """Checks that repositories have all changes committed.""" | 
 |     checked_repos = (PIGWEED_ROOT, *ctx.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,) | 
 |  | 
 | QUICK = ( | 
 |     default_build, | 
 |     format_code.presubmit_checks( | 
 |         code_formats=format_code.CODE_FORMATS_WITH_BLACK | 
 |     ), | 
 | ) | 
 |  | 
 | LINTFORMAT = ( | 
 |     # keep-sorted: start | 
 |     cpp_checks.pragma_once, | 
 |     format_code.presubmit_checks(), | 
 |     inclusive_language.presubmit_check, | 
 |     keep_sorted.presubmit_check, | 
 |     python_checks.gn_python_lint, | 
 |     # keep-sorted: end | 
 | ) | 
 |  | 
 | FULL = ( | 
 |     QUICK,  # Add all checks from the 'quick' program | 
 |     LINTFORMAT, | 
 |     # Use the upstream Python checks, with custom path filters applied. | 
 |     python_checks.gn_python_check, | 
 | ) | 
 |  | 
 | PROGRAMS = pw_presubmit.Programs( | 
 |     # keep-sorted: start | 
 |     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', | 
 |                 'sample_project_tools.presubmit_checks', | 
 |                 '--base', | 
 |                 'origin/main..HEAD', | 
 |                 '--program', | 
 |                 'quick', | 
 |             ], | 
 |         ) | 
 |         return 0 | 
 |  | 
 |     exclude.extend(PATH_EXCLUSIONS) | 
 |     repos = git_repo.discover_submodules(superproject_dir=PROJECT_ROOT) | 
 |     return cli.run( | 
 |         root=PROJECT_ROOT, repositories=repos, 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()) |