1# Copyright (c) 2017 The Chromium Embedded Framework Authors. 2# Portions copyright (c) 2011 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6from __future__ import absolute_import 7from __future__ import print_function 8import os, re, sys 9from clang_util import clang_format 10from file_util import eval_file, get_files, read_file, write_file 11from git_util import get_changed_files 12from yapf_util import yapf_format 13 14# File extensions that can be formatted. 15DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.h|.*\.java|.*\.mm|.*\.py)$" 16DEFAULT_LINT_BLACKLIST_REGEX = r"$^" 17 18# Directories containing these path components will be ignored. 19IGNORE_DIRECTORIES = [] 20 21# Script directory. 22script_dir = os.path.dirname(__file__) 23root_dir = os.path.join(script_dir, os.pardir) 24 25 26def msg(filename, status): 27 if sys.platform == 'win32': 28 # Use Unix path separator. 29 filename = filename.replace("\\", "/") 30 31 if len(filename) > 60: 32 # Truncate the file path in a nice way. 33 filename = filename[-57:] 34 pos = filename.find("/") 35 if pos > 0: 36 filename = filename[pos:] 37 filename = "..." + filename 38 39 print("%-60s %s" % (filename, status)) 40 41 42updatect = 0 43 44 45def read_config(): 46 style_cfg = os.path.join(root_dir, ".style.cfg") 47 if os.path.exists(style_cfg): 48 config = eval_file(style_cfg) 49 if 'ignore_directories' in config: 50 global IGNORE_DIRECTORIES 51 IGNORE_DIRECTORIES = config['ignore_directories'] 52 53 54def update_file(filename): 55 oldcontents = read_file(filename) 56 if len(oldcontents) == 0: 57 msg(filename, "empty") 58 return 59 60 if os.path.splitext(filename)[1] == ".py": 61 # Format Python files using YAPF. 62 newcontents = yapf_format(filename, oldcontents) 63 else: 64 # Format C/C++/ObjC/Java files using clang-format. 65 newcontents = clang_format(filename, oldcontents) 66 67 if newcontents is None: 68 raise Exception("Failed to process %s" % filename) 69 70 if newcontents != oldcontents: 71 msg(filename, "fixed") 72 global updatect 73 updatect += 1 74 write_file(filename, newcontents) 75 else: 76 msg(filename, "ok") 77 return 78 79 80def fix_style(filenames, white_list=None, black_list=None): 81 """ Execute clang-format with the specified arguments. """ 82 if not white_list: 83 white_list = DEFAULT_LINT_WHITELIST_REGEX 84 white_regex = re.compile(white_list) 85 if not black_list: 86 black_list = DEFAULT_LINT_BLACKLIST_REGEX 87 black_regex = re.compile(black_list) 88 89 for filename in filenames: 90 # Ignore files from specific directories. 91 ignore = False 92 for dir_part in filename.split(os.sep): 93 if dir_part in IGNORE_DIRECTORIES: 94 msg(filename, "ignored") 95 ignore = True 96 break 97 if ignore: 98 continue 99 100 if filename.find('*') > 0: 101 # Expand wildcards. 102 filenames.extend(get_files(filename)) 103 continue 104 105 if os.path.isdir(filename): 106 # Add directory contents. 107 filenames.extend(get_files(os.path.join(filename, "*"))) 108 continue 109 110 if not os.path.exists(filename): 111 files = get_changed_files(".", filename) 112 if len(files) > 0: 113 filenames.extend(files) 114 else: 115 msg(filename, "missing") 116 continue 117 118 if white_regex.match(filename): 119 if black_regex.match(filename): 120 msg(filename, "ignored") 121 else: 122 update_file(filename) 123 else: 124 msg(filename, "skipped") 125 126 127if __name__ == "__main__": 128 if len(sys.argv) == 1: 129 print("Usage: %s [file-path|git-hash|unstaged|staged] ...\n" % sys.argv[0]) 130 print(" Format C, C++ and ObjC files using Chromium's clang-format style.") 131 print("\nOptions:") 132 print(" file-path\tProcess the specified file or directory.") 133 print(" \t\tDirectories will be processed recursively.") 134 print(" \t\tThe \"*\" wildcard character is supported.") 135 print(" git-hash\tProcess all files changed in the specified Git commit.") 136 print(" unstaged\tProcess all unstaged files in the Git repo.") 137 print(" staged\t\tProcess all staged files in the Git repo.") 138 sys.exit(1) 139 140 # Read the configuration file. 141 read_config() 142 143 # Process anything passed on the command-line. 144 fix_style(sys.argv[1:]) 145 print('Done - Wrote %d files.' % updatect) 146