• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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