mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 09:59:12 +00:00
e368fa1290
Check for leading TABs in files marked with the whitespace=tab-in-indent attribute instead of hard-coding a list of file extensions.
242 lines
7.8 KiB
Bash
Executable File
242 lines
7.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#=============================================================================
|
|
# 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.
|
|
#=============================================================================
|
|
|
|
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
|
|
|
|
# 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
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Builtin whitespace checks.
|
|
bad=$(git diff-index --check --cached $against --) || die "$bad"
|
|
|
|
# Approximate whitespace=tab-in-indent check with Git < 1.7.2.
|
|
check_tab() {
|
|
lines=$(git diff-index -p --cached $against -- "$1" |
|
|
grep '^+ ') &&
|
|
echo "$lines" |
|
|
while read line; do
|
|
echo "$1: tab in indent." &&
|
|
echo "$line"
|
|
done
|
|
}
|
|
approx_tab_in_indent() {
|
|
ws=$(git check-attr whitespace -- "$file" |
|
|
sed 's/^[^:]*: whitespace: //')
|
|
case ",$ws," in
|
|
*,tab-in-indent,*) check_tab "$1" ;;
|
|
esac
|
|
}
|
|
if git --version | grep " \(1\.[0-6]\|1\.7\.[01]\)" >/dev/null; then
|
|
bad=$(git diff-index --name-only --cached $against -- |
|
|
while read file; do
|
|
approx_tab_in_indent "$file"
|
|
done)
|
|
test -z "$bad" || die "$bad"
|
|
fi
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Check file modes and sizes.
|
|
mode_looks_exe() {
|
|
case "$1" in
|
|
*.bat) return 0 ;;
|
|
*.cmd) return 0 ;;
|
|
*.exe) return 0 ;;
|
|
*.com) return 0 ;;
|
|
esac
|
|
git cat-file blob "$2" | head -1 | grep "^#!/" > /dev/null
|
|
}
|
|
mode_not_exe () {
|
|
echo "The file '$file' has looks executable but does not have an executable mode."
|
|
}
|
|
mode_bad_exe () {
|
|
echo "The file '$file' has executable mode but does not look executable."
|
|
}
|
|
mode_non_file () {
|
|
echo "The path '$file' has a non-file mode."
|
|
}
|
|
check_mode() {
|
|
case "$dst_mode" in
|
|
100755) mode_looks_exe "$file" "$dst_obj" || mode_bad_exe ;;
|
|
100644) mode_looks_exe "$file" "$dst_obj" && mode_not_exe ;;
|
|
160000) ;;
|
|
*) mode_non_file ;;
|
|
esac
|
|
}
|
|
|
|
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. 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
|
|
}
|
|
|
|
short_commit() {
|
|
git rev-parse --short "$1" 2>/dev/null || echo "$1"
|
|
}
|
|
|
|
lookup_config_module_update() {
|
|
# Format is "aaaaaa..bbbbbb" for update aaaaaa => bbbbbb.
|
|
# Convert to regex "^aaaaaa[a-z0-9]* bbbbbb[a-z0-9]*$".
|
|
sha1ex='[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]*'
|
|
regex='^\('"$sha1ex"'\)\.\.\('"$sha1ex"'\)$'
|
|
git config "hooks.$1.update" |
|
|
sed -n "/$regex/ {s/$regex/"'^\1[a-z0-9]* \2[a-z0-9]*$/;p;}' |
|
|
grep '.' # Return false if result is empty.
|
|
}
|
|
|
|
check_module() {
|
|
# Allow module-only commits without extra work.
|
|
test -z "$diffs_normal" && return
|
|
|
|
# Check if module update is allowed with other changes.
|
|
allow=$(lookup_config_module_update "$file") || allow='none'
|
|
if echo "$src_obj $dst_obj" | grep "$allow" > /dev/null; then
|
|
return
|
|
fi
|
|
src_short=$(short_commit "$src_obj")
|
|
dst_short=$(short_commit "$dst_obj")
|
|
echo 'A submodule link is staged for commit (among other changes):
|
|
|
|
"'"$file"'" '"$src_short => $dst_short"'
|
|
|
|
This may occur by accident so we require an extra step to commit.
|
|
If you intend to include this change in your commit, run
|
|
|
|
git config "hooks.'"$file"'.update" '"$src_short..$dst_short"'
|
|
|
|
to explicitly allow the change and try the commit again. Otherwise run
|
|
|
|
git reset HEAD -- "'"$file"'"
|
|
|
|
to unstage the change. Furthermore, if you did not intend to modify
|
|
the submodule at all, also run
|
|
|
|
git submodule update -- "'"$file"'"
|
|
|
|
to checkout the current version of the submodule in your work tree.
|
|
Test your changes again to see if they still work with the module.
|
|
Finally, try the commit again.
|
|
'
|
|
}
|
|
|
|
diffs=$(git diff-index --cached $against -- |
|
|
sed -n '/^:[^:]/ {s/^://;p;}')
|
|
diffs_normal=$(echo "$diffs" | grep -v '^...... 160000')
|
|
diffs_module=$(echo "$diffs" | grep '^...... 160000')
|
|
bad=$(
|
|
test -n "$diffs_normal" && echo "$diffs_normal" |
|
|
while read src_mode dst_mode src_obj dst_obj status file; do
|
|
if test "$src_mode" != "$dst_mode" -a "$dst_mode" != "000000"; then
|
|
check_mode
|
|
fi
|
|
if test "$dst_mode" != "160000" -a "$dst_mode" != '000000'; then
|
|
check_size
|
|
fi
|
|
done
|
|
test -n "$diffs_module" && echo "$diffs_module" |
|
|
while read src_mode dst_mode src_obj dst_obj status file; do
|
|
check_module
|
|
done
|
|
)
|
|
test -z "$bad" || die "$bad"
|