2 # Copyright (c) 2015, David Martin. All rights reserved.
3 # Copyright (c) 2017-2022. The SimGrid team. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
8 # * Redistributions of source code must retain the above copyright notice, this
9 # list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright notice,
12 # this list of conditions and the following disclaimer in the documentation
13 # and/or other materials provided with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 # git pre-commit hook that runs a clang-format stylecheck.
27 # - abort commit when commit does not comply with the style guidelines
28 # - create a patch of the proposed style changes
30 # Modifications for clang-format by rene.milk@wwu.de
31 # This file is part of a set of unofficial pre-commit hooks available
33 # Link: https://github.com/githubbrowser/Pre-commit-hooks
35 # Modifications for modern clang formats and other improvements as part of the SimGrid project.
36 # See git logs for the detail of changes.
38 ##################################################################
41 # remove any older patches from previous commits. Set to true or false.
42 DELETE_OLD_PATCHES=true
44 # only parse files with the extensions in FILE_EXTS. Set to true or false.
45 # if false every changed file in the commit will be parsed with clang-format.
46 # if true only files matching one of the extensions are parsed with clang-format.
49 # file types to parse. Only effective when PARSE_EXTS is true.
50 # FILE_EXTS=".c .h .cpp .hpp"
51 FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx"
53 ##################################################################
54 # Potential names for clang-format (debian...)
55 CLANG_FMT_PNAMES=(clang-format clang-format-5.0 clang-format-4.0 clang-format-3.9 clang-format-3.8)
56 CLANG_FMT_CMD="NOT-FOUND"
57 GIT_CLANG_FMT_CMD="NOT-FOUND"
59 # Find which clang-format should be used
60 for name in ${CLANG_FMT_PNAMES[*]}
62 where=$(which ${name} 2> /dev/null)
63 if [ x != "x${where}" ]
65 echo "clang-format found: ${where}"
66 CLANG_FMT_CMD=${where}
71 if [[ "${CLANG_FMT_CMD}" == NOT-FOUND ]]
73 echo "Unable to find clang-format! Please install it:"
74 echo "- debian(-like): apt-get install clang-format[-VERSION]"
75 echo "- arch(-like): pacman -S clang"
80 # Find which git-clang-format should be used
81 for name in ${CLANG_FMT_PNAMES[*]}
83 where=$(which "git-${name}" 2> /dev/null)
84 if [ x != "x${where}" ]
86 echo "git-clang-format found: ${where}"
87 GIT_CLANG_FMT_CMD=${where}
92 if [[ "${GIT_CLANG_FMT_CMD}" == NOT-FOUND ]]
94 echo "Unable to find git-clang-format! Please install it:"
95 echo "- debian(-like): apt-get install clang-format[-VERSION]"
96 echo "- arch(-like): pacman -S clang"
101 # error on unset variable expansion
106 # There should be no need to change anything below this line.
108 # Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
109 canonicalize_filename () {
110 local target_file=${1}
111 local physical_directory=""
114 # Need to restore the working directory after work.
115 pushd $(pwd) > /dev/null
117 cd "$(dirname "${target_file}")"
118 target_file=$(basename ${target_file})
120 # Iterate down a (possible) chain of symlinks
121 while [ -L "${target_file}" ]
123 target_file=$(readlink "${target_file}")
124 cd "$(dirname "${target_file}")"
125 target_file=$(basename "${target_file}")
128 # Compute the canonicalized name by finding the physical path
129 # for the directory we're in and appending the target file.
130 physical_directory=$(pwd -P)
131 result="${physical_directory}"/"${target_file}"
133 # restore the working directory after work.
139 # check whether the given file matches any of the set extensions
140 matches_extension() {
141 local filename=$(basename "${1}")
142 local extension=".${filename##*.}"
145 for ext in ${FILE_EXTS}; do [[ "${ext}" == "${extension}" ]] && return 0; done
150 # necessary check for initial commit
151 if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
154 # Initial commit: diff against an empty tree object
155 against=foobaridonotexist
158 # create a random filename to store our generated patch
159 prefix="pre-commit-clang-format"
161 patch="/tmp/${prefix}-${suffix}.patch"
163 # clean up any older clang-format patches
164 ${DELETE_OLD_PATCHES} && rm -f /tmp/${prefix}*.patch
166 # create one patch containing all changes to the files
167 git diff-index --cached --diff-filter=ACMR --name-only ${against} -- | while read file;
169 # ignore file if we do check for file extensions and the file
170 # does not match any of the extensions specified in $FILE_EXTS
171 if ${PARSE_EXTS} && ! matches_extension "${file}"; then
175 # clang-format our sourcefile, create a patch with diff and append it to our $patch
176 # The sed call is necessary to transform the patch from
177 # --- $file timestamp
179 # to both lines working on the same file and having a a/ and b/ prefix.
180 # Else it can not be applied with 'git apply'.
181 ${GIT_CLANG_FMT_CMD} --binary ${CLANG_FMT_CMD} --diff -q "${file}" \
182 | (grep -v "no modified files to format"||true) \
184 #"${CLANG_FMT_CMD}" -style=file "${file}" | \
185 #diff -u "${file}" - | \
186 #sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/${file}|" >> "${patch}"
189 # if no patch has been generated all is ok, clean up the file stub and exit
190 if [ ! -s "${patch}" ] ; then
191 printf "Files in this commit comply with the clang-format rules.\n"
196 # a patch has been created, notify the user and exit
197 printf "\nThe following differences were found between the code to commit "
198 printf "and the clang-format rules:\n\n"
201 printf "\nYou can apply these changes and read the files with:\n"
202 printf " git apply ${patch} && git apply --cached ${patch}\n"
203 printf "(call this command from the root directory of your repository)\n"
205 printf "Aborting commit. Apply changes and commit again.\n"
206 # printf "Skip checking with: --no-verify (not recommended).\n"