Skip to content
This repository was archived by the owner on Dec 10, 2022. It is now read-only.

Commit 0d65c50

Browse files
committed
add pre-commit hook + .clang-format
1 parent b1ff1b2 commit 0d65c50

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed

.clang-format

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
Language: Cpp
3+
BasedOnStyle: Google
4+
IndentWidth: 4
5+
# don't indent public, private and protected
6+
AccessModifierOffset: -4
7+
BreakBeforeBraces: Allman
8+
# respect user choice for line breaking
9+
ColumnLimit: 0
10+
BreakConstructorInitializersBeforeComma: true
11+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
12+
SortIncludes: false
13+
DerivePointerAlignment: false
14+
PointerAlignment: Left
15+
NamespaceIndentation: All
16+
SortIncludes: true
17+
18+
IncludeCategories:
19+
- Regex: '<[^./]+>' # c++ stl includes
20+
Priority: 1
21+
- Regex: '(<|")[^/]+(>|")' # includes without path
22+
Priority: 2
23+
- Regex: '(<|").+(>|")' # includes with path
24+
Priority: 3
25+
...
26+

create_git_hooks.sh

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
GIT_REPO_DIR=$(git rev-parse --show-toplevel)
4+
5+
cd "$GIT_REPO_DIR"
6+
7+
for hook in hooks/*
8+
do
9+
SYMLINK_HOOK=.git/$hook
10+
if [ -f $hook ] && [ ! -e "$SYMLINK_HOOK" ] && [ ! -L "$SYMLINK_HOOK" ]
11+
then
12+
ln -v -s "../../$hook" .git/hooks/
13+
fi
14+
done

hooks/pre-commit

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#!/usr/bin/env bash
2+
3+
# git pre-commit hook that runs an clang-format stylecheck.
4+
# Features:
5+
# - abort commit when commit does not comply with the style guidelines
6+
# - create a patch of the proposed style changes
7+
8+
# modifications for clang-format by [email protected]
9+
# This file is part of a set of unofficial pre-commit hooks available
10+
# at github.
11+
# Link: https://github.com/githubbrowser/Pre-commit-hooks
12+
# Contact: David Martin, [email protected]
13+
14+
15+
##################################################################
16+
# SETTINGS
17+
# set path to clang-format binary
18+
CLANG_FORMAT_BIN=$(command -v clang-format)
19+
20+
# remove any older patches from previous commits. Set to true or false.
21+
# DELETE_OLD_PATCHES=false
22+
DELETE_OLD_PATCHES=false
23+
24+
# only parse files with the extensions in FILE_EXTS. Set to true or false.
25+
# if false every changed file in the commit will be parsed with clang-format.
26+
# if true only files matching one of the extensions are parsed with clang-format.
27+
# PARSE_EXTS=true
28+
PARSE_EXTS=true
29+
30+
# file types to parse. Only effective when PARSE_EXTS is true.
31+
# FILE_EXTS=".c .h .cpp .hpp"
32+
FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m"
33+
34+
##################################################################
35+
# bash error codes
36+
EXIT_ERROR=1
37+
EXIT_SUCCESS=0
38+
39+
# Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
40+
canonicalize_filename () {
41+
local target_file=$1
42+
local physical_directory=""
43+
local result=""
44+
45+
# Need to restore the working directory after work.
46+
pushd `pwd` > /dev/null
47+
48+
cd "$(dirname "$target_file")"
49+
target_file=`basename $target_file`
50+
51+
# Iterate down a (possible) chain of symlinks
52+
while [ -L "$target_file" ]
53+
do
54+
target_file=$(readlink "$target_file")
55+
cd "$(dirname "$target_file")"
56+
target_file=$(basename "$target_file")
57+
done
58+
59+
# Compute the canonicalized name by finding the physical path
60+
# for the directory we're in and appending the target file.
61+
physical_directory=`pwd -P`
62+
result="$physical_directory"/"$target_file"
63+
64+
# restore the working directory after work.
65+
popd > /dev/null
66+
67+
echo "$result"
68+
}
69+
70+
# exit on error
71+
set -e
72+
73+
# check whether the given file matches any of the set extensions
74+
matches_extension() {
75+
local filename=$(basename "$1")
76+
local extension=".${filename##*.}"
77+
local ext
78+
79+
for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
80+
81+
return 1
82+
}
83+
84+
# necessary check for initial commit
85+
if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
86+
against=HEAD
87+
else
88+
# Initial commit: diff against an empty tree object
89+
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
90+
fi
91+
92+
if [ ! -x "$CLANG_FORMAT_BIN" ] ; then
93+
printf "Error: clang-format executable not found.\n"
94+
printf "Set the correct path in $(canonicalize_filename "$0").\n"
95+
exit $EXIT_ERROR
96+
fi
97+
98+
# create a random filename to store our generated patch
99+
prefix="pre-commit-clang-format"
100+
suffix="$(date +%s)"
101+
patch="/tmp/$prefix-$suffix.patch"
102+
103+
# clean up any older clang-format patches
104+
$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
105+
106+
# create one patch containing all changes to the files
107+
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
108+
do
109+
# ignore file if we do check for file extensions and the file
110+
# does not match any of the extensions specified in $FILE_EXTS
111+
if $PARSE_EXTS && ! matches_extension "$file"; then
112+
continue;
113+
fi
114+
115+
116+
# abort commit if staged file differs from workspace file
117+
# need to unset bash error checking, because diff returns 1 if different
118+
set +e
119+
git show :"$file" | diff -u "$file" - >/dev/null
120+
diff_return_code=$?
121+
set -e
122+
if [ $diff_return_code -eq 1 ];then
123+
echo "Error: Cannot check/apply formatting. Staged files and workspace differ for file:"
124+
printf "\t$file\n"
125+
exit $EXIT_ERROR
126+
elif [ $diff_return_code -eq 2 ];then
127+
exit $EXIT_ERROR
128+
fi
129+
130+
# clang-format our sourcefile, create a patch with diff and append it to our $patch
131+
# The sed call is necessary to transform the patch from
132+
# --- $file timestamp
133+
# +++ - timestamp
134+
# to both lines working on the same file and having a a/ and b/ prefix.
135+
# Else it can not be applied with 'git apply'.
136+
"$CLANG_FORMAT_BIN" -style=file "$file" | \
137+
diff -u "$file" - | \
138+
sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/$file|" >> "$patch"
139+
done
140+
141+
# if no patch has been generated all is ok, clean up the file stub and exit
142+
if [ ! -s "$patch" ] ; then
143+
printf "Files in this commit comply with the clang-format rules.\n"
144+
rm -f "$patch"
145+
exit $EXIT_SUCCESS
146+
fi
147+
148+
# some files are not properly formatted
149+
printf "\nThe following files do not match the clang-format rules:\n\n"
150+
lsdiff "$patch" --strip=1 | sed 's/^/\t/'
151+
printf "\nDifferences:\n\n"
152+
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
153+
cat "$patch"
154+
echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
155+
156+
echo ""
157+
echo "Should the changes be added to the commit (y/n/abort)?"
158+
echo " - (y)es : apply formatting and proceed with commit"
159+
echo " - (n)o : proceed with commit (do not apply formatting)"
160+
echo " - (a)bort : abort commit"
161+
162+
# Allows us to read user input below, assigns stdin to keyboard
163+
exec < /dev/tty
164+
read answer
165+
# close STDIN
166+
exec <&-
167+
168+
if echo "$answer" | grep -iq "^y" ;then
169+
formatted_files=$(lsdiff "$patch" --strip=1)
170+
echo "Applying formatting on files:"
171+
echo "$formatted_files" | sed 's/^/\t/'
172+
git apply $patch
173+
git add $formatted_files
174+
exit $EXIT_SUCCESS
175+
elif echo "$answer" | grep -iq "^n" ;then
176+
echo "No formatting applied. Proceeding with commit."
177+
exit $EXIT_SUCCESS
178+
else
179+
echo "Aborting commit"
180+
printf "You may apply these changes manually with:\n git apply $patch\n"
181+
printf "(may need to be called from the root directory of your repository)\n"
182+
printf "(pre-commit can be disabled by committing with --no-verify)\n"
183+
exit $EXIT_ERROR
184+
fi

0 commit comments

Comments
 (0)