-
Notifications
You must be signed in to change notification settings - Fork 393
/
format_code.sh
executable file
·158 lines (136 loc) · 4.64 KB
/
format_code.sh
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
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail
IFS=$'\n\t'
# Bash script to automatically format LCM source code (currently C and C++).
# Requires `clang-format-15` utility, which is part of the LLVM project. More
# information can be found here: https://clang.llvm.org/docs/ClangFormat.html
#
# To install `clang-format-15` on Ubuntu do:
#
# $ sudo apt install clang-format-15
#
# This script does not format Java, Python, or Lua source code. At the moment,
# it only formats C and C++ sources, i.e., *.h, *.c, *.hpp, and *.cpp. It only
# formats code in certain directories, see below for the full list.
LCM_ROOT="$(cd $(dirname "$0") && pwd)"
# Define which directories should be formatted, with an optional list of
# exceptions as regex. Format is: `dir:regex1:regex2:...`
LCM_FORMAT_DIRS=(
"${LCM_ROOT}/examples"
"${LCM_ROOT}/lcm:/lcmtypes/"
"${LCM_ROOT}/lcmgen"
"${LCM_ROOT}/lcm-lite"
"${LCM_ROOT}/lcm-logger"
"${LCM_ROOT}/lcm-lua"
"${LCM_ROOT}/lcm-python"
"${LCM_ROOT}/liblcm-test"
"${LCM_ROOT}/test:/gtest/"
)
CLANG_FORMAT="clang-format-15"
# Function: show_usage
#
# Shows usage of this script.
function show_usage {
cat <<EOF 1>&2
Usage: $(basename "$0") [-c | --check]
Formats source code for C (*.h, *.c), C++ (*.hpp, *.cpp), etc.
-c | --check Do not format, only check existing formatting
-h | --help Display this help message
EOF
}
# Function: format_c_cpp_dir_r DIR [EXCUDE_PATTERN...]
#
# Formats all C and C++ sources in a directory recursively. DIR is the source
# directory for the recursive formatting. The optional EXCLUDE_PATTERN is an
# Extended Regex matched against each file path, where the file is excluded from
# formatting if it matches. There can be multiple exclude patterns.
function format_c_cpp_dir_r {
include_dir="$1"
exclude_patterns=("${@:2}")
if [ "${#exclude_patterns[@]}" -eq 0 ]; then
# Use an empty pattern to not match anything
exclude_patterns="^$"
fi
exclude_pattern_opts=""
for exclude_pattern in "${exclude_patterns[@]}"; do
exclude_pattern_opts="${exclude_pattern_opts} -e \"${exclude_pattern}\" "
done
find "$1" -regex '.*\.\(c\|h\)\(pp\)?' \
| eval "grep -E -v" "${exclude_pattern_opts}" \
| xargs $CLANG_FORMAT -i
}
# Function: check_format_c_cpp_dir_r DIR [EXCUDE_PATTERN...]
#
# Checks format of all C and C++ sources in a directory recursively. DIR is the
# source directory for the recursive formatting. The optional EXCLUDE_PATTERN is
# an Extended Regex matched against each file path, where the file is excluded
# from formatting if it matches. There can be multiple exclude patterns.
#
# This function will return 0 if all code is formatted, and 1 otherwise.
function check_format_c_cpp_dir_r {
include_dir="$1"
exclude_patterns=("${@:2}")
if [ "${#exclude_patterns[@]}" -eq 0 ]; then
# Use an empty pattern to not match anything
exclude_patterns="^$"
fi
exclude_pattern_opts=""
for exclude_pattern in "${exclude_patterns[@]}"; do
exclude_pattern_opts="${exclude_pattern_opts} -e \"${exclude_pattern}\" "
done
find "$1" -regex '.*\.\(c\|h\)\(pp\)?' \
| eval "grep -E -v" "${exclude_pattern_opts}" \
| xargs $CLANG_FORMAT --dry-run --Werror --ferror-limit=1 &>/dev/null
}
# Default option values
check_mode=0
# Convert long options to short options, preserving order
for arg in "${@}"; do
case "${arg}" in
"--check" ) set -- "${@}" "-c" ;;
"--help" ) set -- "${@}" "-h" ;;
* ) set -- "${@}" "${arg}" ;;
esac
shift
done
# Parse short options using getopts
while getopts "ch" arg &>/dev/null; do
case "${arg}" in
"c" ) check_mode=1 ;;
"h" ) show_usage ; exit 0 ;;
"?" ) show_usage ; exit 1 ;;
esac
done
# Check for $CLANG_FORMAT
if ! command -v $CLANG_FORMAT &>/dev/null; then
echo "ERROR: Can not find $CLANG_FORMAT!" 1>&2
echo "Please add $CLANG_FORMAT to your PATH" 1>&2
echo "On Ubuntu, install it with: sudo apt install $CLANG_FORMAT" 1>&2
exit 1
fi
# Determine which function to run
func="format_c_cpp_dir_r"
if [ ${check_mode} -ne 0 ]; then
func="check_format_c_cpp_dir_r"
fi
# Run the function for all directories
error_code=0
for entry in "${LCM_FORMAT_DIRS[@]}"; do
IFS=":" read -r -a args <<< "${entry}"
if ! eval "${func}" "${args[@]}"; then
error_code=1
break
fi
done
# Show check results
if [ ${check_mode} -ne 0 ]; then
if [ ${error_code} -eq 0 ]; then
echo "FORMATTING OK!"
else
echo "UNFORMATTED FILES!"
echo "Please run the formatting script: ./format_code.sh"
fi
fi
exit ${error_code}