Hooks: Add pre-commit hook for psf/black formatting

(cherry picked from commit 164826a39b)
This commit is contained in:
Rémi Verschelde 2020-03-30 08:55:21 +02:00
parent 7bf9787921
commit 1ec7a73d1c
4 changed files with 146 additions and 16 deletions

View file

@ -5,16 +5,22 @@ contributors to make sure they comply with our requirements.
## List of hooks ## List of hooks
- Pre-commit hook for clang-format: Applies clang-format to the staged files - Pre-commit hook for `clang-format`: Applies `clang-format` to the staged
before accepting a commit; blocks the commit and generates a patch if the files before accepting a commit; blocks the commit and generates a patch if
style is not respected. the style is not respected.
Should work on Linux and macOS. You may need to edit the file if your You may need to edit the file if your `clang-format` binary is not in the
clang-format binary is not in the `$PATH`, or if you want to enable colored `PATH`, or if you want to enable colored output with `pygmentize`.
output with pygmentize. - Pre-commit hook for `black`: Applies `black` to the staged Python files
- Pre-commit hook for makerst: Checks the class reference syntax using `makerst.py`. before accepting a commit.
Should work on Linux and macOS. - Pre-commit hook for `makerst`: Checks the class reference syntax using
`makerst.py`.
## Installation ## Installation
Copy all the files from this folder into your `.git/hooks` folder, and make sure Copy all the files from this folder into your `.git/hooks` folder, and make
the hooks and helper scripts are executable. sure the hooks and helper scripts are executable.
The hooks rely on bash scripts and tools which should be in the system `PATH`,
so they should work out of the box on Linux/macOS, and might work on Windows
when using `git-bash.exe` with `clang-format`, Python, `black`, etc. in the
`PATH`.

View file

@ -14,7 +14,7 @@
# as this script. Hooks should return 0 if successful and nonzero to cancel the # as this script. Hooks should return 0 if successful and nonzero to cancel the
# commit. They are executed in the order in which they are listed. # commit. They are executed in the order in which they are listed.
#HOOKS="pre-commit-compile pre-commit-uncrustify" #HOOKS="pre-commit-compile pre-commit-uncrustify"
HOOKS="pre-commit-clang-format pre-commit-makerst" HOOKS="pre-commit-clang-format pre-commit-black pre-commit-makerst"
########################################################### ###########################################################
# There should be no need to change anything below this line. # There should be no need to change anything below this line.

128
misc/hooks/pre-commit-black Executable file
View file

@ -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

View file

@ -15,22 +15,18 @@
################################################################## ##################################################################
# SETTINGS # SETTINGS
# Set path to clang-format binary # Set path to clang-format binary.
# CLANG_FORMAT="/usr/bin/clang-format"
CLANG_FORMAT=`which clang-format` CLANG_FORMAT=`which clang-format`
# Remove any older patches from previous commits. Set to true or false. # Remove any older patches from previous commits. Set to true or false.
# DELETE_OLD_PATCHES=false
DELETE_OLD_PATCHES=false DELETE_OLD_PATCHES=false
# Only parse files with the extensions in FILE_EXTS. Set to true or false. # Only parse files with the extensions in FILE_EXTS. Set to true or false.
# If false every changed file in the commit will be parsed with clang-format. # If false every changed file in the commit will be parsed with clang-format.
# If true only files matching one of the extensions are parsed with clang-format. # If true only files matching one of the extensions are parsed with clang-format.
# PARSE_EXTS=true
PARSE_EXTS=true PARSE_EXTS=true
# File types to parse. Only effective when PARSE_EXTS is true. # File types to parse. Only effective when PARSE_EXTS is true.
# FILE_EXTS=".c .h .cpp .hpp"
FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl" FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl"
# Use pygmentize instead of cat to parse diff with highlighting. # Use pygmentize instead of cat to parse diff with highlighting.