Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/dev/pre-commit
8815 views
#!/usr/bin/env bash

# the following strips any trailing whitespace from the commit as well
# as turn any tab characters into spaces for python and cython files
# and updates local files to match

if git rev-parse --verify HEAD >/dev/null 2>&1
then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# add null object to repository for is-binary
NULL_OBJECT=`git hash-object -w /dev/null`

# based on
# http://stackoverflow.com/questions/6119956/how-to-determine-if-git-handles-a-file-as-binary-or-as-text
BINARY_NUMSTAT="`printf '%s\t-\t' -`"
is-binary () {
    diffstat="`git diff --numstat $NULL_OBJECT $1`"
    case $diffstat in
        "$BINARY_NUMSTAT"*)
            return 0
        ;;
        *)
            return 1
        ;;
    esac
}

# set IFS to newlines for the following for loops
OIFS=$IFS
IFS=$'\n'

# fixed the index first
for line in `git diff-index --cached $against | sed "s/\t/ /" | cut -f2,4,6 -d' '`
do
    mode="${line:0:6}"
    object="${line:7:40}"
    path="${line:48}"
    if [ "${mode:0:2}" != "10" ]; then
        # not a regular file in this case, so skip it
        new_object=$object
    elif is-binary $object; then
        # don't mess with binaries (such as png files)
        new_object=$object
    elif [ "${path: -6}" == ".patch" -o "${path: -5}" == ".diff" ]; then
        # don't mess with diff or patch files
        new_object=$object
    else
        lines=`git cat-file -p $object | sed 's+\s*++g' | GREP_OPTIONS= egrep -n '^..*$' | sed 's+:.*++' | tail -1`
        if [ \
            "${path: -3}" == ".py" -o \
            "${path: -4}" == ".pyx" -o \
            "${path: -4}" == ".pxd" -o \
            "${path: -4}" == ".pxi" -o \
            "${path: -4}" == ".rst" ]; then
            tabs="-e s+\t+    +g"
        else
            tabs=""
        fi
        new_object=`git cat-file -p $object | sed -e 's+\s*$++' $tabs | head -n $lines | git hash-object -w --stdin`
    fi
    echo -e "$mode $new_object\t$path"
done |
    git update-index --index-info

# now fix the local files
for line in `git diff-index $against | sed "s/\t/ /" | cut -f2,6 -d' '`
do
    mode="${line:0:6}"
    path="${line:7}"
    object=`git hash-object $path`
    if [ "${mode:0:2}" != "10" ]; then
        # not a regular file in this case, so skip it
        true
    elif is-binary $object; then
        # don't mess with binaries (such as png files)
        true
    elif [ "${path: -6}" == ".patch" -o "${path: -5}" == ".diff" ]; then
        # don't mess with diff or patch files
        true
    else
        if [ \
            "${path: -3}" == ".py" -o \
            "${path: -4}" == ".pyx" -o \
            "${path: -4}" == ".pxd" -o \
            "${path: -4}" == ".pxi" -o \
            "${path: -4}" == ".rst" ]; then
            tabs="-e s+\t+    +g"
        else
            tabs=""
        fi
        sed -i -e 's+\s*$++' $tabs $path
        echo "$path: removed all trailing whitespace"
        if [ -n "$tabs" ]; then
            echo "$path: replaced all tab characters with 4 spaces"
        fi
        lines=`sed 's+\s*++g' $path | GREP_OPTIONS= egrep -n '^..*$' | sed 's+:.*++' | tail -1`
        if [ $lines -ne `wc -l $path | cut -d' ' -f1` ]; then
            head -n $lines $path > $path.new && mv $path.new $path
            echo "$path: removed all empty trailing newlines"
        fi
    fi
done

IFS=$OIFS

if git diff --cached --quiet; then
    git status
    exit 1
fi