contrib: improve nm-code-format.sh script
- accept directory names in the command line. In that case, still honor the excluded files. That is a major improvement for me, because I usually only want to reformat a directory that I know has changed and it is fast to only process some directories. - pass all files at once to clang-format. For me that gives a significant speed improvement (about 3 times faster), although clang-format is only single threaded. Possibly clang-format could even be faster by checking files in parallel. In case of a style error, the script still falls back to iterate over all files to find the first bad file and print the full diff. But that is considered an unusual case. - make it correctly work from calling it from a subdirectory. In that case, we only check files inside that directory -- but still correctly honor the excluded files.
This commit is contained in:
@@ -2,74 +2,140 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
while (( $# )); do
|
die() {
|
||||||
case $1 in
|
printf '%s\n' "$*" >&2
|
||||||
-i)
|
exit 1
|
||||||
FLAGS="-i"
|
}
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h)
|
|
||||||
printf "Usage: %s [OPTION]... [FILE]...\n" $(basename $0)
|
|
||||||
printf "Reformat source files using NetworkManager's code-style.\n\n"
|
|
||||||
printf "If no file is given the script runs on the whole codebase.\n"
|
|
||||||
printf "If no flag is given no file is touch but errors are reported.\n\n"
|
|
||||||
printf "OPTIONS:\n"
|
|
||||||
printf " -i Reformat files\n"
|
|
||||||
printf " -h Print this help message\n"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
FILES+=($1)
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
NM_ROOT=$(git rev-parse --show-toplevel)
|
EXCLUDE=(
|
||||||
EXCLUDE="
|
":(exclude)shared/c-list"
|
||||||
:(exclude)shared/c-list
|
":(exclude)shared/c-list"
|
||||||
:(exclude)shared/c-list
|
":(exclude)shared/c-list"
|
||||||
:(exclude)shared/c-list
|
":(exclude)shared/c-rbtree"
|
||||||
:(exclude)shared/c-rbtree
|
":(exclude)shared/c-siphash"
|
||||||
:(exclude)shared/c-siphash
|
":(exclude)shared/c-stdaux"
|
||||||
:(exclude)shared/c-stdaux
|
":(exclude)shared/n-acd"
|
||||||
:(exclude)shared/n-acd
|
":(exclude)shared/n-dhcp4"
|
||||||
:(exclude)shared/n-dhcp4
|
":(exclude)shared/nm-std-aux/unaligned.h"
|
||||||
:(exclude)shared/nm-std-aux/unaligned.h
|
":(exclude)shared/systemd/src"
|
||||||
:(exclude)shared/systemd/src
|
":(exclude)src/systemd/src"
|
||||||
:(exclude)src/systemd/src
|
)
|
||||||
"
|
|
||||||
|
NM_ROOT="$(git rev-parse --show-toplevel)" || die "not inside a git repository"
|
||||||
|
NM_PREFIX="$(git rev-parse --show-prefix)" || die "not inside a git repository"
|
||||||
|
|
||||||
|
if [ ! -f "$NM_ROOT/.clang-format" ]; then
|
||||||
|
die "Error: the clang-format file in \"$NM_ROOT\" does not exist"
|
||||||
|
fi
|
||||||
|
|
||||||
if ! command -v clang-format &> /dev/null; then
|
if ! command -v clang-format &> /dev/null; then
|
||||||
echo -n "Error: clang-format is not installed, "
|
die "Error: clang-format is not installed. On RHEL/Fedora/CentOS run 'dnf install clang-tools-extra'"
|
||||||
echo "on RHEL/Fedora/CentOS run 'dnf install clang-tools-extra'"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f ${NM_ROOT}/.clang-format ]; then
|
if test -n "$NM_PREFIX"; then
|
||||||
echo "Error: the clang-format file does not exist"
|
_EXCLUDE=()
|
||||||
exit 1
|
for e in "${EXCLUDE[@]}"; do
|
||||||
fi
|
REGEX='^:\(exclude\)'"$NM_PREFIX"'([^/].*)$'
|
||||||
|
if [[ "$e" =~ $REGEX ]]; then
|
||||||
|
_EXCLUDE+=(":(exclude)${BASH_REMATCH[1]}")
|
||||||
FLAGS=${FLAGS:-"--Werror -n --ferror-limit=1"}
|
|
||||||
|
|
||||||
if [ -z "${FILES[@]}" ]; then
|
|
||||||
cd $NM_ROOT
|
|
||||||
FILES=($(git ls-files --full-name -- '*.[ch]' ${EXCLUDE}))
|
|
||||||
fi
|
|
||||||
|
|
||||||
for f in "${FILES[@]}"; do
|
|
||||||
if [ -f $f ]; then
|
|
||||||
if ! clang-format $FLAGS $f &> /dev/null; then
|
|
||||||
TMP_FILE=$(mktemp)
|
|
||||||
clang-format $f > $TMP_FILE
|
|
||||||
git --no-pager diff $f $TMP_FILE || true
|
|
||||||
rm $TMP_FILE
|
|
||||||
echo "Error: $(basename $f) code-style is wrong, fix it by running '$0 -i $f)"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
else
|
done
|
||||||
echo "Error: $f No such file"
|
EXCLUDE=("${_EXCLUDE[@]}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
FILES=()
|
||||||
|
HAS_EXPLICIT_FILES=0
|
||||||
|
SHOW_FILENAMES=0
|
||||||
|
TEST_ONLY=1
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
printf "Usage: %s [OPTION]... [FILE]...\n" $(basename $0)
|
||||||
|
printf "Reformat source files using NetworkManager's code-style.\n\n"
|
||||||
|
printf "If no file is given the script runs on the whole codebase.\n"
|
||||||
|
printf "If no flag is given no file is touch but errors are reported.\n\n"
|
||||||
|
printf "OPTIONS:\n"
|
||||||
|
printf " -i Reformat files\n"
|
||||||
|
printf " -n Only check the files (this is the default)\n"
|
||||||
|
printf " -h Print this help message\n"
|
||||||
|
printf " --show-filenames Only print the filenames that would be checked\n"
|
||||||
|
printf " -- Separate options from filenames/directories\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
HAD_DASHDASH=0
|
||||||
|
while (( $# )); do
|
||||||
|
if [ "$HAD_DASHDASH" = 0 ]; then
|
||||||
|
case "$1" in
|
||||||
|
-h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--show-filenames)
|
||||||
|
SHOW_FILENAMES=1
|
||||||
|
shift
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
-n)
|
||||||
|
TEST_ONLY=1
|
||||||
|
shift
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
-i)
|
||||||
|
TEST_ONLY=0
|
||||||
|
shift
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
HAD_DASHDASH=1
|
||||||
|
shift
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
if [ -d "$1" ]; then
|
||||||
|
FILES+=( $(git ls-files -- "${1}/*.[hc]" "${EXCLUDE[@]}" ) )
|
||||||
|
elif [ -f "$1" ]; then
|
||||||
|
FILES+=("$1")
|
||||||
|
else
|
||||||
|
usage >&2
|
||||||
|
echo >&2
|
||||||
|
die "Unknown argument \"$1\" which also is neither a file nor a directory."
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
HAS_EXPLICIT_FILES=1
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [ $HAS_EXPLICIT_FILES = 0 ]; then
|
||||||
|
FILES=( $(git ls-files -- '*.[ch]' "${EXCLUDE[@]}") )
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $SHOW_FILENAMES = 1 ]; then
|
||||||
|
printf '%s\n' "${FILES[@]}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
FLAGS_TEST=( --Werror -n --ferror-limit=1 )
|
||||||
|
|
||||||
|
if [ $TEST_ONLY = 1 ]; then
|
||||||
|
# We assume that all formatting is correct. In that mode, passing
|
||||||
|
# all filenames to clang-format is significantly faster.
|
||||||
|
#
|
||||||
|
# Only in case of an error, we iterate over the files one by one
|
||||||
|
# until we find the first invalid file.
|
||||||
|
for f in "${FILES[@]}"; do
|
||||||
|
[ -f $f ] || die "Error: file \"$f\" does not exist (or is not a regular file)"
|
||||||
|
done
|
||||||
|
clang-format "${FLAGS_TEST[@]}" "${FILES[@]}" &>/dev/null && exit 0
|
||||||
|
for f in "${FILES[@]}"; do
|
||||||
|
[ -f $f ] || die "Error: file \"$f\" does not exist (or is not a regular file)"
|
||||||
|
if ! clang-format "${FLAGS_TEST[@]}" "$f" &>/dev/null; then
|
||||||
|
FF="$(mktemp)"
|
||||||
|
trap 'rm -f "$FF"' EXIT
|
||||||
|
clang-format "$f" 2>/dev/null > "$FF"
|
||||||
|
git --no-pager diff "$f" "$FF" || :
|
||||||
|
die "Error: file \"$f\" has code-style is wrong. Fix it by running "'`'"\"$0\" -i \"$f\""'`'
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
die "an unknown error happened."
|
||||||
|
fi
|
||||||
|
|
||||||
|
clang-format -i "${FILES[@]}"
|
||||||
|
Reference in New Issue
Block a user