1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
#! /usr/bin/env bash
set -eu -o pipefail
FILE=
BASE=
HEAD=HEAD
declare -a args=()
diff_input=false
show_help=false
for opt in "$@" ; do
case "${opt}" in
-h | --help)
show_help=true
;;
-d | --diff)
diff_input=true
;;
-o*)
FILE=${opt#-o}
;;
*)
args+=("${opt}")
;;
esac
done
declare -r diff_input show_help
show_help ()
{
echo "Usage: $0 [-o<file>] [-d|--diff] [<committish> [<committish>]]"
}
if ${show_help} ; then
show_help
exit
fi
if [[ ${#args[@]} -eq 1 ]] ; then
BASE=${args[0]}
elif [[ ${#args[@]} -eq 2 ]] ; then
BASE=${args[0]}
HEAD=${args[1]}
elif [[ ${#args[@]} -eq 0 ]] && ${diff_input} ; then
: no-op
else
show_help 1>&2
exit 1
fi
declare -r BASE HEAD
declare -ra clang_format_diff_candidates=(
# Search in $PATH (Ubuntu, Debian, maybe others)
clang-format-diff-13
clang-format-diff-13.py
clang-format-diff
clang-format-diff.py
# Arch Linux, Fedora.
/usr/share/clang/clang-format-diff.py
)
find_program ()
{
local candidate path
for candidate in "$@" ; do
path=$(type -P "${candidate}")
if [[ -x ${path} ]] ; then
echo "${path}"
return
fi
done
}
clang_format_diff=$(find_program "${clang_format_diff_candidates[@]}")
clang_format=$(find_program clang-format-11 clang-format)
declare -r clang_format_diff clang_format
if [[ ! -x ${clang_format_diff} ]] ; then
echo "$0: clang-format-diff does not seem to be installed" 1>&2
exit 1
fi
if [[ ! -x ${clang_format} ]] ; then
echo "$0: clang-format does not seem to be installed" 1>&2
exit 1
fi
#
# Check the version of clang-format, to make sure that it will support the
# configuration file. The output of "clang-format --version" is formatted
# as follows:
#
# clang-format version X.Y.Z
#
declare -r clang_format_min_version=11
clang_format_version=$("${clang_format}" --version)
if [[ ${clang_format_version} =~ clang-format[[:space:]]+version[[:space:]]+([[:digit:]]+)\. ]] ; then
clang_format_version=${BASH_REMATCH[1]}
if [[ ${clang_format_version} -lt ${clang_format_min_version} ]] ; then
echo "$0: clang-format ${clang_format_min_version}+ is needed, ${clang_format_version} detected" 1>&2
exit 1
fi
else
echo "$0: clang-format did not report its version number"
exit 1
fi
if [[ -z ${FILE} ]] ; then
FILE=$(mktemp)
trap 'rm -f "${FILE}"' EXIT
else
trap '[[ -s ${FILE} ]] || rm -f "${FILE}"' EXIT
fi
declare -a input_cmd
if ${diff_input} ; then
input_cmd=(cat)
else
input_cmd=(git diff --no-color -U0 "${BASE}" "${HEAD}")
fi
"${input_cmd[@]}" \
| "${clang_format_diff}" -p1 -style=file -regex='.+\.(c|h)' \
| tee "${FILE}"
[[ ! -s ${FILE} ]]
|