blob: 60c3be98a4f89e05a87d5c5a59ef17b24ba6bfdd [file] [log] [blame]
Minos Galanakisf4ca6ac2017-12-11 02:39:21 +01001#!/bin/bash
2#-------------------------------------------------------------------------------
3# Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
4#
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;
27SKIP_PATHS='./build-\*:./test/\*:./platform/\*:*/tz_\*'
28
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>)."
76 echo " -p <path>, Provide location of directory containing checkpath."
77 echo -e "\nNOTE: make sure checkpatch is located in '$CHECKPATCH_PATH'"
78}
79
80##@fn app_err(void)
81##@brief Print error massage.
82##@returns n/a
83##
84#This is needed for Doxygen for now.
85#!void app_err(void){};
86app_err() {
87 echo "Error: "$1 >&2
88}
89
90##@fn download_checkpatch_file(string f_name)
91##@brief Download the specified checkpatch file.
92##@param[in] f_name name of file to download.
93##@returns status code
94##
95##Download checkpatch files from raw.githubusercontent.com to the current
96##directory. Target files are truncated to avoid breaking links.
97##
98#This is needed for Doxygen for now.
99#!err download_checkpatch_file(string f_name){};
100download_checkpatch_file() {
101 # HTTPS address location to download checkpatch file
102 if [ $VERBOSE -eq 0 ]; then
103 REDIRECT=" >/dev/null"
104 fi
105
106 curl "https://raw.githubusercontent.com/torvalds/linux/master/scripts/$1" --output "$1.new" &>/dev/null
107
108 if [ $? != 0 ]; then
109 app_err "curl reported error while downloading $1"
110 exit 1
111 else
112 #Copy file and preserve links.
113 cat "$1.new" > "$1"
114 rm "$1.new"
115 fi
116}
117
118##@fn update_checkpatch()
119##@brief Download checkpatch files.
120##@returns status code
121##
122##Download checkpatch files from raw.githubusercontent.com to \ref CHECKPATCH_PATH
123##directory.
124##
125#This is needed for Doxygen for now.
126#!void update_checkpatch(){};
127update_checkpatch() {
128 echo "Updating checkpatch..."
129 if ! [ -x "$(command -v curl)" ]; then
130 app_err "curl was not found. Please, make sure curl command is available"
131 exit 1
132 fi
133
134 pushd $CHECKPATCH_PATH > /dev/null
135 #Execute popd when shell exits.
136 trap popd 0
137
138 # Download checkpatch.pl
139 download_checkpatch_file checkpatch.pl
140 chmod 750 $CHECKPATCH_PATH/checkpatch.pl
141
142 # Download const_structs.checkpatch
143 download_checkpatch_file const_structs.checkpatch
144 chmod 640 $CHECKPATCH_PATH/const_structs.checkpatch
145
146 # Download spelling.txt
147 download_checkpatch_file spelling.txt
148 chmod 640 $CHECKPATCH_PATH/spelling.txt
149
150 popd >/dev/null
151 #Remove cleanup trap
152 trap 0
153}
154
155##@fn check_tree()
156##@brief Run checkpatch in directory tree checking mode
157##@returns status code
158##
159##Execute checkpatch to check the full content of all source files under the
160##directory specified in \ref TFM_DIRECTORY_NAME. Directory content specified in
161##\ref SKIP_PATHS will be excluded.
162##This function uses xargs to execute multiple checkpatch instances in parallel.
163##
164#This is needed for Doxygen for now.
165#!void check_tree(){};
166check_tree() {
167 # Find all files to execute checkpatch on
168 FIND_CMD="find $TFM_DIRECTORY_NAME -name '*.[ch]' -a -not \( -path "${SKIP_PATHS//:/ -o -path }" \)"
169 echo "Scanning "$TFM_DIRECTORY_NAME" dir to find all .c and .h files to check ..."
170 #Modify checkpatch command line to make checkpatch work on files.
171 CHECKPATCH_CMD="$CHECKPATCH_CMD -f "
172 if [ $VERBOSE -eq 1 ]; then
173 eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} |tee -a "$OUTPUT_FILE_PATH"
174 else
175 eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} >> $OUTPUT_FILE_PATH
176 fi
177}
178
179##@fn check_diff()
180##@brief Run checkpatch in git diff mode.
181##@returns status code
182##
183##Execute checkpatch to check the last N (\ref CHECK_LAST_COMMITS) commits of
184##the branch checked out at directory specified in \ref TFM_DIRECTORY_NAME.
185##Directory content specified in \ref SKIP_PATHS will be excluded.
186##
187#This is needed for Doxygen for now.
188#!void check_diff(){};
189check_diff() {
190 BASE_COMMIT="HEAD~$CHECK_LAST_COMMITS"
191 #use find to limit diff content to the same set of files as when checking
192 #the whole tree.
193 FIND_CMD="find ./ -name '*.[ch]' -a -not \( -path "${SKIP_PATHS//:/ -o -path }" \)"
194
195 #enter tf-m working copy to make git commands execute fine
196 pushd "$TFM_DIRECTORY_NAME" > /dev/null
197 #Execute popd when shell exits
198 trap popd 0
199
200 #List of files we care about. Filter out changed files from interesting
201 #list of files. This is needed to avoid GIT_CMD to break the argument
202 #list length.
203 CARE_LIST=$(eval $FIND_CMD | grep "$(git diff $BASE_COMMIT --name-only)" -)
204 GIT_CMD="git diff $BASE_COMMIT -- $CARE_LIST"
205
206 echo "Checking commits: $(git log "$BASE_COMMIT"..HEAD --format=%h | tr $"\n" " ")"
207
208 #Modify checkpatch parameters to give more details when working on
209 #diff:s
210 CHECKPATCH_CMD="$CHECKPATCH_CMD --showfile -"
211
212 if [ $VERBOSE -eq 1 ]; then
213 $GIT_CMD | $CHECKPATCH_CMD | tee -a "$OUTPUT_FILE_PATH"
214 else
215 $GIT_CMD | $CHECKPATCH_CMD >> $OUTPUT_FILE_PATH
216 fi
217
218 popd > /dev/null
219 #Remove cleanup trap.
220 trap 0
221}
222
223#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224#~~~~~~~~~~~~~~~~~~~~~~~~ Entry point ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
226#Internal variables not to be modified.
227VERBOSE=0
228UPDATE_CHECKPATCH_FILES=0
229
230##@var CHECK_LAST_COMMITS
231##@brief Number of commits to check.
232##
233##Number of commits relative to HEAD to check. When set to 0 full file content
234##is checked instead of commit diffs.
235##
236#This is needed for Doxygen for now.
237#!path CHECK_LAST_COMMITS;
238CHECK_LAST_COMMITS=0
239
240# Getting options and setting variables required to execute the script. This
241# script starts executing from here.
242while getopts "uvhd:f:l:p:" opt
243do
244 case $opt in
245 v) VERBOSE=1 ;;
246 h) usage ; exit 0 ;;
247 d) TFM_DIRECTORY_NAME="$OPTARG" ;;
248 f) OUTPUT_FILE_PATH="$OPTARG" ;;
249 u) UPDATE_CHECKPATCH_FILES=1 ;;
250 l) CHECK_LAST_COMMITS="$OPTARG" ;;
251 p) CHECKPATCH_PATH="$OPTARG" ;;
252 \?) usage ; exit 1 ;;
253 esac
254done
255
256# Update checkpatch files
257if [ $UPDATE_CHECKPATCH_FILES -eq 1 ]; then
258 update_checkpatch
259 echo "Checkpatch update was successfull."
260 exit 0
261fi
262
263#Convert checkpath override path to full path
264CHECKPATCH_PATH=$(readlink -f "$CHECKPATCH_PATH")
265
266#Convert output file name to full path
267OUTPUT_FILE_PATH=$(readlink -f "$OUTPUT_FILE_PATH")
268
269# Create checkpatch command
270CHECKPATCH_APP=$CHECKPATCH_PATH"/checkpatch.pl"
271CHECKPATCH_CONFG_FILENAME=$CHECKPATCH_PATH_DEF"/checkpatch.conf"
272CHECKPATCH_CMD=$CHECKPATCH_APP" $(grep -o '^[^#]*' $CHECKPATCH_CONFG_FILENAME)"
273
274# Check if checkpatch is present
275if ! [ -f "$CHECKPATCH_APP" ]; then
276 app_err "checkpatch.pl was not found. checkpatch.pl has to be located in $CHECKPATCH_PATH"
277 exit 1
278fi
279
280#Truncate previous content
281: > $OUTPUT_FILE_PATH
282
283#Do we need to work on a git diff?
284if [ $CHECK_LAST_COMMITS -eq 0 ]
285then
286 #Working on files
287 check_tree
288else
289 #Working on git diff
290 check_diff
291fi
292
293echo "checkpatch report \"$OUTPUT_FILE_PATH\" is ready!"