--- /dev/null
+#!/usr/bin/env python3
+
+import argparse
+import os
+import shutil
+import sys
+import subprocess as sp
+
+"""
+Apply `clang-format` on every C++ source file
+and `black` on every Python file.
+
+C++ files are fetched based on their file extension (see CPP_EXTENSIONS).
+"""
+
+CPP_EXTENSIONS = (".h", ".cpp", ".cxx", ".hxx")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--dry",
+ help="dry run and return non-zero error code if some reformatting has to be done",
+ action="store_true",
+ )
+ parser.add_argument(
+ "--verbose",
+ "-v",
+ help="print list of formated files",
+ action="store_true",
+ )
+ parser.add_argument(
+ "--clang-format-bin",
+ help="explicitly provide a clang-format executable (e.g. '--clang-format-bin clang-format-12')",
+ dest="clang_format_bin",
+ default="clang-format",
+ )
+ parser.add_argument(
+ "--black-bin",
+ help="explicitly provide a black executable (e.g. '--black-bin <path-to-black>)",
+ dest="black_bin",
+ default="black",
+ )
+ args = parser.parse_args()
+
+ def find_bin(exe: str) -> bool:
+ result = shutil.which(exe)
+ if not result:
+ print(f"ERROR: the binary '{exe}' cannot be found.")
+ return False
+ else:
+ print(f"Found '{exe}' at '{result}'")
+ return True
+
+ if not (find_bin(args.black_bin) and find_bin(args.clang_format_bin)):
+ print(f"Missing binaries must be installed. Abort.")
+ sys.exit(1)
+
+ # collect paths of all the C++ source files
+ # in the current directory and its subdirectories
+ cpp_files: list[str] = []
+ for path, dirs, files in os.walk(os.getcwd()):
+ cpp_files += [
+ os.path.join(path, file)
+ for file in files
+ if file.endswith(CPP_EXTENSIONS)
+ ]
+
+ clang_format_options: list[str] = ["-style=file", "-i"]
+ black_options: list[str] = []
+ if args.dry:
+ clang_format_options += ["--dry-run", "-Werror"]
+ black_options += ["--diff"]
+ if args.verbose:
+ clang_format_options += ["--verbose"]
+ else:
+ black_options += ["--quiet"]
+
+ if cpp_files:
+ sp.run(
+ args=[args.clang_format_bin] + clang_format_options + cpp_files,
+ )
+
+ sp.run(
+ args=[args.black_bin] + black_options + [os.getcwd()] ,
+ )