From cc31ce96fb51cbf2c3437388ae365a8a388c7658 Mon Sep 17 00:00:00 2001 From: Andrey Astafyev Date: Mon, 19 Oct 2020 07:39:46 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pre-commit | 48 +++++++++++++ pre-commit-uncrustify | 148 ++++++++++++++++++++++++++++++++++++++ pre-commit-uncrustify.cfg | 42 +++++++++++ pre-commit.cfg | 18 +++++ 4 files changed, 256 insertions(+) create mode 100755 pre-commit create mode 100755 pre-commit-uncrustify create mode 100644 pre-commit-uncrustify.cfg create mode 100644 pre-commit.cfg diff --git a/pre-commit b/pre-commit new file mode 100755 index 0000000..3e6642e --- /dev/null +++ b/pre-commit @@ -0,0 +1,48 @@ +#!/bin/sh +# Git pre-commit hook that runs multiple hooks specified in $HOOKS. +# Make sure this script is executable. Bypass hooks with git commit --no-verify. + +# This file is part of a set of unofficial pre-commit hooks available +# at github. +# Link: https://github.com/ddddavidmartin/Pre-commit-hooks +# Contact: David Martin, ddddavidmartin@fastmail.com + +########################################################### +# There should be no need to change anything below this line. +# For configuration see pre-commit.cfg and pre-commit.example.cfg. + +# exit on error +set -e + +# Absolute path to this script, e.g. /home/user/bin/foo.sh +SCRIPT="$(readlink -f "$0")" +# Absolute path this script is in, thus /home/user/bin +SCRIPTPATH="$(dirname -- "$SCRIPT")" +CONFIG="$SCRIPTPATH/pre-commit.cfg" + +if [ ! -f "$CONFIG" ] ; then + echo "Missing config file $CONFIG." + echo "You can skip all pre-commit hooks with --no-verify (not recommended)." + exit 1 +else + . "$CONFIG" +fi + +for hook in $HOOKS +do + echo "Running hook: $hook" + # run hook if it exists + # if it returns with nonzero exit with 1 and thus abort the commit + if [ -f "$SCRIPTPATH/$hook" ]; then + "$SCRIPTPATH/$hook" + if [ $? != 0 ]; then + exit 1 + fi + else + echo "Error: file $hook not found." + echo "Aborting commit. Make sure the hook is in $SCRIPTPATH and executable." + echo "You can disable it by removing it from the list in $CONFIG." + echo "You can skip all pre-commit hooks with --no-verify (not recommended)." + exit 1 + fi +done diff --git a/pre-commit-uncrustify b/pre-commit-uncrustify new file mode 100755 index 0000000..aa22349 --- /dev/null +++ b/pre-commit-uncrustify @@ -0,0 +1,148 @@ +#!/bin/sh + +# git pre-commit hook that runs an Uncrustify stylecheck. +# Features: +# - abort commit when commit does not comply with the style guidelines +# - create a patch of the proposed style changes +# +# More info on Uncrustify: http://uncrustify.sourceforge.net/ + +# This file is part of a set of unofficial pre-commit hooks available +# at github. +# Link: https://github.com/ddddavidmartin/Pre-commit-hooks +# Contact: David Martin, ddddavidmartin@fastmail.com + +################################################################## +# There should be no need to change anything below this line. +# For configuration see pre-commit-uncrustify.cfg and +# pre-commit-uncrustify.example.cfg. + +# exit on error +set -e + +# Absolute path to this script, e.g. /home/user/bin/foo.sh +SCRIPT="$(readlink -f "$0")" +# Absolute path this script is in, e.g. /home/user/bin/ +SCRIPTPATH="$(dirname -- "$SCRIPT")" +CONFIG="$SCRIPTPATH/pre-commit-uncrustify.cfg" +REPO="$(git rev-parse --show-toplevel)" + +if [ ! -f "$CONFIG" ] ; then + echo "Missing config file $CONFIG." + exit 1 +else + . "$CONFIG" +fi + + +# check whether the given file matches any of the set extensions +matches_extension() { + local filename="$(basename -- "$1")" + local extension=".${filename##*.}" + local ext + + 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 + +# make sure the config file and executable are correctly set +if [ ! -f "$UNCRUST_CONFIG" ] ; then + printf "Error: uncrustify config file not found.\n" + printf "Set the correct path in $CONFIG.\n" + exit 1 +fi + +if ! command -v "$UNCRUSTIFY" > /dev/null ; then + printf "Error: uncrustify executable not found.\n" + printf "Set the correct path in $CONFIG.\n" + exit 1 +fi + +# create a filename to store our generated patch +prefix="pre-commit-uncrustify" +suffix="$(date +%C%y-%m-%d_%Hh%Mm%Ss)" +patch="/tmp/$prefix-$suffix.patch" + +# clean up any older uncrustify patches +$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch + +# create one patch containing all changes to the files +# sed to remove quotes around the filename, if inserted by the system +# (done sometimes, if the filename contains special characters, like the quote itself) +git diff-index --cached --diff-filter=ACMR --name-only $against -- | \ +sed -e 's/^"\(.*\)"$/\1/' | \ +while read file +do + # ignore file if we do check for file extensions and the file + # does not match any of the extensions specified in $FILE_EXTS + if $PARSE_EXTS && ! matches_extension "$file"; then + continue; + fi + + # escape special characters in the source filename: + # - '\': backslash needs to be escaped + # - '*': used as matching string => '*' would mean expansion + # (curiously, '?' must not be escaped) + # - '[': used as matching string => '[' would mean start of set + # - '|': used as sed split char instead of '/', so it needs to be escaped + # in the filename + # printf %s particularly important if the filename contains the % character + file_escaped_source=$(printf "%s" "$file" | sed -e 's/[\*[|]/\\&/g') + + # escape special characters in the target filename: + # phase 1 (characters escaped in the output diff): + # - '\': backslash needs to be escaped in the output diff + # - '"': quote needs to be escaped in the output diff if present inside + # of the filename, as it used to bracket the entire filename part + # phase 2 (characters escaped in the match replacement): + # - '\': backslash needs to be escaped again for sed itself + # (i.e. double escaping after phase 1) + # - '&': would expand to matched string + # - '|': used as sed split char instead of '/' + # printf %s particularly important if the filename contains the % character + file_escaped_target=$(printf "%s" "$file" | sed -e 's/[\"]/\\&/g' -e 's/[\&|]/\\&/g') + + # Uncrustify detects the language automatically if it is not specified + language_option="" + if [ "$SOURCE_LANGUAGE" != "AUTO" ] ; then + language_option="-l $SOURCE_LANGUAGE" + fi + + # uncrustify our sourcefile, create a patch with diff and append it to our $patch + # The sed call is necessary to transform the patch from + # --- $file timestamp + # +++ - timestamp + # to both lines working on the same file and having a a/ and b/ prefix. + # Else it can not be applied with 'git apply'. + "$UNCRUSTIFY" -c "$UNCRUST_CONFIG" -f "$file" $language_option | \ + diff -u -- "$file" - | \ + sed -e "1s|--- $file_escaped_source|--- \"a/$file_escaped_target\"|" -e "2s|+++ -|+++ \"b/$file_escaped_target\"|" >> "$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 uncrustify 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 uncrustify rules:\n\n" +cat "$patch" + +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" + +exit 1 diff --git a/pre-commit-uncrustify.cfg b/pre-commit-uncrustify.cfg new file mode 100644 index 0000000..984e204 --- /dev/null +++ b/pre-commit-uncrustify.cfg @@ -0,0 +1,42 @@ +# Example configuration for pre-commit-uncrustify. +# git pre-commit hook that runs an Uncrustify stylecheck. +# +# Instructions: +# Copy as pre-commit-uncrustify.cfg and place in same directory as +# pre-commit-uncrustify. +# +# This file is part of a set of unofficial pre-commit hooks available +# at github. +# Link: https://github.com/ddddavidmartin/Pre-commit-hooks +# Contact: David Martin, ddddavidmartin@fastmail.com + +################################################################## +# CONFIGURATION +# set uncrustify path or executable +# UNCRUSTIFY="/usr/bin/uncrustify" +UNCRUSTIFY="uncrustify" + +# set uncrustify config location +# UNCRUST_CONFIG="/home/user/.config/uncrustify.cfg" +UNCRUST_CONFIG="$REPO/cmake/etc/uncrustify/default.cfg" + +# the source language: C, CPP, D, CS, JAVA, PAWN, VALA, OC, OC+ +# use AUTO to let Uncrustify decide which language a given file uses. +# the detected language is printed to the console when Uncrustify is called. +# override if the automatic detection seems off. +# SOURCE_LANGUAGE="AUTO" +SOURCE_LANGUAGE="AUTO" + +# remove any older patches from previous commits. Set to true or false. +# DELETE_OLD_PATCHES=false +DELETE_OLD_PATCHES=true + +# 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 Uncrustify. +# if true only files matching one of the extensions are parsed with Uncrustify. +# PARSE_EXTS=true +PARSE_EXTS=true + +# file types to parse. Only effective when PARSE_EXTS is true. +# FILE_EXTS=".c .h .cpp .hpp" +FILE_EXTS=".c .h .cpp .hpp" diff --git a/pre-commit.cfg b/pre-commit.cfg new file mode 100644 index 0000000..4f013de --- /dev/null +++ b/pre-commit.cfg @@ -0,0 +1,18 @@ +# Example configuration for pre-commit. +# Git pre-commit hook that runs multiple hooks specified in $HOOKS. +# +# Instructions: +# Copy as pre-commit.cfg and place in same directory as pre-commit. +# +# This file is part of a set of unofficial pre-commit hooks available +# at github. +# Link: https://github.com/ddddavidmartin/Pre-commit-hooks +# Contact: David Martin, ddddavidmartin@fastmail.com + +########################################################### +# CONFIGURATION: +# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder +# as this file. Hooks should return 0 if successful and nonzero to cancel the +# commit. They are executed in the order in which they are listed. +#HOOKS="pre-commit-compile pre-commit-uncrustify" +HOOKS="pre-commit-uncrustify"