blob: 5a8d247d37fc12f357004cc49d05fd47c4deaa53 [file] [log] [blame]
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +01001#!/bin/bash
2#-------------------------------------------------------------------------------
Xinyu Zhang726aaa52021-02-20 15:56:54 +08003# Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +01004#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7#-------------------------------------------------------------------------------
8
9##
10##@file
11##@brief Execute checkpatch
12##
13##This bash script can be used to execute checkpatch for the tf-m project.
14##The script can be started with -h to give help on usage.
15##
16
17
18##@var SKIP_PATHS
19##@brief Folders and files to not be analysed by checkpatch
20##
21##This variable specifies the list of directories which shall not be analysed
22##by checkpatch.
23##This is a colon (:) separated list.
24##
25#This is needed for Doxygen for now.
26#!string SKIP_PATHS;
Xinyu Zhang726aaa52021-02-20 15:56:54 +080027SKIP_PATHS='./build-\*:./platform/\*:*/tz_\*:./lib/\*:./platform/ext/\*:./bl2/ext/\*:./docs/\*:./tools/\*'
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +010028
29##@var TFM_DIRECTORY_NAME
30##@brief Default path to tf-m source code.
31##
32#This is needed for Doxygen for now.
33#!path TFM_DIRECTORY_NAME;
34TFM_DIRECTORY_NAME="./"
35
36##@var OUTPUT_FILE_PATH
37##@brief Default path to report file.
38##
39##This text file will hold the output report of checkpatch.
40##
41#This is needed for Doxygen for now.
42#!path OUTPUT_FILE_PATH;
43OUTPUT_FILE_PATH="tfm_checkpatch_report.txt"
44
45##@var CHECKPATCH_PATH_DEF
46##@brief Default Path to checkpatch executable.
47##
48#This is needed for Doxygen for now.
49#!path CHECKPATCH_PATH_DEF;
50CHECKPATCH_PATH_DEF=$(readlink -f $(dirname "$0")"/checkpatch")
51
52##@var CHECKPATCH_PATH
53##@brief Path to checkpatch executable.
54##
55## Checkpatch path can be overriden by user argument. Initialized with Default
56## value of ./checkpatch
57##
58#This is needed for Doxygen for now.
59#!path CHECKPATCH_PATH;
60CHECKPATCH_PATH=$CHECKPATCH_PATH_DEF
61
62##@fn usage(void)
63##@brief Print help text on usage.
64##@returns n/a
65##
66#This is needed for Doxygen for now.
67#!void usage(void){};
68usage() {
69 echo "Usage: $(basename -- "$0") [-v] [-h] [-d <TF-M dir>] [-f <output_filename>] [-u] [-p <number>]"
70 echo " -v, Verbose output"
71 echo " -h, Script help"
72 echo " -d, <TF-M dir>, TF-M directory"
73 echo " -f, <output_filename>, Output filename"
74 echo " -u, Update checkpatch files using curl"
75 echo " -l <number>, Check only the last <number> commits (HEAD~<number>)."
Dean Birch62c4f082020-01-17 16:13:26 +000076 echo " -p <path>, Provide location of directory containing checkpatch."
77 echo " -r, Print raw output. Implies verbose."
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +010078 echo -e "\nNOTE: make sure checkpatch is located in '$CHECKPATCH_PATH'"
79}
80
81##@fn app_err(void)
82##@brief Print error massage.
83##@returns n/a
84##
85#This is needed for Doxygen for now.
86#!void app_err(void){};
87app_err() {
88 echo "Error: "$1 >&2
89}
90
91##@fn download_checkpatch_file(string f_name)
92##@brief Download the specified checkpatch file.
93##@param[in] f_name name of file to download.
94##@returns status code
95##
96##Download checkpatch files from raw.githubusercontent.com to the current
97##directory. Target files are truncated to avoid breaking links.
98##
99#This is needed for Doxygen for now.
100#!err download_checkpatch_file(string f_name){};
101download_checkpatch_file() {
102 # HTTPS address location to download checkpatch file
103 if [ $VERBOSE -eq 0 ]; then
104 REDIRECT=" >/dev/null"
105 fi
106
Xinyu Zhang5797e202020-10-21 15:18:08 +0800107 curl "https://raw.githubusercontent.com/torvalds/linux/v5.9/scripts/$1" --output "$1.new" &>/dev/null
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100108
109 if [ $? != 0 ]; then
110 app_err "curl reported error while downloading $1"
111 exit 1
112 else
113 #Copy file and preserve links.
114 cat "$1.new" > "$1"
115 rm "$1.new"
116 fi
117}
118
119##@fn update_checkpatch()
120##@brief Download checkpatch files.
121##@returns status code
122##
123##Download checkpatch files from raw.githubusercontent.com to \ref CHECKPATCH_PATH
124##directory.
125##
126#This is needed for Doxygen for now.
127#!void update_checkpatch(){};
128update_checkpatch() {
129 echo "Updating checkpatch..."
130 if ! [ -x "$(command -v curl)" ]; then
131 app_err "curl was not found. Please, make sure curl command is available"
132 exit 1
133 fi
134
135 pushd $CHECKPATCH_PATH > /dev/null
136 #Execute popd when shell exits.
137 trap popd 0
138
139 # Download checkpatch.pl
140 download_checkpatch_file checkpatch.pl
141 chmod 750 $CHECKPATCH_PATH/checkpatch.pl
142
143 # Download const_structs.checkpatch
144 download_checkpatch_file const_structs.checkpatch
145 chmod 640 $CHECKPATCH_PATH/const_structs.checkpatch
146
147 # Download spelling.txt
148 download_checkpatch_file spelling.txt
149 chmod 640 $CHECKPATCH_PATH/spelling.txt
150
151 popd >/dev/null
152 #Remove cleanup trap
153 trap 0
154}
155
156##@fn check_tree()
157##@brief Run checkpatch in directory tree checking mode
158##@returns status code
159##
160##Execute checkpatch to check the full content of all source files under the
161##directory specified in \ref TFM_DIRECTORY_NAME. Directory content specified in
162##\ref SKIP_PATHS will be excluded.
163##This function uses xargs to execute multiple checkpatch instances in parallel.
164##
165#This is needed for Doxygen for now.
166#!void check_tree(){};
167check_tree() {
168 # Find all files to execute checkpatch on
169 FIND_CMD="find $TFM_DIRECTORY_NAME -name '*.[ch]' -a -not \( -path "${SKIP_PATHS//:/ -o -path }" \)"
170 echo "Scanning "$TFM_DIRECTORY_NAME" dir to find all .c and .h files to check ..."
171 #Modify checkpatch command line to make checkpatch work on files.
172 CHECKPATCH_CMD="$CHECKPATCH_CMD -f "
173 if [ $VERBOSE -eq 1 ]; then
174 eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} |tee -a "$OUTPUT_FILE_PATH"
Dean Birch62c4f082020-01-17 16:13:26 +0000175 RETURN_CODE=${PIPESTATUS[1]}
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100176 else
177 eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} >> $OUTPUT_FILE_PATH
Dean Birch62c4f082020-01-17 16:13:26 +0000178 RETURN_CODE=${PIPESTATUS[1]}
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100179 fi
180}
181
182##@fn check_diff()
183##@brief Run checkpatch in git diff mode.
184##@returns status code
185##
186##Execute checkpatch to check the last N (\ref CHECK_LAST_COMMITS) commits of
187##the branch checked out at directory specified in \ref TFM_DIRECTORY_NAME.
188##Directory content specified in \ref SKIP_PATHS will be excluded.
189##
190#This is needed for Doxygen for now.
191#!void check_diff(){};
192check_diff() {
193 BASE_COMMIT="HEAD~$CHECK_LAST_COMMITS"
194 #use find to limit diff content to the same set of files as when checking
195 #the whole tree.
196 FIND_CMD="find ./ -name '*.[ch]' -a -not \( -path "${SKIP_PATHS//:/ -o -path }" \)"
197
198 #enter tf-m working copy to make git commands execute fine
199 pushd "$TFM_DIRECTORY_NAME" > /dev/null
200 #Execute popd when shell exits
201 trap popd 0
202
203 #List of files we care about. Filter out changed files from interesting
204 #list of files. This is needed to avoid GIT_CMD to break the argument
205 #list length.
206 CARE_LIST=$(eval $FIND_CMD | grep "$(git diff $BASE_COMMIT --name-only)" -)
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100207
Minos Galanakisea421232019-06-20 17:11:28 +0100208 if [ ! -z "$CARE_LIST" ]; then
209 # Only run checkpatch if there are files to check
210 GIT_CMD="git diff $BASE_COMMIT -- $CARE_LIST"
211 echo "$GIT_CMD"
212 echo "Checking commits: $(git log "$BASE_COMMIT"..HEAD --format=%h | tr $"\n" " ")"
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100213
Minos Galanakisea421232019-06-20 17:11:28 +0100214 #Modify checkpatch parameters to give more details when working on
215 #diff:s
216 CHECKPATCH_CMD="$CHECKPATCH_CMD --showfile -"
217 fi
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100218
219 if [ $VERBOSE -eq 1 ]; then
220 $GIT_CMD | $CHECKPATCH_CMD | tee -a "$OUTPUT_FILE_PATH"
Dean Birch62c4f082020-01-17 16:13:26 +0000221 RETURN_CODE=${PIPESTATUS[1]}
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100222 else
223 $GIT_CMD | $CHECKPATCH_CMD >> $OUTPUT_FILE_PATH
Dean Birch62c4f082020-01-17 16:13:26 +0000224 RETURN_CODE=${PIPESTATUS[1]}
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100225 fi
226
227 popd > /dev/null
228 #Remove cleanup trap.
229 trap 0
230}
231
232#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
233#~~~~~~~~~~~~~~~~~~~~~~~~ Entry point ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
234#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
235#Internal variables not to be modified.
236VERBOSE=0
237UPDATE_CHECKPATCH_FILES=0
238
239##@var CHECK_LAST_COMMITS
240##@brief Number of commits to check.
241##
242##Number of commits relative to HEAD to check. When set to 0 full file content
243##is checked instead of commit diffs.
244##
245#This is needed for Doxygen for now.
246#!path CHECK_LAST_COMMITS;
247CHECK_LAST_COMMITS=0
248
Dean Birch62c4f082020-01-17 16:13:26 +0000249# Whether to print the output to screen.
250RAW_OUTPUT=0
251
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100252# Getting options and setting variables required to execute the script. This
253# script starts executing from here.
Dean Birch62c4f082020-01-17 16:13:26 +0000254while getopts "uvhd:f:l:p:r" opt
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100255do
256 case $opt in
257 v) VERBOSE=1 ;;
258 h) usage ; exit 0 ;;
259 d) TFM_DIRECTORY_NAME="$OPTARG" ;;
260 f) OUTPUT_FILE_PATH="$OPTARG" ;;
261 u) UPDATE_CHECKPATCH_FILES=1 ;;
262 l) CHECK_LAST_COMMITS="$OPTARG" ;;
263 p) CHECKPATCH_PATH="$OPTARG" ;;
Dean Birch62c4f082020-01-17 16:13:26 +0000264 r) RAW_OUTPUT=1
265 VERBOSE=1 ;;
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100266 \?) usage ; exit 1 ;;
267 esac
268done
269
270# Update checkpatch files
271if [ $UPDATE_CHECKPATCH_FILES -eq 1 ]; then
272 update_checkpatch
Dean Birch62c4f082020-01-17 16:13:26 +0000273 echo "Checkpatch update was successful."
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100274 exit 0
275fi
276
277#Convert checkpath override path to full path
278CHECKPATCH_PATH=$(readlink -f "$CHECKPATCH_PATH")
279
280#Convert output file name to full path
281OUTPUT_FILE_PATH=$(readlink -f "$OUTPUT_FILE_PATH")
282
Xinyu Zhang27449ac2021-12-29 12:01:49 +0800283# Convert TF-M specific type defs file to full path
284TFM_TYPE_DEF_FILE=$CHECKPATCH_PATH"/tfm_type_defs.txt"
285
286# Prepare CheckPatch config file
287CHECKPATCH_CONFG_FILENAME=$CHECKPATCH_PATH_DEF"/checkpatch.conf"
288sed -i "s#TFM_TYPE_DEF_FILE#$TFM_TYPE_DEF_FILE#g" $CHECKPATCH_CONFG_FILENAME
289
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100290# Create checkpatch command
291CHECKPATCH_APP=$CHECKPATCH_PATH"/checkpatch.pl"
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +0100292CHECKPATCH_CMD=$CHECKPATCH_APP" $(grep -o '^[^#]*' $CHECKPATCH_CONFG_FILENAME)"
293
294# Check if checkpatch is present
295if ! [ -f "$CHECKPATCH_APP" ]; then
296 app_err "checkpatch.pl was not found. checkpatch.pl has to be located in $CHECKPATCH_PATH"
297 exit 1
298fi
299
300#Truncate previous content
301: > $OUTPUT_FILE_PATH
302
303#Do we need to work on a git diff?
304if [ $CHECK_LAST_COMMITS -eq 0 ]
305then
306 #Working on files
307 check_tree
308else
309 #Working on git diff
310 check_diff
311fi
312
Dean Birch62c4f082020-01-17 16:13:26 +0000313if [ "$RAW_OUTPUT" == "1" ] ; then
314 rm $OUTPUT_FILE_PATH
315 exit $RETURN_CODE
316else
317 echo "checkpatch report \"$OUTPUT_FILE_PATH\" is ready!"
318fi