blob: e0debaeff8d345c56bcb607d7cb25898c32c8a21 [file] [log] [blame]
# 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)