contrib: fix "nm-code-format.sh" to select files to format

There was always the idea that you could pass paths and filenames
to "nm-code-format.sh" to format only a subset. However, the script
also needs to honor files that should be excluded and don't need
formatting.

Previously, what was implemented via `git ls-files -- ':(exclude)...'`
command, but git-ls-files has a bug ([1]) and might not list all files.

Refactor and do the filtering ourselves.

[1] https://www.spinics.net/lists/git/msg397982.html
This commit is contained in:
Thomas Haller 2021-09-15 21:00:30 +02:00
parent 0ad77d05b9
commit 4c007c4c27
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -7,17 +7,17 @@ die() {
exit 1 exit 1
} }
EXCLUDE=( EXCLUDE_PATHS_TOPLEVEL=(
":(exclude)src/c-list" "src/c-list"
":(exclude)src/c-rbtree" "src/c-rbtree"
":(exclude)src/c-siphash" "src/c-siphash"
":(exclude)src/c-stdaux" "src/c-stdaux"
":(exclude)src/libnm-std-aux/unaligned.h" "src/libnm-std-aux/unaligned.h"
":(exclude)src/libnm-systemd-core/src" "src/libnm-systemd-core/src"
":(exclude)src/libnm-systemd-shared/src" "src/libnm-systemd-shared/src"
":(exclude)src/linux-headers" "src/linux-headers"
":(exclude)src/n-acd" "src/n-acd"
":(exclude)src/n-dhcp4" "src/n-dhcp4"
) )
NM_ROOT="$(git rev-parse --show-toplevel)" || die "not inside a git repository" NM_ROOT="$(git rev-parse --show-toplevel)" || die "not inside a git repository"
@ -32,14 +32,15 @@ if ! command -v clang-format &> /dev/null; then
fi fi
if test -n "$NM_PREFIX"; then if test -n "$NM_PREFIX"; then
_EXCLUDE=() EXCLUDE_PATHS=()
for e in "${EXCLUDE[@]}"; do for e in "${EXCLUDE_PATHS_TOPLEVEL[@]}"; do
REGEX='^:\(exclude\)'"$NM_PREFIX"'([^/].*)$' REGEX="^$NM_PREFIX([^/].*)$"
if [[ "$e" =~ $REGEX ]]; then if [[ "$e" =~ $REGEX ]]; then
_EXCLUDE+=(":(exclude)${BASH_REMATCH[1]}") EXCLUDE_PATHS+=("${BASH_REMATCH[1]}")
fi fi
done done
EXCLUDE=("${_EXCLUDE[@]}") else
EXCLUDE_PATHS=("${EXCLUDE_PATHS_TOPLEVEL[@]}")
fi fi
FILES=() FILES=()
@ -48,7 +49,7 @@ SHOW_FILENAMES=0
TEST_ONLY=1 TEST_ONLY=1
usage() { usage() {
printf "Usage: %s [OPTION]... [FILE]...\n" $(basename $0) printf "Usage: %s [OPTION]... [FILE]...\n" "$(basename "$0")"
printf "Reformat source files using NetworkManager's code-style.\n\n" 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 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 "If no flag is given no file is touch but errors are reported.\n\n"
@ -60,6 +61,24 @@ usage() {
printf " -- Separate options from filenames/directories\n" printf " -- Separate options from filenames/directories\n"
} }
g_ls_files() {
local OLD_IFS="$IFS"
local pattern="$1"
shift
IFS=$'\n'
for f in $(git ls-files -- "$pattern") ; do
local found=1
local p
for p; do
[[ "$f" = "$p/"* ]] && found=
[[ "$f" = "$p" ]] && found=
done
test -n "$found" && printf '%s\n' "$f"
done
IFS="$OLD_IFS"
}
HAD_DASHDASH=0 HAD_DASHDASH=0
while (( $# )); do while (( $# )); do
if [ "$HAD_DASHDASH" = 0 ]; then if [ "$HAD_DASHDASH" = 0 ]; then
@ -91,7 +110,9 @@ while (( $# )); do
esac esac
fi fi
if [ -d "$1" ]; then if [ -d "$1" ]; then
FILES+=( $(git ls-files -- "${1}/*.[hc]" "${EXCLUDE[@]}" ) ) while IFS='' read -r line;
do FILES+=("$line")
done < <(g_ls_files "${1}/*.[hc]" "${EXCLUDE_PATHS[@]}")
elif [ -f "$1" ]; then elif [ -f "$1" ]; then
FILES+=("$1") FILES+=("$1")
else else
@ -104,7 +125,9 @@ while (( $# )); do
done done
if [ $HAS_EXPLICIT_FILES = 0 ]; then if [ $HAS_EXPLICIT_FILES = 0 ]; then
FILES=( $(git ls-files -- '*.[ch]' "${EXCLUDE[@]}") ) while IFS='' read -r line; do
FILES+=("$line")
done < <(g_ls_files '*.[ch]' "${EXCLUDE_PATHS[@]}")
fi fi
if [ $SHOW_FILENAMES = 1 ]; then if [ $SHOW_FILENAMES = 1 ]; then
@ -125,11 +148,11 @@ if [ $TEST_ONLY = 1 ]; then
# Only in case of an error, we iterate over the files one by one # Only in case of an error, we iterate over the files one by one
# until we find the first invalid file. # until we find the first invalid file.
for f in "${FILES[@]}"; do for f in "${FILES[@]}"; do
[ -f $f ] || die "Error: file \"$f\" does not exist (or is not a regular file)" [ -f "$f" ] || die "Error: file \"$f\" does not exist (or is not a regular file)"
done done
clang-format "${FLAGS_TEST[@]}" "${FILES[@]}" &>/dev/null && exit 0 clang-format "${FLAGS_TEST[@]}" "${FILES[@]}" &>/dev/null && exit 0
for f in "${FILES[@]}"; do for f in "${FILES[@]}"; do
[ -f $f ] || die "Error: file \"$f\" does not exist (or is not a regular file)" [ -f "$f" ] || die "Error: file \"$f\" does not exist (or is not a regular file)"
if ! clang-format "${FLAGS_TEST[@]}" "$f" &>/dev/null; then if ! clang-format "${FLAGS_TEST[@]}" "$f" &>/dev/null; then
FF="$(mktemp)" FF="$(mktemp)"
trap 'rm -f "$FF"' EXIT trap 'rm -f "$FF"' EXIT