Commit d5bb0764 authored by Matt McCormick's avatar Matt McCormick

pre-commit: Apply uncrustify and KWStyle check for modified files.

uncrustify (uncrustify.sourceforge.net) is applied to changed files prior to
commit.

This feature is off by default.  To enable this behavior, set

  git config hooks.uncrustify true

By default, the behavior of git-mergetool is used to review the changes
uncrustify makes before they are added to the commit.  For more information on
this behavior, see

  git help mergetool

KWStyle is run on the changed C++ files and the commit is aborted if the files
do not pass the test.  A file similar to the original is saved with a '*.kws'
extension so that line numbers referenced in the error message can be examined.

The test is off by default.  To enable this behavoir, set

  git config hooks.KWStyle true

Project specific uncrustify and KWStyle configuration files are set with 'git
config'.  For example,

  git config hooks.uncrustify.conf path/to/uncrustify.conf
  git config hooks.KWStyle.conf path/to/KWStyle.conf
  git config hooks.KWStyle.overwriteRulesConf path/to/overwrite.conf # optional

If the appropriate values have not been set, die() is called.  An
optional KWStyle overwrite rules file can also been configured.

The files on which to run the style checks must also be identified in the
repository's '.gitattributes'.  For example,

  *.h    hooks.style
  *.cpp  hooks.style

Or, to only enable a subset of style hooks,

  *.h    hooks.style=KWStyle
  *.cpp  hooks.style=KWStyle,uncrustify

