blob: 7cd070e5bd177309efaf6428399138baee56b3f9 [file] [log] [blame]
Andrew Geissler9b0105c2018-01-10 10:58:35 -08001#!/bin/bash
Patrick Williamsc1513c82022-11-27 17:37:08 -06002set -e
Andrew Geissler9b0105c2018-01-10 10:58:35 -08003
Patrick Williamsc1513c82022-11-27 17:37:08 -06004# This script reformats source files using various formatters and linters.
Andrew Geissler9b0105c2018-01-10 10:58:35 -08005#
6# Files are changed in-place, so make sure you don't have anything open in an
7# editor, and you may want to commit before formatting in case of awryness.
8#
9# This must be run on a clean repository to succeed
10#
Patrick Williamsc1513c82022-11-27 17:37:08 -060011function display_help()
12{
13 echo "usage: format-code.sh [-h | --help] "
14 echo " [<path>]"
15 echo
16 echo "Format and lint a repository."
17 echo
18 echo "Arguments:"
19 echo " path Path to git repository (default to pwd)"
20}
Andrew Geissler9b0105c2018-01-10 10:58:35 -080021
Patrick Williamsc1513c82022-11-27 17:37:08 -060022eval set -- "$(getopt -o 'h' --long 'help' -n 'format-code.sh' -- "$@")"
23while true; do
24 case "$1" in
25 '-h'|'--help')
26 display_help && exit 0
27 ;;
Andrew Geissler9b0105c2018-01-10 10:58:35 -080028
Patrick Williamsc1513c82022-11-27 17:37:08 -060029 '--')
30 shift
31 break
32 ;;
33
34 *)
35 echo "unknown option: $1"
36 display_help && exit 1
37 ;;
38 esac
39done
40
41# Detect tty and set nicer colors.
42if [ -t 1 ]; then
43 BLUE="\e[34m"
44 GREEN="\e[32m"
45 NORMAL="\e[0m"
46 RED="\e[31m"
47 YELLOW="\e[33m"
48else # non-tty, no escapes.
49 BLUE=""
50 GREEN=""
51 NORMAL=""
52 RED=""
53 YELLOW=""
54fi
55
56# Path to default config files for linters.
57CONFIG_PATH="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)/config"
58
59# Find repository root for `pwd` or $1.
60if [ -z "$1" ]; then
61 DIR="$(git rev-parse --show-toplevel || pwd)"
62else
63 DIR="$(git -C "$1" rev-parse --show-toplevel)"
64fi
65if [ ! -d "$DIR/.git" ]; then
66 echo "${RED}Error:${NORMAL} Directory ($DIR) does not appear to be a git repository"
67 exit 1
68fi
Andrew Jeffery0cce8482018-04-30 11:37:01 +093069
Manojkiran Edae6f120a2021-03-20 11:13:43 +053070cd "${DIR}"
Patrick Williamsc1513c82022-11-27 17:37:08 -060071echo -e " ${BLUE}Formatting code under${NORMAL} $DIR"
Andrew Geissler9b0105c2018-01-10 10:58:35 -080072
Patrick Williams38515a32022-11-27 06:58:56 -060073ALL_OPERATIONS=( \
Patrick Williams38515a32022-11-27 06:58:56 -060074 commit_gitlint \
75 commit_spelling \
Patrick Williamsc1513c82022-11-27 17:37:08 -060076 clang_format \
Patrick Williams38515a32022-11-27 06:58:56 -060077 eslint \
78 pycodestyle \
79 shellcheck \
80 )
Manojkiran Eda87111bb2021-08-14 11:26:16 +053081
Patrick Williams38515a32022-11-27 06:58:56 -060082function do_commit_spelling() {
Patrick Williamsc1513c82022-11-27 17:37:08 -060083 if [ ! -e .git/COMMIT_EDITMSG ]; then
84 return
85 fi
86 echo -e " ${BLUE}Running codespell${NORMAL}"
Ed Tanousac5915f2022-03-10 08:32:54 -080087
Patrick Williams38515a32022-11-27 06:58:56 -060088 # Run the codespell with openbmc spcific spellings on the patchset
89 echo "openbmc-dictionary - misspelling count >> "
Patrick Williamsc1513c82022-11-27 17:37:08 -060090 sed "s/Signed-off-by.*//" .git/COMMIT_EDITMSG | \
91 codespell -D "${CONFIG_PATH}/openbmc-spelling.txt" -d --count -
Patrick Williams38515a32022-11-27 06:58:56 -060092
93 # Run the codespell with generic dictionary on the patchset
94 echo "generic-dictionary - misspelling count >> "
Patrick Williamsc1513c82022-11-27 17:37:08 -060095 sed "s/Signed-off-by.*//" .git/COMMIT_EDITMSG | \
Patrick Williams38515a32022-11-27 06:58:56 -060096 codespell --builtin clear,rare,en-GB_to_en-US -d --count -
97}
98
99function do_commit_gitlint() {
Patrick Williamsc1513c82022-11-27 17:37:08 -0600100 echo -e " ${BLUE}Running gitlint${NORMAL}"
Patrick Williams38515a32022-11-27 06:58:56 -0600101 # Check for commit message issues
102 gitlint \
Patrick Williamsc1513c82022-11-27 17:37:08 -0600103 --extra-path "${CONFIG_PATH}/gitlint/" \
104 --config "${CONFIG_PATH}/.gitlint"
Patrick Williams38515a32022-11-27 06:58:56 -0600105}
106
107function do_eslint() {
108 if [[ -f ".eslintignore" ]]; then
109 ESLINT_IGNORE="--ignore-path .eslintignore"
110 elif [[ -f ".gitignore" ]]; then
111 ESLINT_IGNORE="--ignore-path .gitignore"
112 fi
113
114 # Get the eslint configuration from the repository
115 if [[ -f ".eslintrc.json" ]]; then
Patrick Williamsc1513c82022-11-27 17:37:08 -0600116 echo -e " ${BLUE}Running eslint${NORMAL}"
Patrick Williams38515a32022-11-27 06:58:56 -0600117 ESLINT_RC="-c .eslintrc.json"
118 else
Patrick Williamsc1513c82022-11-27 17:37:08 -0600119 echo -e " ${BLUE}Running eslint using ${YELLOW}the global config${NORMAL}"
120 ESLINT_RC="--no-eslintrc -c ${CONFIG_PATH}/eslint-global-config.json"
Patrick Williams38515a32022-11-27 06:58:56 -0600121 fi
122
123 ESLINT_COMMAND="eslint . ${ESLINT_IGNORE} ${ESLINT_RC} \
Ed Tanous0c4153b2022-08-17 10:20:26 -0700124 --ext .json --format=stylish \
Ed Tanousac5915f2022-03-10 08:32:54 -0800125 --resolve-plugins-relative-to /usr/local/lib/node_modules \
126 --no-error-on-unmatched-pattern"
127
Patrick Williams38515a32022-11-27 06:58:56 -0600128 # Print eslint command
129 echo "$ESLINT_COMMAND"
130 # Run eslint
131 $ESLINT_COMMAND
132}
Manojkiran Eda87111bb2021-08-14 11:26:16 +0530133
Patrick Williams38515a32022-11-27 06:58:56 -0600134function do_pycodestyle() {
135 if [[ -f "setup.cfg" ]]; then
Patrick Williamsc1513c82022-11-27 17:37:08 -0600136 echo -e " ${BLUE}Running pycodestyle${NORMAL}"
Patrick Williams38515a32022-11-27 06:58:56 -0600137 pycodestyle --show-source --exclude=subprojects .
138 rc=$?
139 if [[ ${rc} -ne 0 ]]; then
140 exit ${rc}
141 fi
James Feistf1665d62019-11-22 09:06:33 -0800142 fi
Patrick Williams38515a32022-11-27 06:58:56 -0600143}
James Feistf1665d62019-11-22 09:06:33 -0800144
Patrick Williams38515a32022-11-27 06:58:56 -0600145function do_shellcheck() {
146 # If .shellcheck exists, stop on error. Otherwise, allow pass.
147 if [[ -f ".shellcheck" ]]; then
148 local shellcheck_allowfail="false"
149 else
150 local shellcheck_allowfail="true"
151 fi
James Feistf1665d62019-11-22 09:06:33 -0800152
Patrick Williams38515a32022-11-27 06:58:56 -0600153 # Run shellcheck on any shell-script.
154 shell_scripts="$(git ls-files | xargs -n1 file -0 | \
155 grep -a "shell script" | cut -d '' -f 1)"
Patrick Williamsc1513c82022-11-27 17:37:08 -0600156 if [ -n "${shell_scripts}" ]; then
157 echo -e " ${BLUE}Running shellcheck${NORMAL}"
158 fi
Patrick Williams38515a32022-11-27 06:58:56 -0600159 for script in ${shell_scripts}; do
160 shellcheck --color=never -x "${script}" || ${shellcheck_allowfail}
161 done
162}
James Feistf1665d62019-11-22 09:06:33 -0800163
Patrick Williams38515a32022-11-27 06:58:56 -0600164
165do_clang_format() {
166 # Allow called scripts to know which clang format we are using
167 export CLANG_FORMAT="clang-format"
168 IGNORE_FILE=".clang-ignore"
169 declare -a IGNORE_LIST
170
171 if [[ -f "${IGNORE_FILE}" ]]; then
172 readarray -t IGNORE_LIST < "${IGNORE_FILE}"
173 fi
174
175 ignorepaths=""
176 ignorefiles=""
177
178 for path in "${IGNORE_LIST[@]}"; do
179 # Check for comment, line starting with space, or zero-length string.
180 # Checking for [[:space:]] checks all options.
181 if [[ -z "${path}" ]] || [[ "${path}" =~ ^(#|[[:space:]]).*$ ]]; then
182 continue
183 fi
184
185 # All paths must start with ./ for find's path prune expectation.
186 if [[ "${path}" =~ ^\.\/.+$ ]]; then
187 ignorepaths+=" ${path}"
188 else
189 ignorefiles+=" ${path}"
190 fi
191 done
192
193 searchfiles=""
194 while read -r path; do
195 # skip ignorefiles
196 if [[ $ignorefiles == *"$(basename "${path}")"* ]]; then
197 continue
198 fi
199
200 skip=false
201 #skip paths in ingorepaths
202 for pathname in $ignorepaths; do
203 if [[ "./${path}" == "${pathname}"* ]]; then
204 skip=true
205 break
206 fi
207 done
208
209 if [ "$skip" = true ]; then
210 continue
211 fi
212 # shellcheck disable=2089
213 searchfiles+="\"./${path}\" "
214
215 # Get C and C++ files managed by git and skip the mako files
216 done <<<"$(git ls-files | grep -e '\.[ch]pp$' -e '\.[ch]$' | grep -v '\.mako\.')"
217
218 if [[ -f ".clang-format" ]]; then
Patrick Williamsc1513c82022-11-27 17:37:08 -0600219 echo -e " ${BLUE}Running clang-format${NORMAL}"
Patrick Williams38515a32022-11-27 06:58:56 -0600220 # shellcheck disable=SC2090 disable=SC2086
221 echo ${searchfiles} | xargs "${CLANG_FORMAT}" -i
Patrick Williams38515a32022-11-27 06:58:56 -0600222 fi
223
224}
225
226for op in "${ALL_OPERATIONS[@]}"; do
227 "do_$op"
228done
Andrew Jeffery457b6d12018-03-09 15:28:14 +1030229
Patrick Williamsc1513c82022-11-27 17:37:08 -0600230echo -e " ${BLUE}Result differences...${NORMAL}"
231if ! git --no-pager diff --exit-code ; then
232 echo -e "Format: ${RED}FAILED${NORMAL}"
233 exit 1
234else
235 echo -e "Format: ${GREEN}PASSED${NORMAL}"
236fi
237
Andrew Jeffery457b6d12018-03-09 15:28:14 +1030238# Sometimes your situation is terrible enough that you need the flexibility.
239# For example, phosphor-mboxd.
Patrick Venture30ec0c42018-10-22 11:56:27 -0700240if [[ -f "format-code.sh" ]]; then
Patrick Williams38515a32022-11-27 06:58:56 -0600241 ./format-code.sh
242 git --no-pager diff --exit-code
Andrew Jeffery457b6d12018-03-09 15:28:14 +1030243fi