| #!/usr/bin/env bash |
| |
| #------------------------------------------------------------------------------- |
| # Copyright (c) 2018-2024, 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-\*:./platform/\*:*/tz_\*:./lib/\*:./platform/ext/\*:./bl2/ext/\*:./docs/\*:./tools/\*:./interface/include/mbedtls/\*:./interface/include/psa/\*' |
| |
| ##@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 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>] [-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 " -l <number>, Check only the last <number> commits (HEAD~<number>)." |
| echo " -p <path>, Provide location of directory containing checkpatch." |
| echo " -r, Print raw output. Implies verbose." |
| 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 "run-checkpatch.sh($LINENO): Error: "$1 >&2 |
| } |
| |
| ##@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 "run-checkpatch.sh($LINENO): 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" |
| RETURN_CODE=${PIPESTATUS[1]} |
| else |
| eval "$FIND_CMD" | xargs -n 1 -i -P 8 $CHECKPATCH_CMD {} >> $OUTPUT_FILE_PATH |
| RETURN_CODE=${PIPESTATUS[1]} |
| 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 "run-checkpatch.sh($LINENO): $GIT_CMD" |
| echo "run-checkpatch.sh($LINENO): 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" |
| RETURN_CODE=${PIPESTATUS[1]} |
| else |
| $GIT_CMD | $CHECKPATCH_CMD >> $OUTPUT_FILE_PATH |
| RETURN_CODE=${PIPESTATUS[1]} |
| fi |
| |
| popd > /dev/null |
| #Remove cleanup trap. |
| trap 0 |
| } |
| |
| #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| #~~~~~~~~~~~~~~~~~~~~~~~~ Entry point ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| #Internal variables not to be modified. |
| VERBOSE=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 |
| |
| # Whether to print the output to screen. |
| RAW_OUTPUT=0 |
| |
| # Getting options and setting variables required to execute the script. This |
| # script starts executing from here. |
| while getopts "vhd:f:l:p:r" opt |
| do |
| case $opt in |
| v) VERBOSE=1 ;; |
| h) usage ; exit 0 ;; |
| d) TFM_DIRECTORY_NAME="$OPTARG" ;; |
| f) OUTPUT_FILE_PATH="$OPTARG" ;; |
| l) CHECK_LAST_COMMITS="$OPTARG" ;; |
| p) CHECKPATCH_PATH="$OPTARG" ;; |
| r) RAW_OUTPUT=1 |
| VERBOSE=1 ;; |
| \?) usage ; exit 1 ;; |
| esac |
| done |
| |
| #Convert checkpath override path to full path |
| CHECKPATCH_PATH=$(readlink -f "$CHECKPATCH_PATH") |
| |
| # Convert TF-M specific type defs file to full path |
| TFM_TYPE_DEF_FILE=$CHECKPATCH_PATH"/tfm_type_defs.txt" |
| |
| # Prepare CheckPatch config file |
| CHECKPATCH_CONFIG_FILENAME=$CHECKPATCH_PATH_DEF"/checkpatch.conf" |
| sed -i.bak "s#TFM_TYPE_DEF_FILE#$TFM_TYPE_DEF_FILE#g" $CHECKPATCH_CONFIG_FILENAME |
| |
| # Create checkpatch command |
| CHECKPATCH_APP=$CHECKPATCH_PATH"/checkpatch.pl" |
| CHECKPATCH_CMD=$CHECKPATCH_APP" $(grep -o '^[^#]*' $CHECKPATCH_CONFIG_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 |
| |
| OUTPUT_FILE_PATH=${OUTPUT_FILE_PATH:-"tfm_checkpatch_report.txt"} |
| #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 |
| |
| #Restore the contents of the config file to original values |
| sed -i.bak "s#$TFM_TYPE_DEF_FILE#TFM_TYPE_DEF_FILE#g" $CHECKPATCH_CONFIG_FILENAME |
| rm $CHECKPATCH_CONFIG_FILENAME.bak |
| |
| if [ "$RAW_OUTPUT" == "1" ] ; then |
| rm $OUTPUT_FILE_PATH |
| exit $RETURN_CODE |
| else |
| echo "run-checkpatch.sh($LINENO): checkpatch report \"$(readlink -f ${OUTPUT_FILE_PATH})\" is ready!" |
| fi |