• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2017 gRPC authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import argparse
17import multiprocessing
18import os
19import subprocess
20import sys
21
22sys.path.append(
23    os.path.join(os.path.dirname(sys.argv[0]), '..', 'run_tests',
24                 'python_utils'))
25import jobset
26
27clang_tidy = os.environ.get('CLANG_TIDY', 'clang-tidy')
28
29argp = argparse.ArgumentParser(description='Run clang-tidy against core')
30argp.add_argument('files', nargs='+', help='Files to tidy')
31argp.add_argument('--fix', dest='fix', action='store_true')
32argp.add_argument('-j',
33                  '--jobs',
34                  type=int,
35                  default=multiprocessing.cpu_count(),
36                  help='Number of CPUs to use')
37argp.add_argument('--only-changed', dest='only_changed', action='store_true')
38argp.set_defaults(fix=False, only_changed=False)
39args = argp.parse_args()
40
41# Explicitly passing the .clang-tidy config by reading it.
42# This is required because source files in the compilation database are
43# in a different source tree so clang-tidy cannot find the right config file
44# by seeking their parent directories.
45with open(".clang-tidy") as f:
46    config = f.read()
47cmdline = [
48    clang_tidy,
49    '--config=' + config,
50]
51
52if args.fix:
53    cmdline.append('--fix-errors')
54
55if args.only_changed:
56    orig_files = set(args.files)
57    actual_files = []
58    output = subprocess.check_output(
59        ['git', 'diff', 'upstream/master', 'HEAD', '--name-only'])
60    for line in output.decode('ascii').splitlines(False):
61        if line in orig_files:
62            print(("check: %s" % line))
63            actual_files.append(line)
64        else:
65            print(("skip: %s - not in the build" % line))
66    args.files = actual_files
67
68jobs = []
69for filename in args.files:
70    jobs.append(
71        jobset.JobSpec(
72            cmdline + [filename],
73            shortname=filename,
74            timeout_seconds=15 * 60,
75        ))
76
77num_fails, res_set = jobset.run(jobs, maxjobs=args.jobs, quiet_success=True)
78sys.exit(num_fails)
79