Skip to content

Commit

Permalink
build: add clang format (#243)
Browse files Browse the repository at this point in the history
* tools: adds run-clang-format.sh

* tools: adds new line at the end of run-clang-format.sh

* tools: use BasedOnStyle in .clang-format

* cmake|tools: adding formatting scripts

* cmake: adds empty line at the end

* cmake: throwing error when code cheeking fails

* .github: adds workflow for lint and format check

* cmake: change variable IS_CI to be LINT_AND_FORMAT_CHECK

* switch to ubuntu-latest + consider .clang-format on clang-format call

* tools: adds missing -style=file to lint_and_format.py

* cmake: refactor clang-format.cmake

* .github: fix system name for workflow lint_and_format_check.yml

* clang-format: fix clang-format version

* .github: adds missing 'sudo'

* .github: adds missing 'sudo'

* .github: adds missing 'sudo'

* .github: replace existing clang-format with the right version

* .github: adds missing newline to lint_and_format_check.yml
  • Loading branch information
miguelteixeiraa committed Mar 22, 2023
1 parent 307ba9e commit fd91974
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 0 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
BasedOnStyle: Google
32 changes: 32 additions & 0 deletions .github/workflows/lint_and_format_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Lint and Format Check (Ubuntu Latest)

on:
push:
branches:
- "*"
pull_request:
branches:
- "*"

permissions:
contents: read

jobs:
ubuntu-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install ICU
run: sudo apt-get install -y libicu-dev pkg-config

- name: Install clang-format
run: |
sudo apt update && sudo apt install clang-format-15 -y
sudo ln -sf /usr/bin/clang-format-15 /usr/bin/clang-format
- name: Build with Lint and Format Check
run: |
cmake -B build && cmake --build build
env:
CXX: clang++-14
LINT_AND_FORMAT_CHECK: true
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ set(ADA_LIB_SOVERSION "1" CACHE STRING "ada library soversion")

include(GNUInstallDirs)

include (cmake/clang-format.cmake)

include(CTest)
include(cmake/ada-flags.cmake)

Expand Down
37 changes: 37 additions & 0 deletions cmake/clang-format.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
find_program(PYTHON_EXECUTABLE python3 python)

if(NOT PYTHON_EXECUTABLE)
message(WARNING "Python not found. Skipping lint and format checks.")
else()
set(LINT_AND_FORMAT_SCRIPT_PATH ${CMAKE_SOURCE_DIR}/tools/lint_and_format.py)

# Should run on CI
if(DEFINED ENV{LINT_AND_FORMAT_CHECK})
message(STATUS "Checking code with clang-format...")
execute_process(
COMMAND ${PYTHON_EXECUTABLE} ${LINT_AND_FORMAT_SCRIPT_PATH} check
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE clang_check_result
)

if(clang_check_result)
message(FATAL_ERROR "Clang-format check failed with error code ${clang_check_result}")
endif()

else()
if(DEFINED ENV{FORMAT_ENABLED})
message(STATUS "Formatting code with clang-format...")
execute_process(
COMMAND ${PYTHON_EXECUTABLE} ${LINT_AND_FORMAT_SCRIPT_PATH} format
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE clang_format_result
)

if(clang_format_result)
message(FATAL_ERROR "Clang-format format failed with error code ${clang_check_result}")
endif()
else()
message(STATUS "Code formatting is not enabled.")
endif()
endif()
endif()
96 changes: 96 additions & 0 deletions tools/lint_and_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import os
import sys
import subprocess
import argparse

parser = argparse.ArgumentParser(
description="Format C/C++ code using clang-format."
)
parser.add_argument(
"operation",
choices=["check", "format"],
help='Operation to perform: "check" to check for formatting errors, or "format" to fix formatting errors.',
)
parser.add_argument(
"--extensions",
"-e",
nargs="+",
default=[".cpp", ".cc", ".c", ".h", ".hpp"],
help="List of file extensions to check or format (default: .cpp .cc .c .h .hpp)",
)
parser.add_argument(
"--clangf-version",
"-v",
default="15",
help="Clang-format version",
)

args = parser.parse_args()


ROOT_DIR = (
subprocess.check_output(["git", "rev-parse", "--show-toplevel"])
.strip()
.decode("utf-8")
)

exclude_dirs = ('.git', '.cache', 'build', 'dependencies', 'docs')
file_list = [os.path.join(dirpath, filename)
for dirpath, _, filenames in os.walk(ROOT_DIR)
for filename in filenames
if any(filename.endswith(ext) for ext in args.extensions)
and not any(exclude_dir in dirpath for exclude_dir in exclude_dirs)]


def clang_check(file_path: str) -> None:
try:
diff_output = subprocess.check_output(
["clang-format", "-output-replacements-xml", "-style=file", file_path], stderr=subprocess.STDOUT,
)
if b"<replacement " in diff_output:
print(f"Error: {file_path} needs formatting")
sys.exit(1)

except subprocess.CalledProcessError as error:
print(f'Error: {error.output.decode("utf-8")}')
sys.exit(1)


def clang_format(file_path: str) -> None:
diff_output = subprocess.check_output(
["clang-format", "-output-replacements-xml", "-style=file", file_path], stderr=subprocess.STDOUT,
)

if b"<replacement " in diff_output:
print(f"Formatting: {file_path}")
try:
subprocess.check_call(["clang-format", "-i", "-style=file", file_path])
except subprocess.CalledProcessError as error:
print(f'Error: {error.output.decode("utf-8")}')
sys.exit(1)


def clang_format_verify():
version_output = subprocess.check_output(
["clang-format", "--version"], stderr=subprocess.STDOUT,
).decode("utf-8").split(" ")
if "version" in version_output :
return version_output[version_output.index("version") + 1]

return ""


clang_format_version = clang_format_verify()

if args.clangf_version not in clang_format_version:
print(f'Wrong clang-format version. Expected: {args.clangf_version}, Given: {clang_format_version}')
sys.exit(1)

for file_path in file_list:
if args.operation == "check":
clang_check(file_path)
elif args.operation == "format":
clang_format(file_path)


print("Done!")

0 comments on commit fd91974

Please sign in to comment.