#!/bin/bash #Version 1.0.0 die() { echo 'pre-commit hook failure' 1>&2 echo '-----------------------' 1>&2 echo '' 1>&2 echo "$@" 1>&2 exit 1 } zero='0000000000000000000000000000000000000000' #----------------------------------------------------------------------------- # Check for committer identity. advice=' Use the commands git config --global user.name '\''Your Name'\'' git config --global user.email '\''you@yourdomain.com'\'' to introduce yourself to Git before committing.' # Ensure name and email are available. git config --get user.name > /dev/null && git config --get user.email > /dev/null || die 'Identity not configured!' "$advice" # Validate the name and email. git config --get user.name | grep ' ' > /dev/null || die 'Set user.name to your Real Name (with a space), not a userid.' "$advice" git config --get user.email | grep '^[^@]*@[^@]*$' > /dev/null || die 'Set user.email to an email address (userid@validdomain.com).' "$advice" #----------------------------------------------------------------------------- # Check content that will be added by this commit. if git rev-parse --verify -q HEAD > /dev/null; then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi # Merge ("git commit" after "git merge" with conflicts or --no-commit) merge_head=$(git rev-parse -q --verify MERGE_HEAD) || merge_head='' # Disallow non-ascii file names. The printable range starts at the # space character and ends with tilde. if test "$(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0')"; then die 'Non-ascii file names may not be added: '"$(git diff --cached --name-only --diff-filter=A $against)" fi #----------------------------------------------------------------------------- bad=$(git diff-index --check --cached $against --) || die "$bad" # Approximate whitespace=tab-in-indent check with Git < 1.7.2. git --version | grep -q " \(1\.[0-6]\|1\.7\.[01]\([^0-9]\|\$\)\)" && approx_tab_in_indent=true || approx_tab_in_indent=false check_tab() { echo tab-checking $1 lines=$(git diff-index -p --cached $against -- "$1" | grep '^+ ') && echo "$lines" | while read line; do echo "$1: tab in indent." && echo "$line" done } # Reject addition of a line without a newline at end-of-file. check_no_lf_at_eof() { lines=$(git diff-index -p --cached $against -- "$1" | tail -2) if echo "$lines" | head -1 | grep -q '^+' && echo "$lines" | tail -1 | grep -q '^\\ No newline'; then echo "$1: No newline at end of file" fi } # Custom whitespace checks. check_whitespace() { ws=$(git check-attr whitespace -- "$file" | sed 's/^[^:]*: whitespace: //') if $approx_tab_in_indent; then case ",$ws," in *,tab-in-indent,*) check_tab "$1" ;; esac fi case ",$ws," in *,no-lf-at-eof,*) check_no_lf_at_eof "$1" ;; esac } bad=$(git diff-index --name-only --cached $against -- | while read file; do check_whitespace "$file" done) test -z "$bad" || die "$bad" #----------------------------------------------------------------------------- # Check file size size_max_KiB=$(git config hooks.MaxObjectKiB) test -n "$size_max_KiB" || size_max_KiB=1024 size_too_large_once="" size_too_large_once() { test -z "$size_too_large_once" || return ; size_too_large_once=done echo 'At least one file is staged for commit with size larger than its limit. We prefer to keep large files out of the main source tree, especially binary files that do not compress well. If you absolutely have to commit such a large file be prepared to convince Marco. ' } # This hook disallows large files # by default but can be configured. A limit for specific files or patterns # may be set in ".gitattributes" with the "hooks.MaxObjectKiB" attribute. # For example, the line # # *.c hooks.MaxObjectKiB=2048 # # sets a limit of 2048 KiB for C source files. See "git help attributes" # for details on the .gitattributes format. If no attribute has been set # for a given file then its size is limited by the local default. Run # # git config hooks.MaxObjectKiB $KiB # # to set the local default limit (0 to disable). size_too_large() { size_too_large_once echo "The path '$file' has size $file_KiB KiB, greater than allowed $max_KiB KiB." } size_validate_max_KiB() { test "$max_KiB" -ge "0" 2>/dev/null && return 0 echo "The path '$file' has invalid attribute \"hooks-MaxObjectKiB=$max_KiB\"." return 1 } check_size() { test "$dst_obj" != "$zero" || return max_KiB=$(git check-attr hooks.MaxObjectKiB -- "$file" | sed 's/^[^:]*: hooks.MaxObjectKiB: //') case "$max_KiB" in 'unset') return ;; # No maximum for this object. 'set') max_KiB="$size_max_KiB" ;; # Use local default. 'unspecified') max_KiB="$size_max_KiB" ;; # Use local default. *) size_validate_max_KiB || return ;; esac if test "$max_KiB" -gt "0"; then file_KiB=$(expr '(' $(git cat-file -s "$dst_obj") + 1023 ')' / 1024) test "$file_KiB" -le "$max_KiB" || size_too_large fi } #----------------------------------------------------------------------------- # Make sure the file contains a copyright header check_mitk_copyright(){ cpr_count=$(grep -c "See LICENSE.txt or http://www.mitk.org " $1 | grep '0') && echo "$cpr_count" | echo "$1: Missing MITK copyright header." } check_apache_copyright(){ cpr_count=$(grep -c "Licensed under the Apache License, Version 2.0 " $1 | grep '0') && echo "$cpr_count" | echo "$1: Missing Apache copyright header." } check_copyright() { cpr=$(git check-attr copyright -- "$file" | sed 's/^[^:]*: copyright: //') case ",$cpr," in *,mitk-license,*) check_mitk_copyright "$1" ;; esac case ",$cpr," in *,apache-license,*) check_apache_copyright "$1" ;; esac } bad=$(git diff-index --name-only --cached $against -- | while read file; do check_copyright "$file" done) test -z "$bad" || die "$bad" #-------------------------------------------------------------------------- # Ensure valid doxygen file syntax check_old_doxygen_image_tag() { old_tag_count=$(grep -c "\\\\image " $1 ) && echo "$old_tag_count" | echo "$1: File contains old style doxygen image tag (\image) use the \imageMacro{,\"DESCRIPTION\", }" } check_new_doxygen_image_tag_syntax() { new_tag_count=$(grep -c "\\\\imageMacro{" $1 | grep '0') test -e "$new_tag_count" || grep "\\\\imageMacro{" $1 | awk -F'[{}]' '{print $2}' | while read -r line; do OIFS="$IFS" IFS=',' read -a array <<< "$line" if [ ! ${#array[@]} -eq 3 ] ; then echo "Wrong number of parameters on in imageMacro command \imageMacro{$line}" else path_regex=".*\.(jpg|png)" [[ ${array[0]} =~ $path_regex ]] || echo "No valid image path, received : ${array[0]}" desc_regex="\"[([:alpha:]|[,]|[:space:])]+\"" [[ ${array[1]} =~ $desc_regex ]] || echo "No valid description, received : ${array[1]}" fi IFS="$OIFS" done } check_doxygen_syntax() { # echo "Intern function $1 failed" # check for \image appareance check_old_doxygen_image_tag $1 | check_new_doxygen_image_tag_syntax $1 } check_doxygen(){ #echo "Doxygen check for $1" doxycheck=$(git check-attr doxycheck -- "$1" | sed 's/^[^:]*: doxycheck: //') case ",$doxycheck," in *,image-macro-style,*) check_doxygen_syntax "$1" ;; esac } bad=$(git diff-index --name-only --cached $against -- | while read file; do check_doxygen "$file" done) test -z "$bad" || die "$bad"