From: Jérémie Galarneau Date: Thu, 12 Dec 2024 19:16:22 +0000 (+0000) Subject: misc: Allow users to override the location of clang-format X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=7126b4cfd2ed781f7f2c737552f9f0d9266a09d2;p=lttng-tools.git misc: Allow users to override the location of clang-format Since the coding imposes a specific version of clang-format (16), the pre-commit hook can fail for reasons out of the contributor's control. Local git config settings are used to allow the user to specify the location of these tools. git config --local hooks.clangFormatPath /path/to/clang-format-16 The settings are retrieved by the script and used if they were specified. Note that we should probably do the same for `black` as they change the formatting from version to version. Right now I feel we imply "use the latest version", but we should probably impose one and update it on a release-to-release basis. Change-Id: Iabb3e3964dc137075474ae4a240f30e0ecf4ec0d Signed-off-by: Jérémie Galarneau --- diff --git a/extras/pre-commit.py b/extras/pre-commit.py index 788ea7205..f7013a73e 100755 --- a/extras/pre-commit.py +++ b/extras/pre-commit.py @@ -13,15 +13,77 @@ import sys import clang.cindex +def get_git_config_value(key, default=None): + """ + Get a Git configuration value from the local repository. + Returns the default value if the key is not set. + """ + try: + value = subprocess.check_output( + ["git", "config", "--local", key], stderr=subprocess.DEVNULL + ).strip() + return value + except subprocess.CalledProcessError: + return default + + +def get_clang_format_version(clang_format_path): + try: + # Run the clang-format --version command + result = subprocess.check_output( + [clang_format_path, "--version"], text=True + ).strip() + + # Use regex to extract the version tuple + match = re.search(r"version (\d+)\.(\d+)\.(\d+)", result) + if match: + # Convert the matched groups to integers and return as a tuple + version_tuple = tuple(map(int, match.groups())) + return version_tuple + else: + logging.error("Failed to extract version from clang-format output.") + return None + except FileNotFoundError: + logging.error( + f"clang-format binary could not be found using {clang_format_path}" + ) + return None + except subprocess.CalledProcessError as e: + logging.error(f"Failed to run clang-format: {e}") + return None + + def clang_format(files): + required_clang_format_major_version = 16 + source_files_re = re.compile(r"^.*(\.cpp|\.hpp|\.c|\.h)$") files = [f for f in files if source_files_re.match(f)] if not files: return "No source files for clang-format check", 0 + # Extract the git config value that overrides the location of clang-format. + # If none can be found, use the sytem's clang-format. + clang_format_path = get_git_config_value("hooks.clangFormatPath", "clang-format") + clang_format_version = get_clang_format_version(clang_format_path) + + if clang_format_version is None: + return "Failed to determine clang-format version", 1 + + cf_major, cf_minor, cf_patch = clang_format_version + if cf_major != required_clang_format_major_version: + return ( + f"Invalid clang-format version: binary `{clang_format_path}` is version {cf_major}.{cf_minor}.{cf_patch}, expected version {required_clang_format_major_version}.y.z", + 1, + ) + logging.debug("Files for clang-format: {}".format(files)) format_process = subprocess.Popen( - ["clang-format", "--dry-run", "-Werror"] + files, + [ + clang_format_path, + "--dry-run", + "-Werror", + ] + + files, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, )