1#!/usr/bin/env bash 2 3readonly BASEDIR=$(readlink -f $(dirname $0))/.. 4cd $BASEDIR 5 6# exit on errors 7set -e 8 9if ! hash nproc 2>/dev/null; then 10 11function nproc() { 12 echo 8 13} 14 15fi 16 17function version_lt() { 18 [ $( echo -e "$1\n$2" | sort -V | head -1 ) != "$1" ] 19} 20 21rc=0 22 23echo -n "Checking file permissions..." 24 25while read -r perm _res0 _res1 path; do 26 if [ ! -f "$path" ]; then 27 continue 28 fi 29 30 fname=$(basename -- "$path") 31 32 case ${fname##*.} in 33 c|h|cpp|cc|cxx|hh|hpp|md|html|js|json|svg|Doxyfile|yml|LICENSE|README|conf|in|Makefile|mk|gitignore|go|txt) 34 # These file types should never be executable 35 if [ "$perm" -eq 100755 ]; then 36 echo "ERROR: $path is marked executable but is a code file." 37 rc=1 38 fi 39 ;; 40 *) 41 shebang=$(head -n 1 $path | cut -c1-3) 42 43 # git only tracks the execute bit, so will only ever return 755 or 644 as the permission. 44 if [ "$perm" -eq 100755 ]; then 45 # If the file has execute permission, it should start with a shebang. 46 if [ "$shebang" != "#!/" ]; then 47 echo "ERROR: $path is marked executable but does not start with a shebang." 48 rc=1 49 fi 50 else 51 # If the file doesnot have execute permissions, it should not start with a shebang. 52 if [ "$shebang" = "#!/" ]; then 53 echo "ERROR: $path is not marked executable but starts with a shebang." 54 rc=1 55 fi 56 fi 57 ;; 58 esac 59 60done <<< "$(git grep -I --name-only --untracked -e . | git ls-files -s)" 61 62if [ $rc -eq 0 ]; then 63 echo " OK" 64fi 65 66if hash astyle; then 67 echo -n "Checking coding style..." 68 if [ "$(astyle -V)" \< "Artistic Style Version 3" ] 69 then 70 echo -n " Your astyle version is too old so skipping coding style checks. Please update astyle to at least 3.0.1 version..." 71 else 72 rm -f astyle.log 73 touch astyle.log 74 # Exclude rte_vhost code imported from DPDK - we want to keep the original code 75 # as-is to enable ongoing work to synch with a generic upstream DPDK vhost library, 76 # rather than making diffs more complicated by a lot of changes to follow SPDK 77 # coding standards. 78 git ls-files '*.[ch]' '*.cpp' '*.cc' '*.cxx' '*.hh' '*.hpp' | \ 79 grep -v rte_vhost | grep -v cpp_headers | \ 80 xargs -P$(nproc) -n10 astyle --options=.astylerc >> astyle.log 81 if grep -q "^Formatted" astyle.log; then 82 echo " errors detected" 83 git diff 84 sed -i -e 's/ / /g' astyle.log 85 grep --color=auto "^Formatted.*" astyle.log 86 echo "Incorrect code style detected in one or more files." 87 echo "The files have been automatically formatted." 88 echo "Remember to add the files to your commit." 89 rc=1 90 else 91 echo " OK" 92 fi 93 rm -f astyle.log 94 fi 95else 96 echo "You do not have astyle installed so your code style is not being checked!" 97fi 98 99GIT_VERSION=$( git --version | cut -d' ' -f3 ) 100 101if version_lt "1.9.5" "${GIT_VERSION}"; then 102 # git <1.9.5 doesn't support pathspec magic exclude 103 echo " Your git version is too old to perform all tests. Please update git to at least 1.9.5 version..." 104 exit 0 105fi 106 107echo -n "Checking comment style..." 108 109git grep --line-number -e '/[*][^ *-]' -- '*.[ch]' > comment.log || true 110git grep --line-number -e '[^ ][*]/' -- '*.[ch]' ':!lib/rte_vhost*/*' >> comment.log || true 111git grep --line-number -e '^[*]' -- '*.[ch]' >> comment.log || true 112git grep --line-number -e '\s//' -- '*.[ch]' >> comment.log || true 113git grep --line-number -e '^//' -- '*.[ch]' >> comment.log || true 114 115if [ -s comment.log ]; then 116 echo " Incorrect comment formatting detected" 117 cat comment.log 118 rc=1 119else 120 echo " OK" 121fi 122rm -f comment.log 123 124echo -n "Checking for spaces before tabs..." 125git grep --line-number $' \t' -- './*' ':!*.patch' > whitespace.log || true 126if [ -s whitespace.log ]; then 127 echo " Spaces before tabs detected" 128 cat whitespace.log 129 rc=1 130else 131 echo " OK" 132fi 133rm -f whitespace.log 134 135echo -n "Checking trailing whitespace in output strings..." 136 137git grep --line-number -e ' \\n"' -- '*.[ch]' > whitespace.log || true 138 139if [ -s whitespace.log ]; then 140 echo " Incorrect trailing whitespace detected" 141 cat whitespace.log 142 rc=1 143else 144 echo " OK" 145fi 146rm -f whitespace.log 147 148echo -n "Checking for use of forbidden library functions..." 149 150git grep --line-number -w '\(atoi\|atol\|atoll\|strncpy\|strcpy\|strcat\|sprintf\|vsprintf\)' -- './*.c' ':!lib/rte_vhost*/**' > badfunc.log || true 151if [ -s badfunc.log ]; then 152 echo " Forbidden library functions detected" 153 cat badfunc.log 154 rc=1 155else 156 echo " OK" 157fi 158rm -f badfunc.log 159 160echo -n "Checking for use of forbidden CUnit macros..." 161 162git grep --line-number -w 'CU_ASSERT_FATAL' -- 'test/*' ':!test/spdk_cunit.h' > badcunit.log || true 163if [ -s badcunit.log ]; then 164 echo " Forbidden CU_ASSERT_FATAL usage detected - use SPDK_CU_ASSERT_FATAL instead" 165 cat badcunit.log 166 rc=1 167else 168 echo " OK" 169fi 170rm -f badcunit.log 171 172echo -n "Checking blank lines at end of file..." 173 174if ! git grep -I -l -e . -z './*' ':!*.patch' | \ 175 xargs -0 -P$(nproc) -n1 scripts/eofnl > eofnl.log; then 176 echo " Incorrect end-of-file formatting detected" 177 cat eofnl.log 178 rc=1 179else 180 echo " OK" 181fi 182rm -f eofnl.log 183 184echo -n "Checking for POSIX includes..." 185git grep -I -i -f scripts/posix.txt -- './*' ':!include/spdk/stdinc.h' ':!include/linux/**' ':!lib/rte_vhost*/**' ':!scripts/posix.txt' ':!*.patch' > scripts/posix.log || true 186if [ -s scripts/posix.log ]; then 187 echo "POSIX includes detected. Please include spdk/stdinc.h instead." 188 cat scripts/posix.log 189 rc=1 190else 191 echo " OK" 192fi 193rm -f scripts/posix.log 194 195echo -n "Checking #include style..." 196git grep -I -i --line-number "#include <spdk/" -- '*.[ch]' > scripts/includes.log || true 197if [ -s scripts/includes.log ]; then 198 echo "Incorrect #include syntax. #includes of spdk/ files should use quotes." 199 cat scripts/includes.log 200 rc=1 201else 202 echo " OK" 203fi 204rm -f scripts/includes.log 205 206if hash pycodestyle 2>/dev/null; then 207 PEP8=pycodestyle 208elif hash pep8 2>/dev/null; then 209 PEP8=pep8 210fi 211 212if [ -n "${PEP8}" ]; then 213 echo -n "Checking Python style..." 214 215 PEP8_ARGS+=" --max-line-length=140" 216 217 error=0 218 git ls-files '*.py' | xargs -P$(nproc) -n1 $PEP8 $PEP8_ARGS > pep8.log || error=1 219 if [ $error -ne 0 ]; then 220 echo " Python formatting errors detected" 221 cat pep8.log 222 rc=1 223 else 224 echo " OK" 225 fi 226 rm -f pep8.log 227else 228 echo "You do not have pycodestyle or pep8 installed so your Python style is not being checked!" 229fi 230 231if hash shellcheck 2>/dev/null; then 232 echo -n "Checking Bash style..." 233 234 shellcheck_v=$(shellcheck --version | grep -P "version: [0-9\.]+" | cut -d " " -f2) 235 236 # SHCK_EXCLUDE contains a list of all of the spellcheck errors found in SPDK scripts 237 # currently. New errors should only be added to this list if the cost of fixing them 238 # is deemed too high. For more information about the errors, go to: 239 # https://github.com/koalaman/shellcheck/wiki/Checks 240 # Error descriptions can also be found at: https://github.com/koalaman/shellcheck/wiki 241 # SPDK fails some error checks which have been deprecated in later versions of shellcheck. 242 # We will not try to fix these error checks, but instead just leave the error types here 243 # so that we can still run with older versions of shellcheck. 244 SHCK_EXCLUDE="SC1117" 245 # SPDK has decided to not fix violations of these errors. 246 # We are aware about below exclude list and we want this errors to be excluded. 247 # SC1083: This {/} is literal. Check expression (missing ;/\n?) or quote it. 248 # SC1090: Can't follow non-constant source. Use a directive to specify location. 249 # SC1091: Not following: (error message here) 250 # SC2001: See if you can use ${variable//search/replace} instead. 251 # SC2010: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames. 252 # SC2015: Note that A && B || C is not if-then-else. C may run when A is true. 253 # SC2016: Expressions don't expand in single quotes, use double quotes for that. 254 # SC2034: foo appears unused. Verify it or export it. 255 # SC2046: Quote this to prevent word splitting. 256 # SC2086: Double quote to prevent globbing and word splitting. 257 # SC2119: Use foo "$@" if function's $1 should mean script's $1. 258 # SC2120: foo references arguments, but none are ever passed. 259 # SC2148: Add shebang to the top of your script. 260 # SC2153: Possible Misspelling: MYVARIABLE may not be assigned, but MY_VARIABLE is. 261 # SC2154: var is referenced but not assigned. 262 # SC2164: Use cd ... || exit in case cd fails. 263 # SC2174: When used with -p, -m only applies to the deepest directory. 264 # SC2206: Quote to prevent word splitting/globbing, 265 # or split robustly with mapfile or read -a. 266 # SC2207: Prefer mapfile or read -a to split command output (or quote to avoid splitting). 267 # SC2223: This default assignment may cause DoS due to globbing. Quote it. 268 SHCK_EXCLUDE="$SHCK_EXCLUDE,SC1083,SC1090,SC1091,SC2010,SC2015,SC2016,SC2034,SC2046,SC2086,\ 269SC2119,SC2120,SC2148,SC2153,SC2154,SC2164,SC2174,SC2001,SC2206,SC2207,SC2223" 270 271 SHCK_FORMAT="diff" 272 SHCK_APPLY=true 273 if [ "$shellcheck_v" \< "0.7.0" ]; then 274 SHCK_FORMAT="tty" 275 SHCK_APPLY=false 276 fi 277 SHCH_ARGS=" -x -e $SHCK_EXCLUDE -f $SHCK_FORMAT" 278 279 error=0 280 git ls-files '*.sh' | xargs -P$(nproc) -n1 shellcheck $SHCH_ARGS &> shellcheck.log || error=1 281 if [ $error -ne 0 ]; then 282 echo " Bash formatting errors detected!" 283 284 # Some errors are not auto-fixable. Fall back to tty output. 285 if grep -q "Use another format to see them." shellcheck.log; then 286 SHCK_FORMAT="tty" 287 SHCK_APPLY=false 288 SHCH_ARGS=" -e $SHCK_EXCLUDE -f $SHCK_FORMAT" 289 git ls-files '*.sh' | xargs -P$(nproc) -n1 shellcheck $SHCH_ARGS > shellcheck.log || error=1 290 fi 291 292 cat shellcheck.log 293 if $SHCK_APPLY; then 294 git apply shellcheck.log 295 echo "Bash errors were automatically corrected." 296 echo "Please remember to add the changes to your commit." 297 fi 298 rc=1 299 else 300 echo " OK" 301 fi 302 rm -f shellcheck.log 303else 304 echo "You do not have shellcheck installed so your Bash style is not being checked!" 305fi 306 307# Check if any of the public interfaces were modified by this patch. 308# Warn the user to consider updating the changelog any changes 309# are detected. 310echo -n "Checking whether CHANGELOG.md should be updated..." 311staged=$(git diff --name-only --cached .) 312working=$(git status -s --porcelain --ignore-submodules | grep -iv "??" | awk '{print $2}') 313files="$staged $working" 314if [[ "$files" = " " ]]; then 315 files=$(git diff-tree --no-commit-id --name-only -r HEAD) 316fi 317 318has_changelog=0 319for f in $files; do 320 if [[ $f == CHANGELOG.md ]]; then 321 # The user has a changelog entry, so exit. 322 has_changelog=1 323 break 324 fi 325done 326 327needs_changelog=0 328if [ $has_changelog -eq 0 ]; then 329 for f in $files; do 330 if [[ $f == include/spdk/* ]] || [[ $f == scripts/rpc.py ]] || [[ $f == etc/* ]]; then 331 echo "" 332 echo -n "$f was modified. Consider updating CHANGELOG.md." 333 needs_changelog=1 334 fi 335 done 336fi 337 338if [ $needs_changelog -eq 0 ]; then 339 echo " OK" 340else 341 echo "" 342fi 343 344exit $rc 345