--- a/tools/mach_commands.py
+++ b/tools/mach_commands.py
@@ -164,19 +164,23 @@ class PastebinProvider(object):
return 1
return 0
@CommandProvider
class FormatProvider(MachCommandBase):
@Command('clang-format', category='misc',
description='Run clang-format on current changes')
- @CommandArgument('--show', '-s', action='store_true',
+ @CommandArgument('--show', '-s', action='store_true', default=False,
help='Show diff output on instead of applying changes')
- def clang_format(self, show=False):
+ @CommandArgument('--path', '-p', nargs='+', default=None,
+ help='Specify the path(s) to reformat')
+ def clang_format(self, show, path):
+ # Run clang-format or clang-format-diff on the local changes
+ # or files/directories
import urllib2
plat = platform.system()
fmt = plat.lower() + "/clang-format-5.0~svn297730"
fmt_diff = "clang-format-diff-5.0~svn297730"
# We are currently using an unmodified snapshot of upstream clang-format.
# This is a temporary work around until clang 5.0 has been released with our changes.
@@ -188,29 +192,35 @@ class FormatProvider(MachCommandBase):
print("Unsupported platform " + plat + "/" + arch +
". Supported platforms are Windows/*, Linux/x86_64 and Darwin/x86_64")
return 1
os.chdir(self.topsrcdir)
self.prompt = True
try:
- if not self.locate_or_fetch(fmt):
+ clang_format = self.locate_or_fetch(fmt)
+ if not clang_format:
return 1
clang_format_diff = self.locate_or_fetch(fmt_diff, python_script=True)
if not clang_format_diff:
return 1
except urllib2.HTTPError as e:
print("HTTP error {0}: {1}".format(e.code, e.reason))
return 1
- return self.run_clang_format_diff(clang_format_diff, show)
+ if path is None:
+ return self.run_clang_format_diff(clang_format_diff, show)
+ else:
+ return self.run_clang_format_path(clang_format, show, path)
def locate_or_fetch(self, root, python_script=False):
+ # Download the clang-format binary & python clang-format-diff if doesn't
+ # exists
import urllib2
import hashlib
bin_sha = {
"Windows": "0cbfc306df48f01bfe804e5e89cef73b3abe8f884fb7a5208f8895897f19ec45c13760787298192bd37de057d0ded091640c7d504438e06ec880f071a38db89c", # noqa: E501
"Linux": "e6da4f6df074bfb15caefcf7767eb5670c02bb4768ba86ae4ab6b35235b53db012900a4f9e9a950ee140158a19532a71f21b986f511826bebc16f2ef83984e57", # noqa: E501
"Darwin": "18000940a11e5ab0c1fe950d4360292216c8e963dd708679c4c5fb8cc845f5919cef3f58a7e092555b8ea6b8d8a809d66153ea6d1e7c226a2c4f2b0b7ad1b2f3", # noqa: E501
"python_script": "34b6934a48a263ea3f88d48c2981d61ae6698823cfa689b9b0c8a607c224437ca0b9fdd434d260bd790d52a98455e2c2e2c745490d327ba84b4e22b7bb55b757", # noqa: E501
}
@@ -242,42 +252,100 @@ class FormatProvider(MachCommandBase):
with open(temp, "wb") as fh:
fh.write(data)
fh.close()
os.chmod(temp, os.stat(temp).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
os.rename(temp, target)
return target
def run_clang_format_diff(self, clang_format_diff, show):
+ # Run clang-format on the diff
+ # Note that this will potentially miss a lot things
from subprocess import Popen, PIPE
if os.path.exists(".hg"):
diff_process = Popen(["hg", "diff", "-U0", "-r", ".^",
"--include", "glob:**.c", "--include", "glob:**.cpp",
"--include", "glob:**.h",
"--exclude", "listfile:.clang-format-ignore"], stdout=PIPE)
else:
git_process = Popen(["git", "diff", "--no-color", "-U0", "HEAD^"], stdout=PIPE)
try:
- diff_process = Popen(["filterdiff", "--include=*.h", "--include=*.cpp",
+ diff_process = Popen(["filterdiff", "--include=*.h",
+ "--include=*.cpp", "--include=*.c",
"--exclude-from-file=.clang-format-ignore"],
stdin=git_process.stdout, stdout=PIPE)
except OSError as e:
if e.errno == errno.ENOENT:
print("Can't find filterdiff. Please install patchutils.")
else:
print("OSError {0}: {1}".format(e.code, e.reason))
return 1
args = [sys.executable, clang_format_diff, "-p1"]
if not show:
args.append("-i")
cf_process = Popen(args, stdin=diff_process.stdout)
return cf_process.communicate()[0]
+ def generate_path_list(self, paths):
+ pathToThirdparty = os.path.join(self.topsrcdir,
+ "tools",
+ "rewriting",
+ "ThirdPartyPaths.txt")
+ with open(pathToThirdparty) as f:
+ # Normalize the path (no trailing /)
+ ignored_dir = tuple(d.rstrip('/') for d in f.read().splitlines())
+
+ extensions = ('.cpp', '.c', '.h')
+
+ path_list = []
+ for f in paths:
+ if f.startswith(ignored_dir):
+ print("clang-format: Ignored third party code '{0}'".format(f))
+ continue
+
+ if os.path.isdir(f):
+ # Processing a directory, generate the file list
+ for folder, subs, files in os.walk(f):
+ subs.sort()
+ for filename in sorted(files):
+ f_in_dir = os.path.join(folder, filename)
+ if f_in_dir.endswith(extensions):
+ # Supported extension
+ path_list.append(f_in_dir)
+ else:
+ if f.endswith(extensions):
+ path_list.append(f)
+
+ return path_list
+
+ def run_clang_format_path(self, clang_format, show, paths):
+ # Run clang-format on files or directories directly
+ from subprocess import Popen
+
+ args = [clang_format, "-i"]
+
+ path_list = self.generate_path_list(paths)
+
+ if path_list == []:
+ return
+
+ args += path_list
+
+ # Run clang-format
+ cf_process = Popen(args)
+ if show:
+ # show the diff
+ if os.path.exists(".hg"):
+ cf_process = Popen(["hg", "diff"] + path_list)
+ else:
+ cf_process = Popen(["git", "diff"] + path_list)
+ return cf_process.communicate()[0]
+
def mozregression_import():
# Lazy loading of mozregression.
# Note that only the mach_interface module should be used from this file.
try:
import mozregression.mach_interface
except ImportError:
return None