#!/usr/bin/env bash
# Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
set -e
set -o pipefail
# trap 'echo ERROR on line: $LINENO running command: $BASH_COMMAND ; trap - EXIT; exit $?' EXIT
# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
# taken from: https://raw.githubusercontent.com/andrewseidl/githook-clang-format/master/clang-format.hook
# - with just added check for cpp file & check for proper version of clang-format
# - with use of clang-format diff.py - for changed chunk changes only
# might be worth to consider: https://github.com/Sarcasm/run-clang-format
# shellcheck source=../config/format-config.sh
# shellcheck source=../config/clang/colors.sh
# shellcheck source=../config/clang/common.sh
L_GIT_DIR=$(git rev-parse --show-toplevel)
source $L_GIT_DIR/config/format-config.sh
source $L_GIT_DIR/config/clang/colors.sh
source $L_GIT_DIR/config/clang/clang-common.sh
CHANGE_TARGET=${CHANGE_TARGET:-master}
# if autoformatting was disabled by user - then ignore this commit hook
if [ "$DISABLE_AUTO_FORMATTING" -eq 1 ]; then
[[ $VERBOSE ]] && echo "auto formatting is disabled"
exit 0
fi
verify_clang_format_version
L_CLANG_TOOL=$(get_clang_format)
if ! [[ $L_CLANG_TOOL ]] || [[ $L_CLANG_TOOL == "" ]]; then
[[ $VERBOSE ]] && echo "clang-format not found"
exit 1
fi
L_CLANG_DIFF_TOOL=$(get_clang_format_diff)
if ! [[ $L_CLANG_DIFF_TOOL ]] || [[ $L_CLANG_DIFF_TOOL == "" ]]; then
[[ $VERBOSE ]] && echo "clang-format-diff not found"
exit 1
fi
check_file() {
file="${1}"
last_commit="${2}"
if [ -f "${file}" ]; then
#[[ $VERBOSE ]] && echo -en "Checking: \e[33m${file}\e[0m :\t"
results["${file}"]="${OK}"
case ${last_commit} in
"True")
if [[ ${FIX,,} == "true" ]]; then
git diff -U0 --no-color remotes/origin/"${CHANGE_TARGET}"...HEAD "${file}" | ${L_CLANG_DIFF_TOOL} -style file -p1 -i
STATUS=$(git status --short -- "${file}")
if [ -n "${STATUS}" ]; then
git add "${file}"
results["${file}"]="${FIXED}";
fi
else
OUT=$(git diff -U0 --no-color remotes/origin/"${CHANGE_TARGET}"...HEAD "${file}" | ${L_CLANG_DIFF_TOOL} -style file -p1 )
if [ -n "${OUT}" ]; then
results["${file}"]="${ERROR}"
return 1
fi
fi
;;
"Stage")
if [[ ${FIX,,} == "true" ]]; then
git diff -U0 --no-color --cached "${file}" | ${L_CLANG_DIFF_TOOL} -style file -p1 -i
STATUS=$(git status --short -- "${file}")
if [ -n "${STATUS}" ]; then
git add "${file}"
results["${file}"]="${FIXED}";
fi
else
OUT=$(git diff -U0 --no-color --cached "${file}" | ${L_CLANG_DIFF_TOOL} -style file -p1)
if [ -n "${OUT}" ]; then
results["${file}"]="${ERROR}"
return 1
fi
fi
;;
"All")
if [[ ${FIX,,} == "true" ]]; then
${L_CLANG_TOOL} -style file -i ${file}
STATUS=$(git status --short -- "${file}")
if [ -n "${STATUS}" ]; then
git add "${file}"
results["${file}"]="${FIXED}";
fi
else
OUT=$(${L_CLANG_TOOL} -style file ${file})
if [ -n "${OUT}" ]; then
results["${file}"]="${ERROR}"
return 1
fi
fi
;;
*)
OUT=$(git diff -U0 --no-color --cached "${file}" | ${L_CLANG_DIFF_TOOL} -style file -p1 )
if [[ -n ${OUT} ]]; then
results["${file}"]="${ERROR}"
return 1
fi
;;
esac
fi
return 0
}
function help() {
echo "Runs clang-format on source files"
cat <<- EOM
usage:
$0 [option]
--about does nothing
--last checks current branch against origin/master - doesn't fix
--branch-fix checks current branch against origin/master and fixes errors - you have to 'git add' and 'git commit' them
--fix fix style in currently staged files (ignores user.fixinstage variale), this is usefull for manual style applying
--all check style in all files
--fix-all fix style in all files
If you would like to automatically fix style before commit
add to your git config "user.fixinstage" variable with value "True"
by calling:
git config user.fixinstage True
EOM
}
case "${1}" in
--about|--help )
help
FILES=''
LAST=""
exit 0
;;
--last)
FILES=$(git diff --name-only remotes/origin/"${CHANGE_TARGET}"...HEAD)
LAST="True"
FIX="false"
;;
--branch-fix)
FILES=$(git diff --name-only remotes/origin/"${CHANGE_TARGET}"...HEAD)
LAST="True"
FIX="true"
;;
--fix)
FILES=$(git diff-index --cached --name-only HEAD)
LAST="Stage"
FIX="true"
;;
--all)
FILES=$(find $L_GIT_DIR -type f -name '*.cpp' -o -name '*.hpp' -o -name '*.c' -o -name '*.h' -o -name '*.cxx' -o -name '*.gcc' -o -name '*.cc')
LAST="All"
FIX="false"
;;
--fix-all)
FILES=$(find $L_GIT_DIR -type f -name '*.cpp' -o -name '*.hpp' -o -name '*.c' -o -name '*.h' -o -name '*.cxx' -o -name '*.gcc' -o -name '*.cc')
LAST="All"
FIX="true"
;;
*)
if [[ $# -ne 0 ]]; then
echo "unknown parameters: '$*'"
help
exit 1
fi
FILES=$(git diff-index --cached --name-only HEAD)
LAST="Stage"
FIX=$([[ $(git config user.fixinstage) ]] && git config user.fixinstage || echo "false")
FIX=${FIX:-false}
;;
esac
declare -A results
EXIT_CODE=0
for file in ${FILES}; do
if [[ ${file} =~ ^.*\.(cpp|hpp|c|h|cxx|gcc|cc)$ ]] && shouldnt_ignore ${file}; then
check_file "${file}" ${LAST} || RESULT=$?
if [[ ${RESULT} -eq 1 ]]; then
EXIT_CODE=1
fi
fi
done
for FILE in "${!results[@]}"
do
echo -e " ${FILE} : ${results[${FILE}]}"
done
echo "exit: ${EXIT_CODE}"
exit ${EXIT_CODE}