| #!/usr/bin/env python3 |
| # Copyright 2017 gRPC 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 |
| # |
| # http://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. |
| |
| import argparse |
| import multiprocessing |
| import os |
| import subprocess |
| import sys |
| |
| sys.path.append( |
| os.path.join( |
| os.path.dirname(sys.argv[0]), "..", "run_tests", "python_utils" |
| ) |
| ) |
| import jobset |
| |
| clang_tidy = os.environ.get("CLANG_TIDY", "clang-tidy") |
| |
| argp = argparse.ArgumentParser(description="Run clang-tidy against core") |
| argp.add_argument("files", nargs="+", help="Files to tidy") |
| argp.add_argument("--fix", dest="fix", action="store_true") |
| argp.add_argument( |
| "-j", |
| "--jobs", |
| type=int, |
| default=multiprocessing.cpu_count(), |
| help="Number of CPUs to use", |
| ) |
| argp.add_argument("--only-changed", dest="only_changed", action="store_true") |
| argp.set_defaults(fix=False, only_changed=False) |
| args = argp.parse_args() |
| |
| # Explicitly passing the .clang-tidy config by reading it. |
| # This is required because source files in the compilation database are |
| # in a different source tree so clang-tidy cannot find the right config file |
| # by seeking their parent directories. |
| with open(".clang-tidy") as f: |
| config = f.read() |
| cmdline = [ |
| clang_tidy, |
| "--config=" + config, |
| ] |
| |
| if args.fix: |
| cmdline.append("--fix-errors") |
| |
| if args.only_changed: |
| orig_files = set(args.files) |
| actual_files = [] |
| output = subprocess.check_output( |
| ["git", "diff", "upstream/master", "HEAD", "--name-only"] |
| ) |
| for line in output.decode("ascii").splitlines(False): |
| if line in orig_files: |
| print(("check: %s" % line)) |
| actual_files.append(line) |
| else: |
| print(("skip: %s - not in the build" % line)) |
| args.files = actual_files |
| |
| jobs = [] |
| for filename in args.files: |
| jobs.append( |
| jobset.JobSpec( |
| cmdline + [filename], |
| shortname=filename, |
| timeout_seconds=15 * 60, |
| ) |
| ) |
| |
| num_fails, res_set = jobset.run(jobs, maxjobs=args.jobs, quiet_success=True) |
| sys.exit(num_fails) |