From f279ed2efbe9d491971398f55cef1bc8ef4495d0 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 13 Feb 2024 18:14:41 -0600 Subject: [PATCH] Add pre-commit hook for clang format --- .clang-format | 28 +++++++++++++ .pre-commit-config.yaml | 9 ++++ contrib/reformat-code.py | 90 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 .clang-format create mode 100755 contrib/reformat-code.py diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..76c403d --- /dev/null +++ b/.clang-format @@ -0,0 +1,28 @@ +# Format Style Options - Created with Clang Power Tools +--- +BasedOnStyle: Mozilla +AlignAfterOpenBracket: DontAlign +AlignConsecutiveMacros: AcrossEmptyLines +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveDeclarations: Consecutive +AlignEscapedNewlines: Left +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Attach +BreakStringLiterals: false +ColumnLimit: 150 +DerivePointerAlignment: true +ExperimentalAutoDetectBinPacking: true +IndentCaseLabels: false +IndentCaseBlocks: true +MaxEmptyLinesToKeep: 2 +SpaceAfterCStyleCast: true +SpaceBeforeParens: Always +SpaceAroundPointerQualifiers: Before +UseTab: Always +... diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b44d998..541e81d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,6 +10,8 @@ repos: - id: check-executables-have-shebangs - id: forbid-new-submodules - id: check-yaml + - id: check-yaml + exclude: '.clang-format' - id: check-json - id: pretty-format-json args: ['--no-sort-keys'] @@ -37,3 +39,10 @@ repos: hooks: - id: markdownlint args: ['--fix'] +- repo: local + hooks: + - id: clang-format + name: clang-format + language: script + entry: ./contrib/reformat-code.py + types: [c] diff --git a/contrib/reformat-code.py b/contrib/reformat-code.py new file mode 100755 index 0000000..ad213c4 --- /dev/null +++ b/contrib/reformat-code.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2017 Dell Inc. +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +import os +import sys +import subprocess +import argparse + +CLANG_DIFF_FORMATTERS = [ + "clang-format-diff-11", + "clang-format-diff-13", + "clang-format-diff", +] + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Reformat C code to match project style", + epilog="Call with no argument to reformat uncommitted code.", + ) + parser.add_argument( + "commit", nargs="*", default="", help="Reformat all changes since this commit" + ) + parser.add_argument( + "--debug", action="store_true", help="Display all launched commands" + ) + return parser.parse_args() + + +def select_clang_version(formatters): + for formatter in formatters: + try: + ret = subprocess.check_call( + [formatter, "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + if ret == 0: + return formatter + except FileNotFoundError: + continue + print("No clang formatter installed") + sys.exit(1) + + +## Entry Point ## +if __name__ == "__main__": + args = parse_args() + base = os.getenv("GITHUB_BASE_REF") + if base: + base = f"origin/{base}" + else: + if args.commit: + base = args.commit[0] + else: + base = "HEAD" + cmd = ["git", "describe", base] + if args.debug: + print(cmd) + ret = subprocess.run(cmd, capture_output=True) + if ret.returncode: + if args.debug: + print(ret.stderr) + base = "HEAD" + print(f"Reformatting code against {base}") + formatter = select_clang_version(CLANG_DIFF_FORMATTERS) + cmd = ["git", "diff", "-U0", base] + if args.debug: + print(cmd) + ret = subprocess.run(cmd, capture_output=True, text=True) + if ret.returncode: + print(f"Failed to run {cmd}\n{ret.stderr.strip()}") + sys.exit(1) + cmd = [formatter, "-regex", "^.*\\.(c|h|proto)$", "-p1"] + if args.debug: + print(cmd) + ret = subprocess.run(cmd, input=ret.stdout, capture_output=True, text=True) + if ret.returncode: + print(f"Failed to run {cmd}\n{ret.stderr.strip()}") + sys.exit(1) + cmd = ["patch", "-p0"] + if args.debug: + print(cmd) + ret = subprocess.run(cmd, input=ret.stdout, capture_output=True, text=True) + if ret.returncode: + print(f"Failed to run {cmd}\n{ret.stderr.strip()}") + sys.exit(1) + sys.exit(0)