diff options
Diffstat (limited to 'misc/hooks/pre-commit-black')
-rwxr-xr-x | misc/hooks/pre-commit-black | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black new file mode 100755 index 0000000000..3dd0a13330 --- /dev/null +++ b/misc/hooks/pre-commit-black @@ -0,0 +1,128 @@ +#!/usr/bin/env bash + +# git pre-commit hook that runs a black stylecheck. +# Based on pre-commit-clang-format. + +################################################################## +# SETTINGS +# Set path to black binary. +BLACK=`which black` +BLACK_OPTIONS="-l 120" + +# Remove any older patches from previous commits. Set to true or false. +DELETE_OLD_PATCHES=false + +# File types to parse. +FILE_NAMES="SConstruct SCsub" +FILE_EXTS="py" + +# Use pygmentize instead of cat to parse diff with highlighting. +# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac) +# READER="pygmentize -l diff" +READER=cat + +################################################################## +# There should be no need to change anything below this line. + +. "$(dirname -- "$0")/canonicalize_filename.sh" + +# exit on error +set -e + +# check whether the given file matches any of the set extensions +matches_name_or_extension() { + local filename=$(basename "$1") + local extension=".${filename##*.}" + + for name in $FILE_NAMES; do [[ "$name" == "$filename" ]] && return 0; done + for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done + + return 1 +} + +# necessary check for initial commit +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 + +if [ ! -x "$BLACK" ] ; then + printf "Error: black executable not found.\n" + printf "Set the correct path in $(canonicalize_filename "$0").\n" + exit 1 +fi + +# create a random filename to store our generated patch +prefix="pre-commit-black" +suffix="$(date +%s)" +patch="/tmp/$prefix-$suffix.patch" + +# clean up any older black patches +$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch + +# create one patch containing all changes to the files +git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; +do + # ignore thirdparty files + if grep -q "thirdparty" <<< $file; then + continue; + fi + + # ignore file if not one of the names or extensions we handle + if ! matches_name_or_extension "$file"; then + continue; + fi + + # format our file with black, create a patch with diff and append it to our $patch + # The sed call is necessary to transform the patch from + # --- $file timestamp + # +++ $file timestamp + # to both lines working on the same file and having a/ and b/ prefix. + # Else it can not be applied with 'git apply'. + "$BLACK" "$BLACK_OPTIONS" --diff "$file" | \ + sed -e "1s|--- |--- a/|" -e "2s|+++ |+++ b/|" >> "$patch" +done + +# if no patch has been generated all is ok, clean up the file stub and exit +if [ ! -s "$patch" ] ; then + printf "Files in this commit comply with the black formatter rules.\n" + rm -f "$patch" + exit 0 +fi + +# a patch has been created, notify the user and exit +printf "\nThe following differences were found between the code to commit " +printf "and the black formatter rules:\n\n" +$READER "$patch" +printf "\n" + +# Allows us to read user input below, assigns stdin to keyboard +exec < /dev/tty + +while true; do + read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn + case $yn in + [Yy] ) git apply $patch; + printf "The patch was applied. You can now stage the changes and commit again.\n\n"; + break + ;; + [Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n"; + printf "(may need to be called from the root directory of your repository)\n"; + printf "Aborting commit. Apply changes and commit again or skip checking with"; + printf " --no-verify (not recommended).\n\n"; + break + ;; + [Ss] ) git apply $patch; + git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; + do git add $file; + done + printf "The patch was applied and the changed files staged. You can now commit.\n\n"; + break + ;; + * ) echo "Please answer yes or no." + ;; + esac +done +exit 1 # we don't commit in any case |