| # Copyright (c) 2017 The Chromium Embedded Framework Authors. | |
| # Portions copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| from __future__ import absolute_import | |
| from __future__ import print_function | |
| import os, re, sys | |
| from clang_util import clang_format | |
| from file_util import eval_file, get_files, read_file, write_file | |
| from git_util import get_changed_files | |
| from yapf_util import yapf_format | |
| # File extensions that can be formatted. | |
| DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.h|.*\.java|.*\.mm|.*\.py)$" | |
| DEFAULT_LINT_BLACKLIST_REGEX = r"$^" | |
| # Directories containing these path components will be ignored. | |
| IGNORE_DIRECTORIES = [] | |
| # Script directory. | |
| script_dir = os.path.dirname(__file__) | |
| root_dir = os.path.join(script_dir, os.pardir) | |
| def msg(filename, status): | |
| if sys.platform == 'win32': | |
| # Use Unix path separator. | |
| filename = filename.replace("\\", "/") | |
| if len(filename) > 60: | |
| # Truncate the file path in a nice way. | |
| filename = filename[-57:] | |
| pos = filename.find("/") | |
| if pos > 0: | |
| filename = filename[pos:] | |
| filename = "..." + filename | |
| print("%-60s %s" % (filename, status)) | |
| updatect = 0 | |
| def read_config(): | |
| style_cfg = os.path.join(root_dir, ".style.cfg") | |
| if os.path.exists(style_cfg): | |
| config = eval_file(style_cfg) | |
| if 'ignore_directories' in config: | |
| global IGNORE_DIRECTORIES | |
| IGNORE_DIRECTORIES = config['ignore_directories'] | |
| def update_file(filename): | |
| oldcontents = read_file(filename) | |
| if len(oldcontents) == 0: | |
| msg(filename, "empty") | |
| return | |
| if os.path.splitext(filename)[1] == ".py": | |
| # Format Python files using YAPF. | |
| newcontents = yapf_format(filename, oldcontents) | |
| else: | |
| # Format C/C++/ObjC/Java files using clang-format. | |
| newcontents = clang_format(filename, oldcontents) | |
| if newcontents is None: | |
| raise Exception("Failed to process %s" % filename) | |
| if newcontents != oldcontents: | |
| msg(filename, "fixed") | |
| global updatect | |
| updatect += 1 | |
| write_file(filename, newcontents) | |
| else: | |
| msg(filename, "ok") | |
| return | |
| def fix_style(filenames, white_list=None, black_list=None): | |
| """ Execute clang-format with the specified arguments. """ | |
| if not white_list: | |
| white_list = DEFAULT_LINT_WHITELIST_REGEX | |
| white_regex = re.compile(white_list) | |
| if not black_list: | |
| black_list = DEFAULT_LINT_BLACKLIST_REGEX | |
| black_regex = re.compile(black_list) | |
| for filename in filenames: | |
| # Ignore files from specific directories. | |
| ignore = False | |
| for dir_part in filename.split(os.sep): | |
| if dir_part in IGNORE_DIRECTORIES: | |
| msg(filename, "ignored") | |
| ignore = True | |
| break | |
| if ignore: | |
| continue | |
| if filename.find('*') > 0: | |
| # Expand wildcards. | |
| filenames.extend(get_files(filename)) | |
| continue | |
| if os.path.isdir(filename): | |
| # Add directory contents. | |
| filenames.extend(get_files(os.path.join(filename, "*"))) | |
| continue | |
| if not os.path.exists(filename): | |
| files = get_changed_files(".", filename) | |
| if len(files) > 0: | |
| filenames.extend(files) | |
| else: | |
| msg(filename, "missing") | |
| continue | |
| if white_regex.match(filename): | |
| if black_regex.match(filename): | |
| msg(filename, "ignored") | |
| else: | |
| update_file(filename) | |
| else: | |
| msg(filename, "skipped") | |
| if __name__ == "__main__": | |
| if len(sys.argv) == 1: | |
| print("Usage: %s [file-path|git-hash|unstaged|staged] ...\n" % sys.argv[0]) | |
| print(" Format C, C++ and ObjC files using Chromium's clang-format style.") | |
| print("\nOptions:") | |
| print(" file-path\tProcess the specified file or directory.") | |
| print(" \t\tDirectories will be processed recursively.") | |
| print(" \t\tThe \"*\" wildcard character is supported.") | |
| print(" git-hash\tProcess all files changed in the specified Git commit.") | |
| print(" unstaged\tProcess all unstaged files in the Git repo.") | |
| print(" staged\t\tProcess all staged files in the Git repo.") | |
| sys.exit(1) | |
| # Read the configuration file. | |
| read_config() | |
| # Process anything passed on the command-line. | |
| fix_style(sys.argv[1:]) | |
| print('Done - Wrote %d files.' % updatect) |