xref: /spdk/scripts/check_format.sh (revision 552e21cce6cccbf833ed9109827e08337377d7ce)
1#!/usr/bin/env bash
2
3readonly BASEDIR=$(readlink -f $(dirname $0))/..
4cd $BASEDIR
5
6# exit on errors
7set -e
8
9if ! hash nproc 2>/dev/null; then
10
11function nproc() {
12	echo 8
13}
14
15fi
16
17rc=0
18
19echo -n "Checking file permissions..."
20
21while read -r perm _res0 _res1 path; do
22	if [ ! -f "$path" ]; then
23		continue
24	fi
25
26	fname=$(basename -- "$path")
27
28	case ${fname##*.} in
29		c|h|cpp|cc|cxx|hh|hpp|md|html|js|json|svg|Doxyfile|yml|LICENSE|README|conf|in|Makefile|mk|gitignore|go|txt)
30			# These file types should never be executable
31			if [ "$perm" -eq 100755 ]; then
32				echo "ERROR: $path is marked executable but is a code file."
33				rc=1
34			fi
35		;;
36		*)
37			shebang=$(head -n 1 $path | cut -c1-3)
38
39			# git only tracks the execute bit, so will only ever return 755 or 644 as the permission.
40			if [ "$perm" -eq 100755 ]; then
41				# If the file has execute permission, it should start with a shebang.
42				if [ "$shebang" != "#!/" ]; then
43					echo "ERROR: $path is marked executable but does not start with a shebang."
44					rc=1
45				fi
46			else
47				# If the file doesnot have execute permissions, it should not start with a shebang.
48				if [ "$shebang" = "#!/" ]; then
49					echo "ERROR: $path is not marked executable but starts with a shebang."
50					rc=1
51				fi
52			fi
53		;;
54	esac
55
56done <<< "$(git grep -I --name-only --untracked -e . | git ls-files -s)"
57
58if [ $rc -eq 0 ]; then
59	echo " OK"
60fi
61
62if hash astyle; then
63	echo -n "Checking coding style..."
64	if [ "$(astyle -V)" \< "Artistic Style Version 3" ]
65	then
66		echo -n " Your astyle version is too old so skipping coding style checks. Please update astyle to at least 3.0.1 version..."
67	else
68		rm -f astyle.log
69		touch astyle.log
70		# Exclude rte_vhost code imported from DPDK - we want to keep the original code
71		#  as-is to enable ongoing work to synch with a generic upstream DPDK vhost library,
72		#  rather than making diffs more complicated by a lot of changes to follow SPDK
73		#  coding standards.
74		git ls-files '*.[ch]' '*.cpp' '*.cc' '*.cxx' '*.hh' '*.hpp' | \
75			grep -v rte_vhost | grep -v cpp_headers | \
76			xargs -P$(nproc) -n10 astyle --options=.astylerc >> astyle.log
77		if grep -q "^Formatted" astyle.log; then
78			echo " errors detected"
79			git diff
80			sed -i -e 's/  / /g' astyle.log
81			grep --color=auto "^Formatted.*" astyle.log
82			echo "Incorrect code style detected in one or more files."
83			echo "The files have been automatically formatted."
84			echo "Remember to add the files to your commit."
85			rc=1
86		else
87			echo " OK"
88		fi
89		rm -f astyle.log
90	fi
91else
92	echo "You do not have astyle installed so your code style is not being checked!"
93fi
94
95echo -n "Checking comment style..."
96
97git grep --line-number -e '/[*][^ *-]' -- '*.[ch]' > comment.log || true
98git grep --line-number -e '[^ ][*]/' -- '*.[ch]' ':!lib/vhost/rte_vhost*/*' >> comment.log || true
99git grep --line-number -e '^[*]' -- '*.[ch]' >> comment.log || true
100git grep --line-number -e '\s//' -- '*.[ch]' >> comment.log || true
101git grep --line-number -e '^//' -- '*.[ch]' >> comment.log || true
102
103if [ -s comment.log ]; then
104	echo " Incorrect comment formatting detected"
105	cat comment.log
106	rc=1
107else
108	echo " OK"
109fi
110rm -f comment.log
111
112echo -n "Checking for spaces before tabs..."
113git grep --line-number $' \t' -- > whitespace.log || true
114if [ -s whitespace.log ]; then
115	echo " Spaces before tabs detected"
116	cat whitespace.log
117	rc=1
118else
119	echo " OK"
120fi
121rm -f whitespace.log
122
123echo -n "Checking trailing whitespace in output strings..."
124
125git grep --line-number -e ' \\n"' -- '*.[ch]' > whitespace.log || true
126
127if [ -s whitespace.log ]; then
128	echo " Incorrect trailing whitespace detected"
129	cat whitespace.log
130	rc=1
131else
132	echo " OK"
133fi
134rm -f whitespace.log
135
136echo -n "Checking for use of forbidden library functions..."
137
138git grep --line-number -w '\(strncpy\|strcpy\|strcat\|sprintf\|vsprintf\)' -- './*.c' ':!lib/vhost/rte_vhost*/**' > badfunc.log || true
139if [ -s badfunc.log ]; then
140	echo " Forbidden library functions detected"
141	cat badfunc.log
142	rc=1
143else
144	echo " OK"
145fi
146rm -f badfunc.log
147
148echo -n "Checking for use of forbidden CUnit macros..."
149
150git grep --line-number -w 'CU_ASSERT_FATAL' -- 'test/*' ':!test/spdk_cunit.h' > badcunit.log || true
151if [ -s badcunit.log ]; then
152	echo " Forbidden CU_ASSERT_FATAL usage detected - use SPDK_CU_ASSERT_FATAL instead"
153	cat badcunit.log
154	rc=1
155else
156	echo " OK"
157fi
158rm -f badcunit.log
159
160echo -n "Checking blank lines at end of file..."
161
162if ! git grep -I -l -e . -z | \
163	xargs -0 -P$(nproc) -n1 scripts/eofnl > eofnl.log; then
164	echo " Incorrect end-of-file formatting detected"
165	cat eofnl.log
166	rc=1
167else
168	echo " OK"
169fi
170rm -f eofnl.log
171
172echo -n "Checking for POSIX includes..."
173git grep -I -i -f scripts/posix.txt -- './*' ':!include/spdk/stdinc.h' ':!include/linux/**' ':!lib/vhost/rte_vhost*/**' ':!scripts/posix.txt' > scripts/posix.log || true
174if [ -s scripts/posix.log ]; then
175	echo "POSIX includes detected. Please include spdk/stdinc.h instead."
176	cat scripts/posix.log
177	rc=1
178else
179	echo " OK"
180fi
181rm -f scripts/posix.log
182
183echo -n "Checking #include style..."
184git grep -I -i --line-number "#include <spdk/" -- '*.[ch]' > scripts/includes.log || true
185if [ -s scripts/includes.log ]; then
186	echo "Incorrect #include syntax. #includes of spdk/ files should use quotes."
187	cat scripts/includes.log
188	rc=1
189else
190	echo " OK"
191fi
192rm -f scripts/includes.log
193
194if hash pycodestyle 2>/dev/null; then
195	PEP8=pycodestyle
196elif hash pep8 2>/dev/null; then
197	PEP8=pep8
198fi
199
200if [ ! -z ${PEP8} ]; then
201	echo -n "Checking Python style..."
202
203	PEP8_ARGS+=" --max-line-length=140"
204
205	error=0
206	git ls-files '*.py' | xargs -P$(nproc) -n1 $PEP8 $PEP8_ARGS > pep8.log || error=1
207	if [ $error -ne 0 ]; then
208		echo " Python formatting errors detected"
209		cat pep8.log
210		rc=1
211	else
212		echo " OK"
213	fi
214	rm -f pep8.log
215else
216	echo "You do not have pycodestyle or pep8 installed so your Python style is not being checked!"
217fi
218
219# Check if any of the public interfaces were modified by this patch.
220# Warn the user to consider updating the changelog any changes
221# are detected.
222echo -n "Checking whether CHANGELOG.md should be updated..."
223staged=$(git diff --name-only --cached .)
224working=$(git status -s --porcelain --ignore-submodules | grep -iv "??" | awk '{print $2}')
225files="$staged $working"
226if [[ "$files" = " " ]]; then
227	files=$(git diff-tree --no-commit-id --name-only -r HEAD)
228fi
229
230has_changelog=0
231for f in $files; do
232	if [[ $f == CHANGELOG.md ]]; then
233		# The user has a changelog entry, so exit.
234		has_changelog=1
235		break
236	fi
237done
238
239needs_changelog=0
240if [ $has_changelog -eq 0 ]; then
241	for f in $files; do
242		if [[ $f == include/spdk/* ]] || [[ $f == scripts/rpc.py ]] || [[ $f == etc/* ]]; then
243			echo ""
244			echo -n "$f was modified. Consider updating CHANGELOG.md."
245			needs_changelog=1
246		fi
247	done
248fi
249
250if [ $needs_changelog -eq 0 ]; then
251	echo " OK"
252else
253	echo ""
254fi
255
256exit $rc
257