blob: 9d259f4391b0340f859cdea11ef5540092c380e8 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2016 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Lints all of Cobalt's C++ files."""
from __future__ import print_function
import os
import shutil
import subprocess
import sys
import re
THIS_DIR = os.path.dirname(__file__)
SRC_ROOT_DIR = os.path.abspath(os.path.join(THIS_DIR, os.pardir))
OUT_DIR = os.path.abspath(os.path.join(THIS_DIR, os.pardir, 'out'))
CLANG_TIDY = os.path.join(SRC_ROOT_DIR, 'sysroot', 'share', 'clang',
'run-clang-tidy.py')
CHECK_HEADER_GUARDS = os.path.join(SRC_ROOT_DIR, 'tools', 'style',
'check-header-guards.py')
# A list of directories which should be skipped while walking the directory
# tree looking for C++ files to be linted. We also skip directories starting
# with a "." such as ".git"
SKIP_LINT_DIRS = [
os.path.join(SRC_ROOT_DIR, 'out'),
os.path.join(SRC_ROOT_DIR, 'sysroot'),
os.path.join(SRC_ROOT_DIR, 'third_party'),
os.path.join(SRC_ROOT_DIR, 'src', 'bin', 'config_parser', 'src',
'source_generator', 'source_generator_test_files'),
]
TEST_FILE_REGEX = re.compile('.*_(unit)?tests?.cc$')
TEST_FILE_CLANG_TIDY_CHECKS = [
'-readability-magic-numbers',
'-misc-non-private-member-variables-in-classes'
]
# Given a directory's parent path and name, returns a boolean indicating whether
# or not the directory should be skipped for liniting.
def should_skip_dir(parent_path, name):
if name.startswith('.'):
return True
full_path = os.path.join(parent_path, name)
for p in SKIP_LINT_DIRS:
if full_path.startswith(p):
return True
return False
def main(only_directories=[]):
status = 0
clang_tidy_files = []
clang_tidy_test_files = []
only_directories = [os.path.join(SRC_ROOT_DIR, d) for d in only_directories]
for root, dirs, files in os.walk(SRC_ROOT_DIR):
for f in files:
if f.endswith('.h') or f.endswith('.cc'):
full_path = os.path.join(root, f)
if only_directories and len(
[d for d in only_directories if full_path.startswith(d)]) == 0:
continue
if TEST_FILE_REGEX.match(full_path):
clang_tidy_test_files.append(full_path)
else:
clang_tidy_files.append(full_path)
# Before recursing into directories remove the ones we want to skip.
dirs_to_skip = [dir for dir in dirs if should_skip_dir(root, dir)]
for d in dirs_to_skip:
dirs.remove(d)
header_files = [
f for f in clang_tidy_files + clang_tidy_test_files
if f.endswith('.h') and not os.path.islink(f)
]
print('Running check-header-guards.py on %d files' % len(header_files))
if len(header_files) > 0:
try:
subprocess.check_call([CHECK_HEADER_GUARDS] + header_files)
except:
status += 1
clang_tidy_command = [CLANG_TIDY, '-quiet', '-p', OUT_DIR]
print('Running clang-tidy on %d source files' % len(clang_tidy_files))
if len(clang_tidy_files) > 0:
try:
subprocess.check_call(clang_tidy_command + clang_tidy_files)
except:
status += 1
print('Running clang-tidy on %d test files' % len(clang_tidy_test_files))
if len(clang_tidy_test_files) > 0:
try:
subprocess.check_call(
clang_tidy_command +
['-checks=%s' % ','.join(TEST_FILE_CLANG_TIDY_CHECKS)] +
clang_tidy_test_files)
except:
status += 1
return status
if __name__ == '__main__':
exit(main())