summaryrefslogtreecommitdiff
path: root/contrib/scripts/nm-code-format.sh
blob: d73cc72f6de9f508242ed655618ca2bdbee60761 (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/bin/bash

set -e

die() {
    printf '%s\n' "$*" >&2
    exit 1
}

EXCLUDE=(
    ":(exclude)src/c-list"
    ":(exclude)src/c-list"
    ":(exclude)src/c-list"
    ":(exclude)src/c-rbtree"
    ":(exclude)src/c-siphash"
    ":(exclude)src/c-stdaux"
    ":(exclude)src/libnm-std-aux/unaligned.h"
    ":(exclude)src/libnm-systemd-shared/src"
    ":(exclude)src/libnm-systemd-core/src"
    ":(exclude)src/n-acd"
    ":(exclude)src/n-dhcp4"
)

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
    die "Error: clang-format is not installed. On RHEL/Fedora/CentOS run 'dnf install clang-tools-extra'"
fi

if test -n "$NM_PREFIX"; then
    _EXCLUDE=()
    for e in "${EXCLUDE[@]}"; do
        REGEX='^:\(exclude\)'"$NM_PREFIX"'([^/].*)$'
        if [[ "$e" =~ $REGEX ]]; then
            _EXCLUDE+=(":(exclude)${BASH_REMATCH[1]}")
        fi
    done
    EXCLUDE=("${_EXCLUDE[@]}")
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

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

if [ "${#FILES[@]}" = 0 ]; then
    die "Error: no files to check"
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[@]}"