summaryrefslogtreecommitdiffstats
path: root/tools/lint/hooks_clang_format.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lint/hooks_clang_format.py')
-rwxr-xr-xtools/lint/hooks_clang_format.py99
1 files changed, 99 insertions, 0 deletions
diff --git a/tools/lint/hooks_clang_format.py b/tools/lint/hooks_clang_format.py
new file mode 100755
index 0000000000..9adb81b7f0
--- /dev/null
+++ b/tools/lint/hooks_clang_format.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import subprocess
+import sys
+from subprocess import CalledProcessError, check_output
+
+here = os.path.dirname(os.path.realpath(__file__))
+topsrcdir = os.path.join(here, os.pardir, os.pardir)
+
+EXTRA_PATHS = (
+ "python/mach",
+ "python/mozbuild",
+ "python/mozversioncontrol",
+ "testing/mozbase/mozfile",
+ "third_party/python/jsmin",
+ "third_party/python/six",
+)
+sys.path[:0] = [os.path.join(topsrcdir, p) for p in EXTRA_PATHS]
+
+from mozversioncontrol import InvalidRepoPath, get_repository_object
+
+
+def run_clang_format(hooktype, changedFiles):
+ try:
+ vcs = get_repository_object(topsrcdir)
+ except InvalidRepoPath:
+ return
+
+ if not changedFiles:
+ # No files have been touched
+ return
+
+ # We have also a copy of this list in:
+ # python/mozbuild/mozbuild/mach_commands.py
+ # version-control-tools/hgext/clang-format/__init__.py
+ # release-services/src/staticanalysis/bot/static_analysis_bot/config.py
+ # Too heavy to import the full class just for this variable
+ extensions = (".cpp", ".c", ".cc", ".h", ".m", ".mm")
+ path_list = []
+ for filename in sorted(changedFiles):
+ # Ignore files unsupported in clang-format
+ if filename.endswith(extensions):
+ path_list.append(filename)
+
+ if not path_list:
+ # No files have been touched
+ return
+
+ arguments = ["clang-format", "-p"] + path_list
+ # On windows we need this to call the command in a shell, see Bug 1511594
+ if os.name == "nt":
+ clang_format_cmd = [sys.executable, "mach"] + arguments
+ else:
+ clang_format_cmd = [os.path.join(topsrcdir, "mach")] + arguments
+ if "commit" in hooktype:
+ # don't prevent commits, just display the clang-format results
+ subprocess.call(clang_format_cmd)
+
+ vcs.add_remove_files(*path_list)
+
+ return False
+ print("warning: '{}' is not a valid clang-format hooktype".format(hooktype))
+ return False
+
+
+def hg(ui, repo, node, **kwargs):
+ print(
+ "warning: this hook has been deprecated. Please use the hg extension instead.\n"
+ "please add 'clang-format = ~/.mozbuild/version-control-tools/hgext/clang-format'"
+ " to hgrc\n"
+ "Or run 'mach bootstrap'"
+ )
+ return False
+
+
+def git():
+ hooktype = os.path.basename(__file__)
+ if hooktype == "hooks_clang_format.py":
+ hooktype = "pre-push"
+
+ try:
+ changedFiles = check_output(
+ ["git", "diff", "--staged", "--diff-filter=d", "--name-only", "HEAD"],
+ text=True,
+ ).split()
+ # TODO we should detect if we are in a "add -p" mode and show a warning
+ return run_clang_format(hooktype, changedFiles)
+
+ except CalledProcessError:
+ print("Command to retrieve local files failed")
+ return 1
+
+
+if __name__ == "__main__":
+ sys.exit(git())