xref: /spdk/scripts/check_format.sh (revision 877573897ad52be4fa8989f7617bd655b87e05c4)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2015 Intel Corporation
4#  All rights reserved.
5#
6if [[ $(uname -s) == Darwin ]]; then
7	# SPDK is not supported on MacOS, but as a developer
8	# convenience we support running the check_format.sh
9	# script on MacOS.
10	# Running "brew install bash coreutils grep" should be
11	# sufficient to get the correct versions of these utilities.
12	if [[ $(type -t mapfile) != builtin ]]; then
13		# We need bash version >= 4.0 for mapfile builtin
14		echo "Please install bash version >= 4.0"
15		exit 1
16	fi
17	if ! hash greadlink 2> /dev/null; then
18		# We need GNU readlink for -f option
19		echo "Please install GNU readlink"
20		exit 1
21	fi
22	if ! hash ggrep 2> /dev/null; then
23		# We need GNU grep for -P option
24		echo "Please install GNU grep"
25		exit 1
26	fi
27	GNU_READLINK="greadlink"
28	GNU_GREP="ggrep"
29else
30	GNU_READLINK="readlink"
31	GNU_GREP="grep"
32fi
33
34rootdir=$($GNU_READLINK -f "$(dirname "$0")")/..
35source "$rootdir/scripts/common.sh"
36
37cd "$rootdir"
38
39# exit on errors
40set -e
41
42if ! hash nproc 2> /dev/null; then
43
44	function nproc() {
45		echo 8
46	}
47
48fi
49
50function version_lt() {
51	[ $(echo -e "$1\n$2" | sort -V | head -1) != "$1" ]
52}
53
54function array_contains_string() {
55	name="$1[@]"
56	array=("${!name}")
57
58	for element in "${array[@]}"; do
59		if [ "$element" = "$2" ]; then
60			return $(true)
61		fi
62	done
63
64	return $(false)
65}
66
67rc=0
68
69function check_permissions() {
70	echo -n "Checking file permissions..."
71
72	local rc=0
73
74	while read -r perm _res0 _res1 path; do
75		if [ ! -f "$path" ]; then
76			continue
77		fi
78
79		# Skip symlinks
80		if [[ -L $path ]]; then
81			continue
82		fi
83		fname=$(basename -- "$path")
84
85		case ${fname##*.} in
86			c | h | cpp | cc | cxx | hh | hpp | md | html | js | json | svg | Doxyfile | yml | LICENSE | README | conf | in | Makefile | mk | gitignore | go | txt)
87				# These file types should never be executable
88				if [ "$perm" -eq 100755 ]; then
89					echo "ERROR: $path is marked executable but is a code file."
90					rc=1
91				fi
92				;;
93			*)
94				shebang=$(head -n 1 $path | cut -c1-3)
95
96				# git only tracks the execute bit, so will only ever return 755 or 644 as the permission.
97				if [ "$perm" -eq 100755 ]; then
98					# If the file has execute permission, it should start with a shebang.
99					if [ "$shebang" != "#!/" ]; then
100						echo "ERROR: $path is marked executable but does not start with a shebang."
101						rc=1
102					fi
103				else
104					# If the file does not have execute permissions, it should not start with a shebang.
105					if [ "$shebang" = "#!/" ]; then
106						echo "ERROR: $path is not marked executable but starts with a shebang."
107						rc=1
108					fi
109				fi
110				;;
111		esac
112
113	done <<< "$(git grep -I --name-only --untracked -e . | git ls-files -s)"
114
115	if [ $rc -eq 0 ]; then
116		echo " OK"
117	fi
118
119	return $rc
120}
121
122function check_c_style() {
123	local rc=0
124
125	if hash astyle; then
126		echo -n "Checking coding style..."
127		if [ "$(astyle -V)" \< "Artistic Style Version 3" ]; then
128			echo -n " Your astyle version is too old so skipping coding style checks. Please update astyle to at least 3.0.1 version..."
129		else
130			rm -f astyle.log
131			touch astyle.log
132			# Exclude DPDK header files copied into our tree
133			git ls-files '*.[ch]' ':!:*/env_dpdk/*/*.h' \
134				| xargs -P$(nproc) -n10 astyle --break-return-type --attach-return-type-decl \
135					--options=.astylerc >> astyle.log
136			git ls-files '*.cpp' '*.cc' '*.cxx' '*.hh' '*.hpp' \
137				| xargs -P$(nproc) -n10 astyle --options=.astylerc >> astyle.log
138			if grep -q "^Formatted" astyle.log; then
139				echo " errors detected"
140				git diff --ignore-submodules=all
141				sed -i -e 's/  / /g' astyle.log
142				grep --color=auto "^Formatted.*" astyle.log
143				echo "Incorrect code style detected in one or more files."
144				echo "The files have been automatically formatted."
145				echo "Remember to add the files to your commit."
146				rc=1
147			else
148				echo " OK"
149			fi
150			rm -f astyle.log
151		fi
152	else
153		echo "You do not have astyle installed so your code style is not being checked!"
154	fi
155	return $rc
156}
157
158function check_comment_style() {
159	local rc=0
160
161	echo -n "Checking comment style..."
162
163	git grep --line-number -e '\/[*][^ *-]' -- '*.[ch]' > comment.log || true
164	git grep --line-number -e '[^ ][*]\/' -- '*.[ch]' ':!lib/rte_vhost*/*' >> comment.log || true
165	git grep --line-number -e '^[*]' -- '*.[ch]' >> comment.log || true
166	git grep --line-number -e '\s\/\/' -- '*.[ch]' >> comment.log || true
167	git grep --line-number -e '^\/\/' -- '*.[ch]' >> comment.log || true
168
169	if [ -s comment.log ]; then
170		echo " Incorrect comment formatting detected"
171		cat comment.log
172		rc=1
173	else
174		echo " OK"
175	fi
176	rm -f comment.log
177
178	return $rc
179}
180
181function check_spaces_before_tabs() {
182	local rc=0
183
184	echo -n "Checking for spaces before tabs..."
185	git grep --line-number $' \t' -- './*' ':!*.patch' > whitespace.log || true
186	if [ -s whitespace.log ]; then
187		echo " Spaces before tabs detected"
188		cat whitespace.log
189		rc=1
190	else
191		echo " OK"
192	fi
193	rm -f whitespace.log
194
195	return $rc
196}
197
198function check_trailing_whitespace() {
199	local rc=0
200
201	echo -n "Checking trailing whitespace in output strings..."
202
203	git grep --line-number -e ' \\n"' -- '*.[ch]' > whitespace.log || true
204
205	if [ -s whitespace.log ]; then
206		echo " Incorrect trailing whitespace detected"
207		cat whitespace.log
208		rc=1
209	else
210		echo " OK"
211	fi
212	rm -f whitespace.log
213
214	return $rc
215}
216
217function check_forbidden_functions() {
218	local rc=0
219
220	echo -n "Checking for use of forbidden library functions..."
221
222	git grep --line-number -w '\(atoi\|atol\|atoll\|strncpy\|strcpy\|strcat\|sprintf\|vsprintf\)' -- './*.c' ':!lib/rte_vhost*/**' > badfunc.log || true
223	if [ -s badfunc.log ]; then
224		echo " Forbidden library functions detected"
225		cat badfunc.log
226		rc=1
227	else
228		echo " OK"
229	fi
230	rm -f badfunc.log
231
232	return $rc
233}
234
235function check_cunit_style() {
236	local rc=0
237
238	echo -n "Checking for use of forbidden CUnit macros..."
239
240	git grep --line-number -w 'CU_ASSERT_FATAL' -- 'test/*' ':!test/spdk_cunit.h' > badcunit.log || true
241	if [ -s badcunit.log ]; then
242		echo " Forbidden CU_ASSERT_FATAL usage detected - use SPDK_CU_ASSERT_FATAL instead"
243		cat badcunit.log
244		rc=1
245	else
246		echo " OK"
247	fi
248	rm -f badcunit.log
249
250	return $rc
251}
252
253function check_eof() {
254	local rc=0
255
256	echo -n "Checking blank lines at end of file..."
257
258	if ! git grep -I -l -e . -z './*' ':!*.patch' \
259		| xargs -0 -P$(nproc) -n1 scripts/eofnl > eofnl.log; then
260		echo " Incorrect end-of-file formatting detected"
261		cat eofnl.log
262		rc=1
263	else
264		echo " OK"
265	fi
266	rm -f eofnl.log
267
268	return $rc
269}
270
271function check_posix_includes() {
272	local rc=0
273
274	echo -n "Checking for POSIX includes..."
275	git grep -I -i -f scripts/posix.txt -- './*' ':!include/spdk/stdinc.h' \
276		':!include/linux/**' ':!scripts/posix.txt' ':!lib/env_dpdk/*/*.h' \
277		':!*.patch' ':!configure' > scripts/posix.log || true
278	if [ -s scripts/posix.log ]; then
279		echo "POSIX includes detected. Please include spdk/stdinc.h instead."
280		cat scripts/posix.log
281		rc=1
282	else
283		echo " OK"
284	fi
285	rm -f scripts/posix.log
286
287	return $rc
288}
289
290function check_naming_conventions() {
291	local rc=0
292
293	echo -n "Checking for proper function naming conventions..."
294	# commit_to_compare = HEAD - 1.
295	commit_to_compare="$(git log --pretty=oneline --skip=1 -n 1 | awk '{print $1}')"
296	failed_naming_conventions=false
297	changed_c_libs=()
298	declared_symbols=()
299
300	# Build an array of all the modified C libraries.
301	mapfile -t changed_c_libs < <(git diff --name-only HEAD $commit_to_compare -- lib/**/*.c module/**/*.c | xargs -r dirname | sort | uniq)
302	# Capture the names of all function declarations
303	mapfile -t declared_symbols < <(grep -Eh 'spdk_[a-zA-Z0-9_]*\(' include/spdk*/*.h \
304		| sed -En 's/.*(spdk[a-z,A-Z,0-9,_]*)\(.*/\1/p')
305
306	for c_lib in "${changed_c_libs[@]}"; do
307		lib_map_file="mk/spdk_blank.map"
308		defined_symbols=()
309		removed_symbols=()
310		exported_symbols=()
311		if ls "$c_lib"/*.map &> /dev/null; then
312			lib_map_file="$(ls "$c_lib"/*.map)"
313		fi
314		# Matching groups are 1. leading +sign. 2, function name 3. argument list / anything after that.
315		# Capture just the names of newly added (or modified) functions that start with "spdk_"
316		mapfile -t defined_symbols < <(git diff -U0 $commit_to_compare HEAD -- $c_lib | sed -En 's/(^[+])(spdk[a-z,A-Z,0-9,_]*)(\(.*)/\2/p')
317		# Capture the names of removed symbols to catch edge cases where we just move definitions around.
318		mapfile -t removed_symbols < <(git diff -U0 $commit_to_compare HEAD -- $c_lib | sed -En 's/(^[-])(spdk[a-z,A-Z,0-9,_]*)(\(.*)/\2/p')
319		for symbol in "${removed_symbols[@]}"; do
320			for i in "${!defined_symbols[@]}"; do
321				if [[ ${defined_symbols[i]} = "$symbol" ]]; then
322					unset -v 'defined_symbols[i]'
323				fi
324			done
325		done
326		# It's possible that we just modified a functions arguments so unfortunately we can't just look at changed lines in this function.
327		# matching groups are 1. All leading whitespace 2. function name. Capture just the symbol name.
328		mapfile -t exported_symbols < <(sed -En 's/(^[[:space:]]*)(spdk[a-z,A-Z,0-9,_]*);/\2/p' < $lib_map_file)
329		for defined_symbol in "${defined_symbols[@]}"; do
330			# if the list of defined symbols is equal to the list of removed symbols, then we are left with a single empty element. skip it.
331			if [ "$defined_symbol" = '' ]; then
332				continue
333			fi
334			not_exported=true
335			not_declared=true
336			if array_contains_string exported_symbols $defined_symbol; then
337				not_exported=false
338			fi
339
340			if array_contains_string declared_symbols $defined_symbol; then
341				not_declared=false
342			fi
343
344			if $not_exported || $not_declared; then
345				if ! $failed_naming_conventions; then
346					echo " found naming convention errors."
347				fi
348				echo "function $defined_symbol starts with spdk_ which is reserved for public API functions."
349				echo "Please add this function to its corresponding map file and a public header or remove the spdk_ prefix."
350				failed_naming_conventions=true
351				rc=1
352			fi
353		done
354	done
355
356	if ! $failed_naming_conventions; then
357		echo " OK"
358	fi
359
360	return $rc
361}
362
363function check_include_style() {
364	local rc=0
365
366	echo -n "Checking #include style..."
367	git grep -I -i --line-number "#include <spdk/" -- '*.[ch]' > scripts/includes.log || true
368	if [ -s scripts/includes.log ]; then
369		echo "Incorrect #include syntax. #includes of spdk/ files should use quotes."
370		cat scripts/includes.log
371		rc=1
372	else
373		echo " OK"
374	fi
375	rm -f scripts/includes.log
376
377	return $rc
378}
379
380function check_python_style() {
381	local rc=0
382
383	if hash pycodestyle 2> /dev/null; then
384		PEP8=pycodestyle
385	elif hash pep8 2> /dev/null; then
386		PEP8=pep8
387	fi
388
389	if [ -n "${PEP8}" ]; then
390		echo -n "Checking Python style..."
391
392		PEP8_ARGS+=" --max-line-length=140"
393
394		error=0
395		git ls-files '*.py' | xargs -P$(nproc) -n1 $PEP8 $PEP8_ARGS > pep8.log || error=1
396		if [ $error -ne 0 ]; then
397			echo " Python formatting errors detected"
398			cat pep8.log
399			rc=1
400		else
401			echo " OK"
402		fi
403		rm -f pep8.log
404	else
405		echo "You do not have pycodestyle or pep8 installed so your Python style is not being checked!"
406	fi
407
408	return $rc
409}
410
411function get_bash_files() {
412	local sh shebang
413
414	mapfile -t sh < <(git ls-files '*.sh')
415	mapfile -t shebang < <(git grep -l '^#!.*bash')
416
417	printf '%s\n' "${sh[@]}" "${shebang[@]}" | sort -u
418}
419
420function check_bash_style() {
421	local rc=0
422
423	# find compatible shfmt binary
424	shfmt_bins=$(compgen -c | grep '^shfmt' | uniq || true)
425	for bin in $shfmt_bins; do
426		shfmt_version=$("$bin" --version)
427		if [ $shfmt_version != "v3.1.0" ]; then
428			echo "$bin version $shfmt_version not used (only v3.1.0 is supported)"
429			echo "v3.1.0 can be installed using 'scripts/pkgdep.sh -d'"
430		else
431			shfmt=$bin
432			break
433		fi
434	done
435
436	if [ -n "$shfmt" ]; then
437		shfmt_cmdline=() sh_files=()
438
439		mapfile -t sh_files < <(get_bash_files)
440
441		if ((${#sh_files[@]})); then
442			printf 'Checking .sh formatting style...'
443
444			shfmt_cmdline+=(-i 0)     # indent_style = tab|indent_size = 0
445			shfmt_cmdline+=(-bn)      # binary_next_line = true
446			shfmt_cmdline+=(-ci)      # switch_case_indent = true
447			shfmt_cmdline+=(-ln bash) # shell_variant = bash (default)
448			shfmt_cmdline+=(-d)       # diffOut - print diff of the changes and exit with != 0
449			shfmt_cmdline+=(-sr)      # redirect operators will be followed by a space
450
451			diff=${output_dir:-$PWD}/$shfmt.patch
452
453			# Explicitly tell shfmt to not look for .editorconfig. .editorconfig is also not looked up
454			# in case any formatting arguments has been passed on its cmdline.
455			if ! SHFMT_NO_EDITORCONFIG=true "$shfmt" "${shfmt_cmdline[@]}" "${sh_files[@]}" > "$diff"; then
456				# In case shfmt detects an actual syntax error it will write out a proper message on
457				# its stderr, hence the diff file should remain empty.
458				if [[ -s $diff ]]; then
459					diff_out=$(< "$diff")
460				fi
461
462				cat <<- ERROR_SHFMT
463
464					* Errors in style formatting have been detected.
465					${diff_out:+* Please, review the generated patch at $diff
466
467					# _START_OF_THE_DIFF
468
469					${diff_out:-ERROR}
470
471					# _END_OF_THE_DIFF
472					}
473
474				ERROR_SHFMT
475				rc=1
476			else
477				rm -f "$diff"
478				printf ' OK\n'
479			fi
480		fi
481	else
482		echo "Supported version of shfmt not detected, Bash style formatting check is skipped"
483	fi
484
485	return $rc
486}
487
488function check_bash_static_analysis() {
489	local rc=0
490
491	if hash shellcheck 2> /dev/null; then
492		echo -n "Checking Bash static analysis with shellcheck..."
493
494		shellcheck_v=$(shellcheck --version | grep -P "version: [0-9\.]+" | cut -d " " -f2)
495
496		# SHCK_EXCLUDE contains a list of all of the spellcheck errors found in SPDK scripts
497		# currently. New errors should only be added to this list if the cost of fixing them
498		# is deemed too high. For more information about the errors, go to:
499		# https://github.com/koalaman/shellcheck/wiki/Checks
500		# Error descriptions can also be found at: https://github.com/koalaman/shellcheck/wiki
501		# SPDK fails some error checks which have been deprecated in later versions of shellcheck.
502		# We will not try to fix these error checks, but instead just leave the error types here
503		# so that we can still run with older versions of shellcheck.
504		SHCK_EXCLUDE="SC1117"
505		# SPDK has decided to not fix violations of these errors.
506		# We are aware about below exclude list and we want this errors to be excluded.
507		# SC1083: This {/} is literal. Check expression (missing ;/\n?) or quote it.
508		# SC1090: Can't follow non-constant source. Use a directive to specify location.
509		# SC1091: Not following: (error message here)
510		# SC2001: See if you can use ${variable//search/replace} instead.
511		# SC2010: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
512		# SC2015: Note that A && B || C is not if-then-else. C may run when A is true.
513		# SC2016: Expressions don't expand in single quotes, use double quotes for that.
514		# SC2034: foo appears unused. Verify it or export it.
515		# SC2046: Quote this to prevent word splitting.
516		# SC2086: Double quote to prevent globbing and word splitting.
517		# SC2119: Use foo "$@" if function's $1 should mean script's $1.
518		# SC2120: foo references arguments, but none are ever passed.
519		# SC2128: Expanding an array without an index only gives the first element.
520		# SC2148: Add shebang to the top of your script.
521		# SC2153: Possible Misspelling: MYVARIABLE may not be assigned, but MY_VARIABLE is.
522		# SC2154: var is referenced but not assigned.
523		# SC2164: Use cd ... || exit in case cd fails.
524		# SC2174: When used with -p, -m only applies to the deepest directory.
525		# SC2178: Variable was used as an array but is now assigned a string.
526		# SC2206: Quote to prevent word splitting/globbing,
527		#         or split robustly with mapfile or read -a.
528		# SC2207: Prefer mapfile or read -a to split command output (or quote to avoid splitting).
529		# SC2223: This default assignment may cause DoS due to globbing. Quote it.
530		SHCK_EXCLUDE="$SHCK_EXCLUDE,SC1083,SC1090,SC1091,SC2010,SC2015,SC2016,SC2034,SC2046,SC2086,\
531SC2119,SC2120,SC2128,SC2148,SC2153,SC2154,SC2164,SC2174,SC2178,SC2001,SC2206,SC2207,SC2223"
532
533		SHCK_FORMAT="tty"
534		SHCK_APPLY=false
535		SHCH_ARGS="-e $SHCK_EXCLUDE -f $SHCK_FORMAT"
536
537		if ge "$shellcheck_v" 0.4.0; then
538			SHCH_ARGS+=" -x"
539		else
540			echo "shellcheck $shellcheck_v detected, recommended >= 0.4.0."
541		fi
542
543		get_bash_files | xargs -P$(nproc) -n1 shellcheck $SHCH_ARGS &> shellcheck.log
544		if [[ -s shellcheck.log ]]; then
545			echo " Bash shellcheck errors detected!"
546
547			cat shellcheck.log
548			if $SHCK_APPLY; then
549				git apply shellcheck.log
550				echo "Bash errors were automatically corrected."
551				echo "Please remember to add the changes to your commit."
552			fi
553			rc=1
554		else
555			echo " OK"
556		fi
557		rm -f shellcheck.log
558	else
559		echo "You do not have shellcheck installed so your Bash static analysis is not being performed!"
560	fi
561
562	return $rc
563}
564
565function check_changelog() {
566	local rc=0
567
568	# Check if any of the public interfaces were modified by this patch.
569	# Warn the user to consider updating the changelog any changes
570	# are detected.
571	echo -n "Checking whether CHANGELOG.md should be updated..."
572	staged=$(git diff --name-only --cached .)
573	working=$(git status -s --porcelain --ignore-submodules | grep -iv "??" | awk '{print $2}')
574	files="$staged $working"
575	if [[ "$files" = " " ]]; then
576		files=$(git diff-tree --no-commit-id --name-only -r HEAD)
577	fi
578
579	has_changelog=0
580	for f in $files; do
581		if [[ $f == CHANGELOG.md ]]; then
582			# The user has a changelog entry, so exit.
583			has_changelog=1
584			break
585		fi
586	done
587
588	needs_changelog=0
589	if [ $has_changelog -eq 0 ]; then
590		for f in $files; do
591			if [[ $f == include/spdk/* ]] || [[ $f == scripts/rpc.py ]] || [[ $f == etc/* ]]; then
592				echo ""
593				echo -n "$f was modified. Consider updating CHANGELOG.md."
594				needs_changelog=1
595			fi
596		done
597	fi
598
599	if [ $needs_changelog -eq 0 ]; then
600		echo " OK"
601	else
602		echo ""
603	fi
604
605	return $rc
606}
607
608function check_json_rpc() {
609	local rc=0
610
611	echo -n "Checking that all RPCs are documented..."
612	while IFS='"' read -r _ rpc _; do
613		if ! grep -q "^### $rpc" doc/jsonrpc.md; then
614			echo "Missing JSON-RPC documentation for ${rpc}"
615			rc=1
616		fi
617	done < <(git grep -h -E "^SPDK_RPC_REGISTER\(" ':!test/*' ':!examples/*')
618
619	if [ $rc -eq 0 ]; then
620		echo " OK"
621	fi
622	return $rc
623}
624
625function check_markdown_format() {
626	local rc=0
627
628	if hash mdl 2> /dev/null; then
629		echo -n "Checking markdown files format..."
630		mdl -g -s $rootdir/mdl_rules.rb . > mdl.log || true
631		if [ -s mdl.log ]; then
632			echo " Errors in .md files detected:"
633			cat mdl.log
634			rc=1
635		else
636			echo " OK"
637		fi
638		rm -f mdl.log
639	else
640		echo "You do not have markdownlint installed so .md files not being checked!"
641	fi
642
643	return $rc
644}
645
646function check_rpc_args() {
647	local rc=0
648
649	echo -n "Checking rpc.py argument option names..."
650	grep add_argument scripts/rpc.py | $GNU_GREP -oP "(?<=--)[a-z0-9\-\_]*(?=\')" | grep "_" > badargs.log
651
652	if [[ -s badargs.log ]]; then
653		echo "rpc.py arguments with underscores detected!"
654		cat badargs.log
655		echo "Please convert the underscores to dashes."
656		rc=1
657	else
658		echo " OK"
659	fi
660	rm -f badargs.log
661	return $rc
662}
663
664function get_files_for_lic() {
665	local f_shebang="" f_suffix=() f_type=() f_all=() exceptions=""
666
667	f_shebang+="bash|"
668	f_shebang+="make|"
669	f_shebang+="perl|"
670	f_shebang+="python|"
671	f_shebang+="sh"
672
673	f_suffix+=("*.c")
674	f_suffix+=("*.cpp")
675	f_suffix+=("*.h")
676	f_suffix+=("*.go")
677	f_suffix+=("*.mk")
678	f_suffix+=("*.pl")
679	f_suffix+=("*.py")
680	f_suffix+=("*.sh")
681	f_suffix+=("*.yaml")
682
683	f_type+=("*Dockerfile")
684	f_type+=("*Makefile")
685
686	# Exclude files that may match the above types but should not
687	# fall under SPDX check.
688	exceptions+="include/linux|"
689	exceptions+="include/spdk/queue_extras.h"
690
691	mapfile -t f_all < <(
692		git ls-files "${f_suffix[@]}" "${f_type[@]}"
693		git grep -lE "^#!.*($f_shebang)"
694	)
695
696	printf '%s\n' "${f_all[@]}" | sort -u | grep -vE "$exceptions"
697}
698
699function check_spdx_lic() {
700	local files_missing_license_header=() hint=()
701	local rc=0
702
703	hint+=("SPDX-License-Identifier: BSD-3-Clause")
704	hint+=("All rights reserved.")
705
706	printf 'Checking SPDX-license...'
707
708	mapfile -t files_missing_license_header < <(
709		grep -LE "SPDX-License-Identifier:.+" $(get_files_for_lic)
710	)
711
712	if ((${#files_missing_license_header[@]} > 0)); then
713		printf '\nFollowing files are missing SPDX-license header:\n'
714		printf '  @%s\n' "${files_missing_license_header[@]}"
715		printf '\nExample:\n'
716		printf '  #  %s\n' "${hint[@]}"
717		return 1
718	fi
719
720	printf 'OK\n'
721}
722
723rc=0
724
725check_permissions || rc=1
726check_c_style || rc=1
727
728GIT_VERSION=$(git --version | cut -d' ' -f3)
729
730if version_lt "1.9.5" "${GIT_VERSION}"; then
731	# git <1.9.5 doesn't support pathspec magic exclude
732	echo " Your git version is too old to perform all tests. Please update git to at least 1.9.5 version..."
733	exit $rc
734fi
735
736check_comment_style || rc=1
737check_markdown_format || rc=1
738check_spaces_before_tabs || rc=1
739check_trailing_whitespace || rc=1
740check_forbidden_functions || rc=1
741check_cunit_style || rc=1
742check_eof || rc=1
743check_posix_includes || rc=1
744check_naming_conventions || rc=1
745check_include_style || rc=1
746check_python_style || rc=1
747check_bash_style || rc=1
748check_bash_static_analysis || rc=1
749check_changelog || rc=1
750check_json_rpc || rc=1
751check_rpc_args || rc=1
752check_spdx_lic || rc=1
753
754exit $rc
755