Change-Id: Ia6b2d4136af3002eb0ec5d36f03c50df928917f4
parent 19f86ec1
......@@ -247,3 +247,9 @@ while read src_mode dst_mode src_obj dst_obj status file; do
done
)
test -z "$bad" || die "$bad"
#-----------------------------------------------------------------------------
# Style hooks.
. "$GIT_DIR/hooks/pre-commit-style"
# vim: set filetype=sh tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab :
#=============================================================================
# Copyright 2010 Kitware, Inc.
#
# 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.
#=============================================================================
# Run uncrustify and KWStyle pre-commit hooks.
#
# 'git config' is used to enable the hooks and set their configuration files.
# The repository .gitattributes must also enable the hooks on the targeted
# files.
do_KWStyle=$(git config --bool hooks.KWStyle) || do_KWStyle=false
do_uncrustify=$(git config --bool hooks.uncrustify) || do_uncrustify=false
#-----------------------------------------------------------------------------
# Check if we want to run the style on a given file. Uses git attributes. If
# the hook.style attribute is set, then all styles are executed. If the
# hook.style attribute is set to a value, only the values given are executed.
# Also, do not run the style check if there are unstaged changes in the file.
# The first positional parameter is the file to check.
# The second positional parameter is the style to check.
# Returns 0 for execute, 1 for don't execute.
run_style_on_file() {
# Do not run on submodule changes.
if git diff-index --cached $against -- "$1" | grep -q '^:...... 160000'; then
return 1
fi
if ! git diff-files --quiet -- "$1"; then
# A way to always allow skipping.
skip_unstaged=$(git config --bool hooks.styleSkipUnstaged) ||
skip_unstaged=false
file_sha=$(git diff-index --cached --abbrev=7 $against -- "$1" | \
awk '{print substr($3,1,9) substr($4,1,7)}')
if file_skip_unstaged=$(git config "hooks.$1.styleSkipUnstaged"); then
if test ",$file_skip_unstaged," = ",$file_sha," -o \
",$file_skip_unstaged," = ",true,"; then
skip_unstaged=true
fi
fi
if $skip_unstaged; then
echo "The file '$1' contains unstaged stages. Skipping style \
check '$2'."
else
die "Style check '$2' cannot run on '$1' with unstaged stages.
Allow skipping the style check for this commit with
git config \"hooks.$1.styleSkipUnstaged\" $file_sha"
fi
return 1
fi
style=$(git check-attr hooks.style -- "$1" |
sed 's/^[^:]*: hooks.style: //')
case "$style" in
'unset') return 1 ;;
'set') return 0 ;;
'unspecified') return 1 ;;
*) echo ",$style," | grep -iq ",$2," && return 0 ;;
esac
return 1
}
#-----------------------------------------------------------------------------
# KWStyle.
check_for_KWStyle() {
KWStyle_path=$(git config hooks.KWStyle.path) ||
KWStyle_path=$(which KWStyle) ||
die "KWStyle executable was not found.
Please install KWStyle or set the executable location with
git config hooks.KWStyle.path /path/to/KWStyle
See http://public.kitware.com/KWStyle/"
KWStyle_conf=$(git config hooks.KWStyle.conf)
if ! test -f "$KWStyle_conf"; then
die "The file '$KWStyle_conf' does not exist.
Please run
git config hooks.KWStyle.conf path/to/KWStyle.conf.xml"
fi
KWStyle_overWriteRulesConf=$(git config hooks.KWStyle.overwriteRulesConf)
if test $? -eq 0 && ! test -f "$KWStyle_overWriteRulesConf"; then
die "The hooks.KWStyle.overwriteRulesConf file '$KWStyle_overWriteRulesConf' does not exist."
fi
}
run_KWStyle_on_file() {
if test -z "$KWStyle_overWriteRulesConf"; then
"$KWStyle_path" -v -xml "$KWStyle_conf" "$1"
else
"$KWStyle_path" -v -xml "$KWStyle_conf" -o "$KWStyle_overWriteRulesConf" "$1"
fi
if test $? -ne 0; then
cp -- "$1"{,.kws}
die "KWStyle check failed.
Line numbers in the errors shown refer to the file:
${1}.kws"
fi
}
run_KWStyle() {
git diff-index --cached --diff-filter=ACMR --name-only $against -- |
while read f; do
if run_style_on_file "$f" KWStyle; then
run_KWStyle_on_file "$f"
fi
done
}
#-----------------------------------------------------------------------------
# uncrustify.
check_for_uncrustify() {
uncrustify_path=$(git config hooks.uncrustify.path) ||
uncrustify_path=$(which uncrustify) ||
die "uncrustify executable was not found.
Please install uncrustify or set the executable location with
git config hooks.uncrustify.path /path/to/uncrustify
See http://uncrustify.sourceforge.net/"
uncrustify_conf=$(git config hooks.uncrustify.conf)
if ! test -f "$uncrustify_conf"; then
die "The file '$uncrustify_conf' does not exist.
Please run
git config hooks.uncrustify.conf path/to/uncrustify.conf"
fi
}
run_uncrustify_on_file() {
MERGED="$1"
if run_style_on_file "$MERGED" uncrustify; then
ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
BACKUP="./$MERGED.BACKUP.$ext"
LOCAL="./$MERGED.STAGED.$ext"
REMOTE="./$MERGED.UNCRUSTIFY.$ext"
NEW_MERGED="./$MERGED.NEW.$ext"
OLD_MERGED="$MERGED"
mv -- "$MERGED" "$BACKUP"
# We temporarily change MERGED because the file might already be open, and
# the text editor may complain.
MERGED="$NEW_MERGED"
cp -- "$BACKUP" "$MERGED"
cp -- "$BACKUP" "$LOCAL"
if ! "$uncrustify_path" -c "$uncrustify_conf" -f "$LOCAL" \
-o "$REMOTE" 2> /dev/null; then
mv -- "$BACKUP" "$OLD_MERGED"
if test "$merge_keep_temporaries" = "false"; then
rm -f -- "$LOCAL" "$REMOTE" "$BACKUP"
fi
die "error when running uncrustify on $OLD_MERGED"
fi
if test $(git hash-object -- "$LOCAL") != $(git hash-object -- "$REMOTE") &&
! run_merge_tool "$merge_tool" "false" </dev/tty; then
mv -- "$BACKUP" "$OLD_MERGED"
if test "$merge_keep_temporaries" = "false"; then
rm -f -- "$LOCAL" "$REMOTE" "$BACKUP" "$NEW_MERGED"
fi
die "uncrustify merge of $OLD_MERGED failed"
fi
mv -- "$NEW_MERGED" "$OLD_MERGED"
MERGED="$OLD_MERGED"
if test "$merge_keep_backup" = "true"; then
mv -- "$BACKUP" "$MERGED.orig"
else
rm -- "$BACKUP"
fi
git add -- "$MERGED"
rm -f -- "$LOCAL" "$REMOTE" "$BACKUP"
fi # end if run uncrustify on file
if $do_KWStyle && run_style_on_file "$MERGED" KWStyle; then
run_KWStyle_on_file "$MERGED"
else
return 0
fi
}
run_uncrustify() {
$do_KWStyle && check_for_KWStyle
merge_tool=$(get_merge_tool "$merge_tool") || die "Merge tool not configured.
Set the merge tool with
git config merge.tool <toolname>
For more information, see
git help mergetool"
merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
git diff-index --cached --diff-filter=ACMR --name-only $against -- |
while read MERGED; do
run_uncrustify_on_file "$MERGED"
done # end for changed files
}
# Do not run during merge commits for now.
if test -f "$GIT_DIR/MERGE_HEAD"; then
:
elif $do_uncrustify; then
# We use git-mergetool settings to review the uncrustify changes.
TOOL_MODE=merge
. "$(git --exec-path)/git-mergetool--lib"
# Redefine check_unchanged because we do not need to check if the merge was
# successful.
check_unchanged() {
status=0
}
check_for_uncrustify
run_uncrustify
# do_uncrustify will run KWStyle on the files incrementally so excessive
# uncrustify merges do not have to occur.
elif $do_KWStyle; then
check_for_KWStyle
run_KWStyle
fi
# vim: set filetype=sh tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab :
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment