summaryrefslogtreecommitdiff
path: root/misc/hooks/pre-commit-black
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2020-03-30 08:55:21 +0200
committerRémi Verschelde <rverschelde@gmail.com>2020-03-30 09:05:59 +0200
commit164826a39bca2fb7b7277752cbc1df8833ce0f1a (patch)
tree16d364582bda7b4122908a2c5c9e3a5cc073f7e2 /misc/hooks/pre-commit-black
parentcd4e46ee65dab6baa6a143bf3b3f64244be36712 (diff)
Hooks: Add pre-commit hook for psf/black formatting
Diffstat (limited to 'misc/hooks/pre-commit-black')
-rwxr-xr-xmisc/hooks/pre-commit-black128
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