2018-03-06 19:53:37 +01:00
#!/usr/bin/env bash
2017-02-12 00:51:14 +01:00
2017-09-02 21:19:06 +07:00
# git pre-commit hook that runs a clang-format stylecheck.
2017-02-12 00:51:14 +01:00
# Features:
# - abort commit when commit does not comply with the style guidelines
# - create a patch of the proposed style changes
# Modifications for clang-format by rene.milk@wwu.de
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
# Some quality of life modifications made for Godot Engine.
##################################################################
# SETTINGS
2020-03-30 08:55:21 +02:00
# Set path to clang-format binary.
2020-04-24 20:11:53 +03:00
CLANG_FORMAT = ` which clang-format 2>/dev/null`
2017-02-12 00:51:14 +01:00
# Remove any older patches from previous commits. Set to true or false.
DELETE_OLD_PATCHES = false
# Only parse files with the extensions in FILE_EXTS. Set to true or false.
# If false every changed file in the commit will be parsed with clang-format.
# If true only files matching one of the extensions are parsed with clang-format.
PARSE_EXTS = true
# File types to parse. Only effective when PARSE_EXTS is true.
2018-10-02 16:10:33 +02:00
FILE_EXTS = ".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl"
2017-02-12 00:51:14 +01:00
# Use pygmentize instead of cat to parse diff with highlighting.
# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
2020-04-24 20:11:53 +03:00
PYGMENTIZE = ` which pygmentize 2>/dev/null`
2020-03-30 09:03:38 +02:00
if [ ! -z " $PYGMENTIZE " ] ; then
READER = "pygmentize -l diff"
else
READER = cat
fi
2017-02-12 00:51:14 +01:00
2020-04-14 16:23:15 +03:00
# Path to zenity
2020-04-24 20:11:53 +03:00
ZENITY = ` which zenity 2>/dev/null`
2020-04-14 16:23:15 +03:00
# Path to xmessage
2020-04-24 20:11:53 +03:00
XMSG = ` which xmessage 2>/dev/null`
2020-04-14 16:23:15 +03:00
# Path to powershell (Windows only)
2020-04-24 20:11:53 +03:00
PWSH = ` which powershell 2>/dev/null`
2020-04-14 16:23:15 +03:00
2017-02-12 00:51:14 +01:00
##################################################################
# There should be no need to change anything below this line.
. " $( dirname -- " $0 " ) /canonicalize_filename.sh "
# exit on error
set -e
# check whether the given file matches any of the set extensions
matches_extension( ) {
local filename = $( basename " $1 " )
local extension = " . ${ filename ##*. } "
local ext
for ext in $FILE_EXTS ; do [ [ " $ext " = = " $extension " ] ] && return 0; done
return 1
}
# necessary check for initial commit
if git rev-parse --verify HEAD >/dev/null 2>& 1 ; then
against = HEAD
else
# Initial commit: diff against an empty tree object
against = 4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
2021-01-12 21:39:40 +01:00
# To get consistent formatting, we recommend contributors to use the same
# clang-format version as CI.
2021-10-24 23:48:21 +02:00
RECOMMENDED_CLANG_FORMAT_MAJOR_MIN = "12"
2022-05-05 13:39:28 +02:00
RECOMMENDED_CLANG_FORMAT_MAJOR_MAX = "14"
2021-01-12 21:39:40 +01:00
2017-02-12 00:51:14 +01:00
if [ ! -x " $CLANG_FORMAT " ] ; then
2021-10-22 20:39:50 +02:00
message = " Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX . "
2021-01-12 21:39:40 +01:00
2020-04-14 16:23:15 +03:00
if [ ! -t 1 ] ; then
if [ -x " $ZENITY " ] ; then
2021-01-12 21:39:40 +01:00
$ZENITY --error --title= "Error" --text= " $message "
2020-04-14 16:23:15 +03:00
exit 1
elif [ -x " $XMSG " ] ; then
2021-01-12 21:39:40 +01:00
$XMSG -center -title "Error" " $message "
2020-04-14 16:23:15 +03:00
exit 1
elif [ \( \( " $OSTYPE " = "msys" \) -o \( " $OSTYPE " = "win32" \) \) -a \( -x " $PWSH " \) ] ; then
2022-08-30 11:17:04 +02:00
winmessage = " $( canonicalize_filename " $( dirname -- " $0 " ) /winmessage.ps1 " ) "
2021-01-12 21:39:40 +01:00
$PWSH -noprofile -executionpolicy bypass -file " $winmessage " -center -title "Error" --text " $message "
2020-04-14 16:23:15 +03:00
exit 1
fi
fi
2021-01-12 21:39:40 +01:00
printf " $message \n "
2017-02-12 00:51:14 +01:00
printf " Set the correct path in $( canonicalize_filename " $0 " ) .\n "
exit 1
fi
2021-05-10 15:12:57 +02:00
# The returned string can be inconsistent depending on where clang-format comes from.
# Example output strings reported by `clang-format --version`:
# - Ubuntu: "Ubuntu clang-format version 11.0.0-2"
# - Fedora: "clang-format version 11.0.0 (Fedora 11.0.0-2.fc33)"
CLANG_FORMAT_VERSION = " $( clang-format --version | sed "s/[^0-9\.]*\([0-9\.]*\).*/\1/" ) "
CLANG_FORMAT_MAJOR = " $( echo " $CLANG_FORMAT_VERSION " | cut -d. -f1) "
2021-01-12 21:39:40 +01:00
2021-06-07 16:59:52 +02:00
if [ [ " $CLANG_FORMAT_MAJOR " -lt " $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN " || " $CLANG_FORMAT_MAJOR " -gt " $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX " ] ] ; then
2021-10-22 20:39:50 +02:00
echo " Warning: Your clang-format binary is the wrong version ( $CLANG_FORMAT_VERSION , expected between $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN and $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX ). "
2021-01-12 21:39:40 +01:00
echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly."
fi
2017-02-12 00:51:14 +01:00
# create a random filename to store our generated patch
prefix = "pre-commit-clang-format"
suffix = " $( date +%s) "
patch = " /tmp/ $prefix - $suffix .patch "
# clean up any older clang-format patches
$DELETE_OLD_PATCHES && rm -f /tmp/$prefix *.patch
# create one patch containing all changes to the files
git diff-index --cached --diff-filter= ACMR --name-only $against -- | while read file;
do
2017-04-09 15:02:09 +02:00
# ignore thirdparty files
if grep -q "thirdparty" <<< $file ; then
continue ;
fi
2019-09-02 17:31:51 -07:00
if grep -q "platform/android/java/lib/src/com" <<< $file ; then
2019-08-27 14:33:41 +02:00
continue ;
fi
2021-02-17 11:28:27 +01:00
if grep -q "\-so_wrap." <<< $file ; then
continue ;
fi
2017-04-09 15:02:09 +02:00
2017-02-12 00:51:14 +01:00
# ignore file if we do check for file extensions and the file
# does not match any of the extensions specified in $FILE_EXTS
if $PARSE_EXTS && ! matches_extension " $file " ; then
continue ;
fi
# clang-format our sourcefile, create a patch with diff and append it to our $patch
# The sed call is necessary to transform the patch from
# --- $file timestamp
# +++ - timestamp
2017-09-02 21:19:06 +07:00
# to both lines working on the same file and having a/ and b/ prefix.
2017-02-12 00:51:14 +01:00
# Else it can not be applied with 'git apply'.
2021-10-24 23:48:21 +02:00
" $CLANG_FORMAT " -style= file " $file " --Wno-error= unknown | \
2017-02-12 00:51:14 +01:00
diff -u " $file " - | \
sed -e "1s|--- |--- a/|" -e " 2s|+++ -|+++ b/ $file | " >> " $patch "
done
# if no patch has been generated all is ok, clean up the file stub and exit
if [ ! -s " $patch " ] ; then
printf "Files in this commit comply with the clang-format rules.\n"
rm -f " $patch "
exit 0
fi
# a patch has been created, notify the user and exit
printf "\nThe following differences were found between the code to commit "
printf "and the clang-format rules:\n\n"
2020-04-14 16:23:15 +03:00
if [ -t 1 ] ; then
$READER " $patch "
printf "\n"
# Allows us to read user input below, assigns stdin to keyboard
exec < /dev/tty
terminal = "1"
else
cat " $patch "
printf "\n"
# Allows non zero zenity/powershell output
set +e
terminal = "0"
fi
2017-02-12 00:51:14 +01:00
while true; do
2020-04-14 16:23:15 +03:00
if [ $terminal = "0" ] ; then
if [ -x " $ZENITY " ] ; then
2022-02-10 12:00:11 +01:00
choice = $( $ZENITY --text-info --filename= " $patch " --width= 800 --height= 600 --title= "Do you want to apply that patch?" --ok-label= "Apply" --cancel-label= "Do not apply" --extra-button= "Apply and stage" )
2020-04-14 16:23:15 +03:00
if [ " $? " = "0" ] ; then
yn = "Y"
else
2022-02-10 12:00:11 +01:00
if [ " $choice " = "Apply and stage" ] ; then
2020-04-14 16:23:15 +03:00
yn = "S"
else
yn = "N"
fi
fi
elif [ -x " $XMSG " ] ; then
$XMSG -file " $patch " -buttons "Apply" :100,"Apply and stage" :200,"Do not apply" :0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
2022-02-10 12:00:11 +01:00
choice = $?
if [ " $choice " = "100" ] ; then
2020-04-14 16:23:15 +03:00
yn = "Y"
2022-02-10 12:00:11 +01:00
elif [ " $choice " = "200" ] ; then
2020-04-14 16:23:15 +03:00
yn = "S"
else
yn = "N"
fi
elif [ \( \( " $OSTYPE " = "msys" \) -o \( " $OSTYPE " = "win32" \) \) -a \( -x " $PWSH " \) ] ; then
2022-08-30 11:17:04 +02:00
winmessage = " $( canonicalize_filename " $( dirname -- " $0 " ) /winmessage.ps1 " ) "
2020-04-14 16:23:15 +03:00
$PWSH -noprofile -executionpolicy bypass -file " $winmessage " -file " $patch " -buttons "Apply" :100,"Apply and stage" :200,"Do not apply" :0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
2022-02-10 12:00:11 +01:00
choice = $?
if [ " $choice " = "100" ] ; then
2020-04-14 16:23:15 +03:00
yn = "Y"
2022-02-10 12:00:11 +01:00
elif [ " $choice " = "200" ] ; then
2020-04-14 16:23:15 +03:00
yn = "S"
else
yn = "N"
fi
else
printf "Error: zenity, xmessage, or powershell executable not found.\n"
exit 1
fi
else
read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn
fi
2017-02-12 00:51:14 +01:00
case $yn in
[ Yy] ) git apply $patch ;
printf "The patch was applied. You can now stage the changes and commit again.\n\n" ;
break
; ;
[ Nn] ) printf " \nYou can apply these changes with:\n git apply $patch \n " ;
printf "(may need to be called from the root directory of your repository)\n" ;
printf "Aborting commit. Apply changes and commit again or skip checking with" ;
printf " --no-verify (not recommended).\n\n" ;
break
; ;
[ Ss] ) git apply $patch ;
git diff-index --cached --diff-filter= ACMR --name-only $against -- | while read file;
do git add $file ;
done
printf "The patch was applied and the changed files staged. You can now commit.\n\n" ;
break
; ;
* ) echo "Please answer yes or no."
; ;
esac
done
exit 1 # we don't commit in any case