Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of ssh://scm.gforge.inria.fr/gitroot/simgrid/simgrid
[simgrid.git] / tools / git-hooks / clang-format.pre-commit
1 #!/usr/bin/env bash
2 # Copyright (c) 2015, David Martin. All rights reserved.
3 # Copyright (c) 2017-2018. The SimGrid team. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
7 #
8 # * Redistributions of source code must retain the above copyright notice, this
9 #   list of conditions and the following disclaimer.
10 #
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.
14 #
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 an clang-format stylecheck.
26 #  Features:
27 #   - abort commit when commit does not comply with the style guidelines
28 #   - create a patch of the proposed style changes
29
30 # Modifications for clang-format by rene.milk@wwu.de
31 # This file is part of a set of unofficial pre-commit hooks available
32 # at github.
33 # Link:    https://github.com/githubbrowser/Pre-commit-hooks
34
35 # Modifications for modern clang formats and other improvements as part of the SimGrid project.
36 # See git logs for the detail of changes.
37
38 ##################################################################
39 # Settings
40
41 # remove any older patches from previous commits. Set to true or false.
42 DELETE_OLD_PATCHES=true
43
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.
47 PARSE_EXTS=true
48
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"
52
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"
58
59 # Find which clang-format should be used
60 for name in ${CLANG_FMT_PNAMES[*]}
61 do
62     where=$(which ${name} 2> /dev/null)
63     if [ x != "x${where}" ]
64     then
65         echo "clang-format found: ${where}"
66         CLANG_FMT_CMD=${where}
67         break
68     fi
69 done
70
71 if [[ "${CLANG_FMT_CMD}" == NOT-FOUND ]]
72 then
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"
76     echo "- ..."
77     exit 1
78 fi
79
80 # Find which git-clang-format should be used
81 for name in ${CLANG_FMT_PNAMES[*]}
82 do
83     where=$(which "git-${name}" 2> /dev/null)
84     if [ x != "x${where}" ]
85     then
86         echo "git-clang-format found: ${where}"
87         GIT_CLANG_FMT_CMD=${where}
88         break
89     fi
90 done
91
92 if [[ "${GIT_CLANG_FMT_CMD}" == NOT-FOUND ]]
93 then
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"
97     echo "- ..."
98     exit 1
99 fi
100
101 # error on unset variable expansion
102 set -u
103 # exit on error
104 set -e
105
106 # There should be no need to change anything below this line.
107
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=""
112     local result=""
113
114     # Need to restore the working directory after work.
115     pushd $(pwd) > /dev/null
116
117     cd "$(dirname "${target_file}")"
118     target_file=$(basename ${target_file})
119
120     # Iterate down a (possible) chain of symlinks
121     while [ -L "${target_file}" ]
122     do
123         target_file=$(readlink "${target_file}")
124         cd "$(dirname "${target_file}")"
125         target_file=$(basename "${target_file}")
126     done
127
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}"
132
133     # restore the working directory after work.
134     popd > /dev/null
135
136     echo "${result}"
137 }
138
139 # check whether the given file matches any of the set extensions
140 matches_extension() {
141     local filename=$(basename "${1}")
142     local extension=".${filename##*.}"
143     local ext
144
145     for ext in ${FILE_EXTS}; do [[ "${ext}" == "${extension}" ]] && return 0; done
146
147     return 1
148 }
149
150 # necessary check for initial commit
151 if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
152     against=HEAD
153 else
154     # Initial commit: diff against an empty tree object
155     against=foobaridonotexist
156 fi
157
158 # create a random filename to store our generated patch
159 prefix="pre-commit-clang-format"
160 suffix="$(date +%s)"
161 patch="/tmp/${prefix}-${suffix}.patch"
162
163 # clean up any older clang-format patches
164 ${DELETE_OLD_PATCHES} && rm -f /tmp/${prefix}*.patch
165
166 # create one patch containing all changes to the files
167 git diff-index --cached --diff-filter=ACMR --name-only ${against} -- | while read file;
168 do
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
172         continue;
173     fi
174
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
178     #    +++ - 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) \
183       >> "${patch}"
184     #"${CLANG_FMT_CMD}" -style=file "${file}" | \
185         #diff -u "${file}" - | \
186         #sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/${file}|" >> "${patch}"
187 done
188
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"
192     rm -f "${patch}"
193     exit 0
194 fi
195
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"
199 cat "${patch}"
200
201 printf "\nYou can apply these changes and readd 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"
204 printf "\n\n\n"
205 printf "Aborting commit. Apply changes and commit again.\n"
206 # printf "Skip checking with: --no-verify (not recommended).\n"
207
208 exit 1