xref: /dpdk/devtools/checkpatches.sh (revision 742bde12)
1#! /bin/sh
2# SPDX-License-Identifier: BSD-3-Clause
3# Copyright 2015 6WIND S.A.
4
5# Load config options:
6# - DPDK_CHECKPATCH_PATH
7# - DPDK_CHECKPATCH_CODESPELL
8# - DPDK_CHECKPATCH_LINE_LENGTH
9. $(dirname $(readlink -e $0))/load-devel-config
10
11VALIDATE_NEW_API=$(dirname $(readlink -e $0))/check-symbol-change.sh
12
13# Enable codespell by default. This can be overwritten from a config file.
14# Codespell can also be enabled by setting DPDK_CHECKPATCH_CODESPELL to a valid path
15# to a dictionary.txt file if dictionary.txt is not in the default location.
16codespell=${DPDK_CHECKPATCH_CODESPELL:-enable}
17length=${DPDK_CHECKPATCH_LINE_LENGTH:-80}
18
19# override default Linux options
20options="--no-tree"
21if [ "$codespell" = "enable" ] ; then
22    options="$options --codespell"
23elif [ -f "$codespell" ] ; then
24    options="$options --codespell"
25    options="$options --codespellfile $codespell"
26fi
27options="$options --max-line-length=$length"
28options="$options --show-types"
29options="$options --ignore=LINUX_VERSION_CODE,\
30FILE_PATH_CHANGES,MAINTAINERS_STYLE,SPDX_LICENSE_TAG,\
31VOLATILE,PREFER_PACKED,PREFER_ALIGNED,PREFER_PRINTF,\
32PREFER_KERNEL_TYPES,BIT_MACRO,CONST_STRUCT,\
33SPLIT_STRING,LONG_LINE_STRING,\
34LINE_SPACING,PARENTHESIS_ALIGNMENT,NETWORKING_BLOCK_COMMENT_STYLE,\
35NEW_TYPEDEFS,COMPARISON_TO_NULL"
36
37clean_tmp_files() {
38	if echo $tmpinput | grep -q '^checkpatches\.' ; then
39		rm -f "$tmpinput"
40	fi
41}
42
43trap "clean_tmp_files" INT
44
45print_usage () {
46	cat <<- END_OF_HELP
47	usage: $(basename $0) [-q] [-v] [-nX|patch1 [patch2] ...]]
48
49	Run Linux kernel checkpatch.pl with DPDK options.
50	The environment variable DPDK_CHECKPATCH_PATH must be set.
51
52	The patches to check can be from stdin, files specified on the command line,
53	or latest git commits limited with -n option (default limit: origin/master).
54	END_OF_HELP
55}
56
57check_forbidden_additions() { # <patch>
58	res=0
59
60	# refrain from new additions of rte_panic() and rte_exit()
61	# multiple folders and expressions are separated by spaces
62	awk -v FOLDERS="lib drivers" \
63		-v EXPRESSIONS="rte_panic\\\( rte_exit\\\(" \
64		-v RET_ON_FAIL=1 \
65		-v MESSAGE='Using rte_panic/rte_exit' \
66		-f $(dirname $(readlink -e $0))/check-forbidden-tokens.awk \
67		"$1" || res=1
68
69	# svg figures must be included with wildcard extension
70	# because of png conversion for pdf docs
71	awk -v FOLDERS='doc' \
72		-v EXPRESSIONS='::[[:space:]]*[^[:space:]]*\\.svg' \
73		-v RET_ON_FAIL=1 \
74		-v MESSAGE='Using explicit .svg extension instead of .*' \
75		-f $(dirname $(readlink -e $0))/check-forbidden-tokens.awk \
76		"$1" || res=1
77
78	return $res
79}
80
81number=0
82quiet=false
83verbose=false
84while getopts hn:qv ARG ; do
85	case $ARG in
86		n ) number=$OPTARG ;;
87		q ) quiet=true ;;
88		v ) verbose=true ;;
89		h ) print_usage ; exit 0 ;;
90		? ) print_usage ; exit 1 ;;
91	esac
92done
93shift $(($OPTIND - 1))
94
95if [ ! -f "$DPDK_CHECKPATCH_PATH" ] || [ ! -x "$DPDK_CHECKPATCH_PATH" ] ; then
96	print_usage >&2
97	echo
98	echo 'Cannot execute DPDK_CHECKPATCH_PATH' >&2
99	exit 1
100fi
101
102print_headline() { # <title>
103	printf '\n### %s\n\n' "$1"
104	headline_printed=true
105}
106
107total=0
108status=0
109
110check () { # <patch> <commit> <title>
111	local ret=0
112	headline_printed=false
113
114	total=$(($total + 1))
115	! $verbose || print_headline "$3"
116	if [ -n "$1" ] ; then
117		tmpinput=$1
118	elif [ -n "$2" ] ; then
119		tmpinput=$(mktemp -t dpdk.checkpatches.XXXXXX)
120		git format-patch --find-renames \
121		--no-stat --stdout -1 $commit > "$tmpinput"
122	else
123		tmpinput=$(mktemp -t dpdk.checkpatches.XXXXXX)
124		cat > "$tmpinput"
125	fi
126
127	! $verbose || printf 'Running checkpatch.pl:\n'
128	report=$($DPDK_CHECKPATCH_PATH $options "$tmpinput" 2>/dev/null)
129	if [ $? -ne 0 ] ; then
130		$headline_printed || print_headline "$3"
131		printf '%s\n' "$report" | sed -n '1,/^total:.*lines checked$/p'
132		ret=1
133	fi
134
135	! $verbose || printf '\nChecking API additions/removals:\n'
136	report=$($VALIDATE_NEW_API "$tmpinput")
137	if [ $? -ne 0 ] ; then
138		$headline_printed || print_headline "$3"
139		printf '%s\n' "$report"
140		ret=1
141	fi
142
143	! $verbose || printf '\nChecking forbidden tokens additions:\n'
144	report=$(check_forbidden_additions "$tmpinput")
145	if [ $? -ne 0 ] ; then
146		$headline_printed || print_headline "$3"
147		printf '%s\n' "$report"
148		ret=1
149	fi
150
151	clean_tmp_files
152	[ $ret -eq 0 ] && return 0
153
154	status=$(($status + 1))
155}
156
157if [ -n "$1" ] ; then
158	for patch in "$@" ; do
159		# Subject can be on 2 lines
160		subject=$(sed '/^Subject: */!d;s///;N;s,\n[[:space:]]\+, ,;s,\n.*,,;q' "$patch")
161		check "$patch" '' "$subject"
162	done
163elif [ ! -t 0 ] ; then # stdin
164	subject=$(while read header value ; do
165		if [ "$header" = 'Subject:' ] ; then
166			IFS= read next
167			continuation=$(echo "$next" | sed -n 's,^[[:space:]]\+, ,p')
168			echo $value$continuation
169			break
170		fi
171	done)
172	check '' '' "$subject"
173else
174	if [ $number -eq 0 ] ; then
175		commits=$(git rev-list --reverse origin/master..)
176	else
177		commits=$(git rev-list --reverse --max-count=$number HEAD)
178	fi
179	for commit in $commits ; do
180		subject=$(git log --format='%s' -1 $commit)
181		check '' $commit "$subject"
182	done
183fi
184pass=$(($total - $status))
185$quiet || printf '\n%d/%d valid patch' $pass $total
186$quiet || [ $pass -le 1 ] || printf 'es'
187$quiet || printf '\n'
188exit $status
189