diff options
-rwxr-xr-x | pre-commit | 6 | ||||
-rw-r--r-- | pre-commit-style | 252 |
2 files changed, 258 insertions, 0 deletions
diff --git a/pre-commit b/pre-commit index bee9c90274..15a0151b00 100755 --- a/pre-commit +++ b/pre-commit @@ -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 : diff --git a/pre-commit-style b/pre-commit-style new file mode 100644 index 0000000000..15af958fd0 --- /dev/null +++ b/pre-commit-style @@ -0,0 +1,252 @@ +#============================================================================= +# 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 : |