blob: 3ff328e53f882f20971cffd65c6fb6234aff9686 [file] [log] [blame]
#!/bin/bash
#-------------------------------------------------------------------------------
# Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
##
##@file
##@brief Execute checkpatch
##
##This bash script can be used to execute checkpatch for the tf-m project.
##The script can be started with -h to give help on usage.
##
##@var SKIP_PATHS
##@brief Folders and files to not be analysed by checkpatch
##
##This variable specifies the list of directories which shall not be analysed
##by checkpatch.
##This is a colon (:) separated list.
##
#This is needed for Doxygen for now.
#!string SKIP_PATHS;
SKIP_PATHS='./build-\*:./test/\*:./platform/\*:*/tz_\*:./lib/ext/\*:./platform/ext/\*:./bl2/ext/\*'
##@var TFM_DIRECTORY_NAME
##@brief Default path to tf-m source code.
##
#This is needed for Doxygen for now.
#!path TFM_DIRECTORY_NAME;
TFM_DIRECTORY_NAME="./"
##@var OUTPUT_FILE_PATH
##@brief Default path to report file.
##
##This text file will hold the output report of checkpatch.
##
#This is needed for Doxygen for now.
#!path OUTPUT_FILE_PATH;
OUTPUT_FILE_PATH="tfm_checkpatch_report.txt"
##@var CHECKPATCH_PATH_DEF
##@brief Default Path to checkpatch executable.
##
#This is needed for Doxygen for now.
#!path CHECKPATCH_PATH_DEF;
CHECKPATCH_PATH_DEF=$(readlink -f $(dirname "$0")"/checkpatch")
##@var CHECKPATCH_PATH
##@brief Path to checkpatch executable.
##
## Checkpatch path can be overriden by user argument. Initialized with Default
## value of ./checkpatch
##
#This is needed for Doxygen for now.
#!path CHECKPATCH_PATH;
CHECKPATCH_PATH=$CHECKPATCH_PATH_DEF
##@fn usage(void)
##@brief Print help text on usage.
##@returns n/a
##
#This is needed for Doxygen for now.
#!void usage(void){};
usage() {
echo "Usage: $(basename -- "$0") [-v] [-h] [-d <TF-M dir>] [-f <output_filename>] [-u] [-p <number>]"
echo " -v, Verbose output"
echo " -h, Script help"
echo " -d, <TF-M dir>, TF-M directory"
echo " -f, <output_filename>, Output filename"
echo " -u, Update checkpatch files using curl"
echo " -l <number>, Check only the last <number> commits (HEAD~<number>)."
echo " -p <path>, Provide location of directory containing checkpath."
echo -e "\nNOTE: make sure checkpatch is located in '$CHECKPATCH_PATH'"
}
##@fn app_err(void)
##@brief Print error massage.
##@returns n/a
##
#This is needed for Doxygen for now.
#!void app_err(void){};
app_err() {
echo "Error: "$1 >&2
}
##@fn download_checkpatch_file(string f_name)
##@brief Download the specified checkpatch file.
##@param[in] f_name name of file to download.
##@returns status code
##
##Download checkpatch files from raw.githubusercontent.com to the current
##directory. Target files are truncated to avoid breaking links.
##
#This is needed for Doxygen for now.
#!err download_checkpatch_file(string f_name){};
download_checkpatch_file() {
# HTTPS address location to download checkpatch file
if [ $VERBOSE -eq 0 ]; then
REDIRECT=" >/dev/null"
fi
curl "https://raw.githubusercontent.com/torvalds/linux/master/scripts/$1" --output "$1.new" &>/dev/null
if [ $? != 0 ]; then
app_err "curl reported error while downloading $1"
exit 1
else
#Copy file and preserve links.
cat "$1.new" > "$1"
rm "$1.new"
fi
}
##@fn update_checkpatch()
##@brief Download checkpatch files.
##@returns status code
##
##Download checkpatch files from raw.githubusercontent.com to \ref CHECKPATCH_PATH
##directory.
##
#This is needed for Doxygen for now.
#!void update_checkpatch(){};
update_checkpatch() {
echo "Updating checkpatch..."
if ! [ -x "$(command -v curl)" ]; then
app_err "curl was not found. Please, make sure curl command is available"
exit 1
fi
pushd $CHECKPATCH_PATH > /dev/null
#Execute popd when shell exits.
trap popd 0
# Download checkpatch.pl
download_checkpatch_file checkpatch.pl
chmod 750 $CHECKPATCH_PATH/checkpatch.pl
# Download const_structs.checkpatch
download_checkpatch_file const_structs.checkpatch
chmod 640 $CHECKPATCH_PATH/const_structs.checkpatch
# Download spelling.txt
download_checkpatch_file spelling.txt
chmod 640 $CHECKPATCH_PATH/spelling.txt
popd >/dev/null
#Remove cleanup trap
trap 0
}
##@fn check_tree()
##@brief Run checkpatch in directory tree checking mode
##@returns status code
##
##Execute checkpatch to check the full content of all source files under the
##directory specified in \ref TFM_DIRECTORY_NAME. Directory content specified in
##\ref SKIP_PATHS will be excluded.
##This function uses xargs to execute multiple checkpatch instances in parallel.
##
#This is needed for Doxygen for now.
#!void check_tree(){};
check_tree() {
# Find all files to execute checkpatch on
FIND_CMD="find $TFM_DIRECTORY_NAME -name '*.[ch]' -a -not \( -path "${SKIP_PATHS//:/ -o -path }" \)"
echo "Scanning "$TFM_DIRECTORY_NAME" dir to find all .c and .h files to check ..."
#Modify checkpatch command line to make checkpatch work on files.
CHECKPATCH_CMD="$CHECKPATCH_CMD -f "
if [ $VERBOSE -eq 1 ]; then
eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} |tee -a "$OUTPUT_FILE_PATH"
else
eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} >> $OUTPUT_FILE_PATH
fi
}
##@fn check_diff()
##@brief Run checkpatch in git diff mode.
##@returns status code
##
##Execute checkpatch to check the last N (\ref CHECK_LAST_COMMITS) commits of
##the branch checked out at directory specified in \ref TFM_DIRECTORY_NAME.
##Directory content specified in \ref SKIP_PATHS will be excluded.
##
#This is needed for Doxygen for now.
#!void check_diff(){};
check_diff() {
BASE_COMMIT="HEAD~$CHECK_LAST_COMMITS"
#use find to limit diff content to the same set of files as when checking
#the whole tree.
FIND_CMD="find ./ -name '*.[ch]' -a -not \( -path "${SKIP_PATHS//:/ -o -path }" \)"
#enter tf-m working copy to make git commands execute fine
pushd "$TFM_DIRECTORY_NAME" > /dev/null
#Execute popd when shell exits
trap popd 0
#List of files we care about. Filter out changed files from interesting
#list of files. This is needed to avoid GIT_CMD to break the argument
#list length.
CARE_LIST=$(eval $FIND_CMD | grep "$(git diff $BASE_COMMIT --name-only)" -)
if [ ! -z "$CARE_LIST" ]; then
# Only run checkpatch if there are files to check
GIT_CMD="git diff $BASE_COMMIT -- $CARE_LIST"
echo "$GIT_CMD"
echo "Checking commits: $(git log "$BASE_COMMIT"..HEAD --format=%h | tr $"\n" " ")"
#Modify checkpatch parameters to give more details when working on
#diff:s
CHECKPATCH_CMD="$CHECKPATCH_CMD --showfile -"
fi
if [ $VERBOSE -eq 1 ]; then
$GIT_CMD | $CHECKPATCH_CMD | tee -a "$OUTPUT_FILE_PATH"
else
$GIT_CMD | $CHECKPATCH_CMD >> $OUTPUT_FILE_PATH
fi
popd > /dev/null
#Remove cleanup trap.
trap 0
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~ Entry point ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Internal variables not to be modified.
VERBOSE=0
UPDATE_CHECKPATCH_FILES=0
##@var CHECK_LAST_COMMITS
##@brief Number of commits to check.
##
##Number of commits relative to HEAD to check. When set to 0 full file content
##is checked instead of commit diffs.
##
#This is needed for Doxygen for now.
#!path CHECK_LAST_COMMITS;
CHECK_LAST_COMMITS=0
# Getting options and setting variables required to execute the script. This
# script starts executing from here.
while getopts "uvhd:f:l:p:" opt
do
case $opt in
v) VERBOSE=1 ;;
h) usage ; exit 0 ;;
d) TFM_DIRECTORY_NAME="$OPTARG" ;;
f) OUTPUT_FILE_PATH="$OPTARG" ;;
u) UPDATE_CHECKPATCH_FILES=1 ;;
l) CHECK_LAST_COMMITS="$OPTARG" ;;
p) CHECKPATCH_PATH="$OPTARG" ;;
\?) usage ; exit 1 ;;
esac
done
# Update checkpatch files
if [ $UPDATE_CHECKPATCH_FILES -eq 1 ]; then
update_checkpatch
echo "Checkpatch update was successfull."
exit 0
fi
#Convert checkpath override path to full path
CHECKPATCH_PATH=$(readlink -f "$CHECKPATCH_PATH")
#Convert output file name to full path
OUTPUT_FILE_PATH=$(readlink -f "$OUTPUT_FILE_PATH")
# Create checkpatch command
CHECKPATCH_APP=$CHECKPATCH_PATH"/checkpatch.pl"
CHECKPATCH_CONFG_FILENAME=$CHECKPATCH_PATH_DEF"/checkpatch.conf"
CHECKPATCH_CMD=$CHECKPATCH_APP" $(grep -o '^[^#]*' $CHECKPATCH_CONFG_FILENAME)"
# Check if checkpatch is present
if ! [ -f "$CHECKPATCH_APP" ]; then
app_err "checkpatch.pl was not found. checkpatch.pl has to be located in $CHECKPATCH_PATH"
exit 1
fi
#Truncate previous content
: > $OUTPUT_FILE_PATH
#Do we need to work on a git diff?
if [ $CHECK_LAST_COMMITS -eq 0 ]
then
#Working on files
check_tree
else
#Working on git diff
check_diff
fi
echo "checkpatch report \"$OUTPUT_FILE_PATH\" is ready!"