diff --git a/CMakeLists.txt b/CMakeLists.txt index 0510cb2..d857aa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) add_subdirectory(src) if(CNTGS_BUILD_TESTS) + include("${CMAKE_CURRENT_LIST_DIR}/cmake/CntgsInstallGitHooks.cmake") find_package(doctest REQUIRED) enable_testing() include(doctest) diff --git a/cmake/CntgsGitHooksInstaller.cmake b/cmake/CntgsGitHooksInstaller.cmake new file mode 100644 index 0000000..b78b559 --- /dev/null +++ b/cmake/CntgsGitHooksInstaller.cmake @@ -0,0 +1,22 @@ +# Copyright 2024 Dennis Hezel +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +file( + COPY "${GIT_HOOKS_SOURCE_DIR}/pre-commit" "${GIT_HOOKS_SOURCE_DIR}/CntgsPreCommit.cmake" + DESTINATION "${GIT_HOOKS_TARGET_DIR}" + FILE_PERMISSIONS + OWNER_READ + GROUP_READ + WORLD_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_EXECUTE + WORLD_EXECUTE) diff --git a/cmake/CntgsInstallGitHooks.cmake b/cmake/CntgsInstallGitHooks.cmake new file mode 100644 index 0000000..5b083d9 --- /dev/null +++ b/cmake/CntgsInstallGitHooks.cmake @@ -0,0 +1,63 @@ +# Copyright 2024 Dennis Hezel +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +find_package(Git) + +function(cntgs_create_init_git_hooks_target) + if(TARGET cntgs-init-git-hooks) + return() + endif() + + set(CNTGS_GIT_HOOKS_TARGET_DIR "${CMAKE_SOURCE_DIR}/.git/hooks") + set(CNTGS_GIT_HOOKS_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/git-hooks/") + + if(NOT EXISTS "${CNTGS_GIT_HOOKS_TARGET_DIR}/pre-commit" OR NOT EXISTS + "${CNTGS_GIT_HOOKS_TARGET_DIR}/CntgsPreCommit.cmake") + message( + AUTHOR_WARNING + "Initialize clang-format and cmake-format pre-commit hooks by building the CMake target cntgs-init-git-hooks." + ) + endif() + + find_program(CNTGS_CMAKE_FORMAT_PROGRAM cmake-format) + find_program(CNTGS_CLANG_FORMAT_PROGRAM clang-format) + + if(NOT CNTGS_CMAKE_FORMAT_PROGRAM OR NOT CNTGS_CLANG_FORMAT_PROGRAM) + message( + AUTHOR_WARNING + "Cannot create init-git-hooks target with\ncmake-format: ${CNTGS_CMAKE_FORMAT_PROGRAM}\nclang-format: ${CNTGS_CLANG_FORMAT_PROGRAM}" + ) + return() + endif() + + set(CNTGS_INIT_GIT_HOOKS_SOURCES "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/hooks/pre-commit.in" + "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/hooks/CntgsPreCommit.cmake.in") + configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/hooks/pre-commit.in" "${CNTGS_GIT_HOOKS_SOURCE_DIR}/pre-commit" + @ONLY NEWLINE_STYLE UNIX) + configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/hooks/CntgsPreCommit.cmake.in" + "${CNTGS_GIT_HOOKS_SOURCE_DIR}/CntgsPreCommit.cmake" @ONLY NEWLINE_STYLE UNIX) + + set(_cntgs_command_arguments + "-DGIT_HOOKS_TARGET_DIR=${CNTGS_GIT_HOOKS_TARGET_DIR}" "-DGIT_HOOKS_SOURCE_DIR=${CNTGS_GIT_HOOKS_SOURCE_DIR}" + -P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CntgsGitHooksInstaller.cmake") + string(REPLACE ";" " " _cntgs_pretty_command_arguments "${_cntgs_command_arguments}") + add_custom_target( + cntgs-init-git-hooks + DEPENDS ${CNTGS_INIT_GIT_HOOKS_SOURCES} + SOURCES ${CNTGS_INIT_GIT_HOOKS_SOURCES} + COMMAND ${CMAKE_COMMAND} ${_cntgs_command_arguments} + COMMENT "cmake ${_cntgs_pretty_command_arguments}" + VERBATIM) +endfunction() + +if(GIT_FOUND) + cntgs_create_init_git_hooks_target() +endif() diff --git a/cmake/hooks/CntgsPreCommit.cmake.in b/cmake/hooks/CntgsPreCommit.cmake.in new file mode 100644 index 0000000..6ffa7d9 --- /dev/null +++ b/cmake/hooks/CntgsPreCommit.cmake.in @@ -0,0 +1,45 @@ +# Copyright 2024 Dennis Hezel +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Do not ignore empty list items +cmake_policy(SET CMP0007 NEW) + +execute_process( + COMMAND "@GIT_EXECUTABLE@" "diff-index" "--cached" "--name-only" "--diff-filter=ACMRT" "HEAD" + OUTPUT_VARIABLE _git_output + WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@") + +string(REPLACE "\r" "" _git_output_no_carriage "${_git_output}") +string(REPLACE "\n" ";" _git_output_list "${_git_output_no_carriage}") +list(REMOVE_ITEM _git_output_list "") + +# process CMake files +foreach(_git_out IN LISTS _git_output_list) + string(REGEX MATCHALL ".*\\.cmake\\.in\$|.*\\.cmake\$|.*CMakeLists.txt\$" _file "${_git_out}") + + if(NOT "${_file}" STREQUAL "") + execute_process(COMMAND "@CNTGS_CMAKE_FORMAT_PROGRAM@" "-i" "${_file}" WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@") + + execute_process(COMMAND "@GIT_EXECUTABLE@" "add" "${_file}" WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@") + endif() +endforeach() + +# process cpp files +foreach(_git_out IN LISTS _git_output_list) + string(REGEX MATCHALL ".*\\.hpp\$|.*\\.cpp\$|.*\\.h\$|.*\\.c\$" _file "${_git_out}") + + if(NOT "${_file}" STREQUAL "") + execute_process(COMMAND "@CNTGS_CLANG_FORMAT_PROGRAM@" "-i" "-style=file" "${_file}" + WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@") + + execute_process(COMMAND "@GIT_EXECUTABLE@" "add" "${_file}" WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@") + endif() +endforeach() diff --git a/cmake/hooks/pre-commit.in b/cmake/hooks/pre-commit.in new file mode 100644 index 0000000..89b0905 --- /dev/null +++ b/cmake/hooks/pre-commit.in @@ -0,0 +1,3 @@ +#!/bin/bash + +"@CMAKE_COMMAND@" -P "@CNTGS_GIT_HOOKS_TARGET_DIR@/CntgsPreCommit.cmake" \ No newline at end of file