Skip to content

Commit 5e294af

Browse files
Gadgetoiddamacus
andcommitted
QA: Add shellcheck and fix/ignore all issues.
This was inspired by and built upon Dan's PR here: pimoroni/grow-python#37 Co-authored-by: Dan Webb <dan.webb@damacus.io>
1 parent 39d73f7 commit 5e294af

File tree

5 files changed

+75
-79
lines changed

5 files changed

+75
-79
lines changed

.github/workflows/qa.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ jobs:
3333
- name: Run Code Checks
3434
run: |
3535
make check
36+
37+
- name: Run Bash Code Checks
38+
run: |
39+
make shellcheck

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@ uninstall:
3030

3131
dev-deps:
3232
python3 -m pip install -r requirements-dev.txt
33-
sudo apt install dos2unix
33+
sudo apt install dos2unix shellcheck
3434

3535
check:
3636
@bash check.sh
3737

38+
shellcheck:
39+
shellcheck *.sh
40+
3841
qa:
3942
tox -e qa
4043

check.sh

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# This script handles some basic QA checks on the source
44

55
NOPOST=$1
6-
LIBRARY_NAME=`hatch project metadata name`
7-
LIBRARY_VERSION=`hatch version | awk -F "." '{print $1"."$2"."$3}'`
8-
POST_VERSION=`hatch version | awk -F "." '{print substr($4,0,length($4))}'`
6+
LIBRARY_NAME=$(hatch project metadata name)
7+
LIBRARY_VERSION=$(hatch version | awk -F "." '{print $1"."$2"."$3}')
8+
POST_VERSION=$(hatch version | awk -F "." '{print substr($4,0,length($4))}')
99
TERM=${TERM:="xterm-256color"}
1010

1111
success() {
@@ -29,7 +29,7 @@ while [[ $# -gt 0 ]]; do
2929
;;
3030
*)
3131
if [[ $1 == -* ]]; then
32-
printf "Unrecognised option: $1\n";
32+
printf "Unrecognised option: %s\n" "$1";
3333
exit 1
3434
fi
3535
POSITIONAL_ARGS+=("$1")
@@ -40,8 +40,7 @@ done
4040
inform "Checking $LIBRARY_NAME $LIBRARY_VERSION\n"
4141

4242
inform "Checking for trailing whitespace..."
43-
grep -IUrn --color "[[:blank:]]$" --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO
44-
if [[ $? -eq 0 ]]; then
43+
if grep -IUrn --color "[[:blank:]]$" --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO; then
4544
warning "Trailing whitespace found!"
4645
exit 1
4746
else
@@ -50,8 +49,7 @@ fi
5049
printf "\n"
5150

5251
inform "Checking for DOS line-endings..."
53-
grep -lIUrn --color $'\r' --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile
54-
if [[ $? -eq 0 ]]; then
52+
if grep -lIUrn --color $'\r' --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile; then
5553
warning "DOS line-endings found!"
5654
exit 1
5755
else
@@ -60,8 +58,7 @@ fi
6058
printf "\n"
6159

6260
inform "Checking CHANGELOG.md..."
63-
cat CHANGELOG.md | grep ^${LIBRARY_VERSION} > /dev/null 2>&1
64-
if [[ $? -eq 1 ]]; then
61+
if ! grep "^${LIBRARY_VERSION}" CHANGELOG.md > /dev/null 2>&1; then
6562
warning "Changes missing for version ${LIBRARY_VERSION}! Please update CHANGELOG.md."
6663
exit 1
6764
else
@@ -70,8 +67,7 @@ fi
7067
printf "\n"
7168

7269
inform "Checking for git tag ${LIBRARY_VERSION}..."
73-
git tag -l | grep -E "${LIBRARY_VERSION}$"
74-
if [[ $? -eq 1 ]]; then
70+
if ! git tag -l | grep -E "${LIBRARY_VERSION}$"; then
7571
warning "Missing git tag for version ${LIBRARY_VERSION}"
7672
fi
7773
printf "\n"

install.sh

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
#!/bin/bash
2-
LIBRARY_NAME=`grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}'`
2+
LIBRARY_NAME=$(grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}')
33
CONFIG_FILE=config.txt
44
CONFIG_DIR="/boot/firmware"
5-
DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"`
5+
DATESTAMP=$(date "+%Y-%m-%d-%H-%M-%S")
66
CONFIG_BACKUP=false
77
APT_HAS_UPDATED=false
88
RESOURCES_TOP_DIR="$HOME/Pimoroni"
99
VENV_BASH_SNIPPET="$RESOURCES_TOP_DIR/auto_venv.sh"
1010
VENV_DIR="$HOME/.virtualenvs/pimoroni"
11-
WD=`pwd`
1211
USAGE="./install.sh (--unstable)"
1312
POSITIONAL_ARGS=()
1413
FORCE=false
@@ -18,7 +17,7 @@ CMD_ERRORS=false
1817

1918

2019
user_check() {
21-
if [ $(id -u) -eq 0 ]; then
20+
if [ "$(id -u)" -eq 0 ]; then
2221
fatal "Script should not be run as root. Try './install.sh'\n"
2322
fi
2423
}
@@ -36,15 +35,6 @@ confirm() {
3635
fi
3736
}
3837

39-
prompt() {
40-
read -r -p "$1 [y/N] " response < /dev/tty
41-
if [[ $response =~ ^(yes|y|Y)$ ]]; then
42-
true
43-
else
44-
false
45-
fi
46-
}
47-
4838
success() {
4939
echo -e "$(tput setaf 2)$1$(tput sgr0)"
5040
}
@@ -79,10 +69,10 @@ find_config() {
7969

8070
venv_bash_snippet() {
8171
inform "Checking for $VENV_BASH_SNIPPET\n"
82-
if [ ! -f $VENV_BASH_SNIPPET ]; then
72+
if [ ! -f "$VENV_BASH_SNIPPET" ]; then
8373
inform "Creating $VENV_BASH_SNIPPET\n"
84-
mkdir -p $RESOURCES_TOP_DIR
85-
cat << EOF > $VENV_BASH_SNIPPET
74+
mkdir -p "$RESOURCES_TOP_DIR"
75+
cat << EOF > "$VENV_BASH_SNIPPET"
8676
# Add "source $VENV_BASH_SNIPPET" to your ~/.bashrc to activate
8777
# the Pimoroni virtual environment automagically!
8878
VENV_DIR="$VENV_DIR"
@@ -98,21 +88,23 @@ EOF
9888
}
9989

10090
venv_check() {
101-
PYTHON_BIN=`which $PYTHON`
91+
PYTHON_BIN=$(which "$PYTHON")
10292
if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then
10393
printf "This script should be run in a virtual Python environment.\n"
10494
if confirm "Would you like us to create and/or use a default one?"; then
10595
printf "\n"
106-
if [ ! -f $VENV_DIR/bin/activate ]; then
96+
if [ ! -f "$VENV_DIR/bin/activate" ]; then
10797
inform "Creating a new virtual Python environment in $VENV_DIR, please wait...\n"
108-
mkdir -p $VENV_DIR
109-
/usr/bin/python3 -m venv $VENV_DIR --system-site-packages
98+
mkdir -p "$VENV_DIR"
99+
/usr/bin/python3 -m venv "$VENV_DIR" --system-site-packages
110100
venv_bash_snippet
111-
source $VENV_DIR/bin/activate
101+
# shellcheck disable=SC1091
102+
source "$VENV_DIR/bin/activate"
112103
else
113104
inform "Activating existing virtual Python environment in $VENV_DIR\n"
114-
printf "source $VENV_DIR/bin/activate\n"
115-
source $VENV_DIR/bin/activate
105+
printf "source \"%s/bin/activate\"\n" "$VENV_DIR"
106+
# shellcheck disable=SC1091
107+
source "$VENV_DIR/bin/activate"
116108
fi
117109
else
118110
printf "\n"
@@ -134,40 +126,40 @@ function do_config_backup {
134126
CONFIG_BACKUP=true
135127
FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt"
136128
inform "Backing up $CONFIG_DIR/$CONFIG_FILE to $CONFIG_DIR/$FILENAME\n"
137-
sudo cp $CONFIG_DIR/$CONFIG_FILE $CONFIG_DIR/$FILENAME
138-
mkdir -p $RESOURCES_TOP_DIR/config-backups/
139-
cp $CONFIG_DIR/$CONFIG_FILE $RESOURCES_TOP_DIR/config-backups/$FILENAME
129+
sudo cp "$CONFIG_DIR/$CONFIG_FILE $CONFIG_DIR/$FILENAME"
130+
mkdir -p "$RESOURCES_TOP_DIR/config-backups/"
131+
cp $CONFIG_DIR/$CONFIG_FILE "$RESOURCES_TOP_DIR/config-backups/$FILENAME"
140132
if [ -f "$UNINSTALLER" ]; then
141-
echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG_DIR/$CONFIG_FILE" >> $UNINSTALLER
133+
echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG_DIR/$CONFIG_FILE" >> "$UNINSTALLER"
142134
fi
143135
fi
144136
}
145137

146138
function apt_pkg_install {
147-
PACKAGES=()
139+
PACKAGES_NEEDED=()
148140
PACKAGES_IN=("$@")
149141
# Check the list of packages and only run update/install if we need to
150142
for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do
151143
PACKAGE="${PACKAGES_IN[$i]}"
152144
if [ "$PACKAGE" == "" ]; then continue; fi
153-
printf "Checking for $PACKAGE\n"
154-
dpkg -L $PACKAGE > /dev/null 2>&1
145+
printf "Checking for %s\n" "$PACKAGE"
146+
dpkg -L "$PACKAGE" > /dev/null 2>&1
155147
if [ "$?" == "1" ]; then
156-
PACKAGES+=("$PACKAGE")
148+
PACKAGES_NEEDED+=("$PACKAGE")
157149
fi
158150
done
159-
PACKAGES="${PACKAGES[@]}"
151+
PACKAGES="${PACKAGES_NEEDED[*]}"
160152
if ! [ "$PACKAGES" == "" ]; then
161153
printf "\n"
162154
inform "Installing missing packages: $PACKAGES"
163155
if [ ! $APT_HAS_UPDATED ]; then
164156
sudo apt update
165157
APT_HAS_UPDATED=true
166158
fi
167-
sudo apt install -y $PACKAGES
159+
sudo apt install -y "$PACKAGES"
168160
check_for_error
169161
if [ -f "$UNINSTALLER" ]; then
170-
echo "apt uninstall -y $PACKAGES" >> $UNINSTALLER
162+
echo "apt uninstall -y $PACKAGES" >> "$UNINSTALLER"
171163
fi
172164
fi
173165
}
@@ -196,33 +188,34 @@ while [[ $# -gt 0 ]]; do
196188
;;
197189
*)
198190
if [[ $1 == -* ]]; then
199-
printf "Unrecognised option: $1\n";
200-
printf "Usage: $USAGE\n";
191+
printf "Unrecognised option: %s\n" "$1";
192+
printf "Usage: %s\n" "$USAGE";
201193
exit 1
202194
fi
203195
POSITIONAL_ARGS+=("$1")
204196
shift
205197
esac
206198
done
207199

208-
printf "Installing $LIBRARY_NAME...\n\n"
200+
printf "Installing %s...\n\n" "$LIBRARY_NAME"
209201

210202
user_check
211203
venv_check
212204

213-
if [ ! -f `which $PYTHON` ]; then
214-
fatal "Python path $PYTHON not found!\n"
205+
if [ ! -f "$(which "$PYTHON")" ]; then
206+
fatal "Python path %s not found!\n" "$PYTHON"
215207
fi
216208

217-
PYTHON_VER=`$PYTHON --version`
209+
PYTHON_VER=$($PYTHON --version)
218210

219211
inform "Checking Dependencies. Please wait..."
220212

221213
# Install toml and try to read pyproject.toml into bash variables
222214

223215
pip_pkg_install toml
224216

225-
CONFIG_VARS=`$PYTHON - <<EOF
217+
CONFIG_VARS=$(
218+
$PYTHON - <<EOF
226219
import toml
227220
config = toml.load("pyproject.toml")
228221
github_url = config['project']['urls']['GitHub']
@@ -237,32 +230,34 @@ APT_PACKAGES={apt_packages}
237230
SETUP_CMDS={commands}
238231
CONFIG_TXT={configtxt}
239232
""".format(**p))
240-
EOF`
233+
EOF
234+
)
241235

236+
# shellcheck disable=SC2181 # Inlining the above command would be messy
242237
if [ $? -ne 0 ]; then
243238
# This is bad, this should not happen in production!
244239
fatal "Error parsing configuration...\n"
245240
fi
246241

247-
eval $CONFIG_VARS
242+
eval "$CONFIG_VARS"
248243

249244
RESOURCES_DIR=$RESOURCES_TOP_DIR/$LIBRARY_NAME
250245
UNINSTALLER=$RESOURCES_DIR/uninstall.sh
251246

252-
RES_DIR_OWNER=`stat -c "%U" $RESOURCES_TOP_DIR`
247+
RES_DIR_OWNER=$(stat -c "%U" "$RESOURCES_TOP_DIR")
253248

254249
# Previous install.sh scripts were run as root with sudo, which caused
255250
# the ~/Pimoroni dir to be created with root ownership. Try and fix it.
256251
if [[ "$RES_DIR_OWNER" == "root" ]]; then
257252
warning "\n\nFixing $RESOURCES_TOP_DIR permissions!\n\n"
258-
sudo chown -R $USER:$USER $RESOURCES_TOP_DIR
253+
sudo chown -R "$USER:$USER" "$RESOURCES_TOP_DIR"
259254
fi
260255

261-
mkdir -p $RESOURCES_DIR
256+
mkdir -p "$RESOURCES_DIR"
262257

263258
# Create a stub uninstaller file, we'll try to add the inverse of every
264259
# install command run to here, though it's not complete.
265-
cat << EOF > $UNINSTALLER
260+
cat << EOF > "$UNINSTALLER"
266261
printf "It's recommended you run these steps manually.\n"
267262
printf "If you want to run the full script, open it in\n"
268263
printf "an editor and remove 'exit 1' from below.\n"
@@ -284,16 +279,15 @@ if $UNSTABLE; then
284279
pip_pkg_install .
285280
else
286281
inform "Installing stable library from pypi.\n"
287-
pip_pkg_install $LIBRARY_NAME
282+
pip_pkg_install "$LIBRARY_NAME"
288283
fi
289284

285+
# shellcheck disable=SC2181 # One of two commands run, depending on --unstable flag
290286
if [ $? -eq 0 ]; then
291287
success "Done!\n"
292-
echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> $UNINSTALLER
288+
echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> "$UNINSTALLER"
293289
fi
294290

295-
cd $WD
296-
297291
find_config
298292

299293
# Run the setup commands from pyproject.toml / tool.pimoroni.commands
@@ -304,7 +298,7 @@ for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do
304298
if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG_DIR/$CONFIG_FILE"* ]] || [[ "$CMD" == *"\$CONFIG_DIR/\$CONFIG_FILE"* ]]; then
305299
do_config_backup
306300
fi
307-
eval $CMD
301+
eval "$CMD"
308302
check_for_error
309303
done
310304

@@ -319,7 +313,7 @@ for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do
319313
inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE"
320314
sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG_DIR/$CONFIG_FILE
321315
if ! grep -q "^$CONFIG_LINE" $CONFIG_DIR/$CONFIG_FILE; then
322-
printf "$CONFIG_LINE\n" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE
316+
printf "%s \n" "$CONFIG_LINE" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE
323317
fi
324318
fi
325319
done
@@ -331,8 +325,8 @@ printf "\n"
331325
if [ -d "examples" ]; then
332326
if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then
333327
inform "Copying examples to $RESOURCES_DIR"
334-
cp -r examples/ $RESOURCES_DIR
335-
echo "rm -r $RESOURCES_DIR" >> $UNINSTALLER
328+
cp -r examples/ "$RESOURCES_DIR"
329+
echo "rm -r $RESOURCES_DIR" >> "$UNINSTALLER"
336330
success "Done!"
337331
fi
338332
fi
@@ -345,8 +339,7 @@ if confirm "Would you like to generate documentation?"; then
345339
inform "Installing pdoc. Please wait..."
346340
pip_pkg_install pdoc
347341
inform "Generating documentation.\n"
348-
$PYTHON -m pdoc $LIBRARY_NAME -o $RESOURCES_DIR/docs > /dev/null
349-
if [ $? -eq 0 ]; then
342+
if $PYTHON -m pdoc "$LIBRARY_NAME" -o "$RESOURCES_DIR/docs" > /dev/null; then
350343
inform "Documentation saved to $RESOURCES_DIR/docs"
351344
success "Done!"
352345
else
@@ -360,13 +353,13 @@ if [ "$CMD_ERRORS" = true ]; then
360353
warning "One or more setup commands appear to have failed."
361354
printf "This might prevent things from working properly.\n"
362355
printf "Make sure your OS is up to date and try re-running this installer.\n"
363-
printf "If things still don't work, report this or find help at $GITHUB_URL.\n\n"
356+
printf "If things still don't work, report this or find help at %s.\n\n" "$GITHUB_URL"
364357
else
365358
success "\nAll done!"
366359
fi
367360

368361
printf "If this is your first time installing you should reboot for hardware changes to take effect.\n"
369-
printf "Find uninstall steps in $UNINSTALLER\n\n"
362+
printf "Find uninstall steps in %s\n\n" "$UNINSTALLER"
370363

371364
if [ "$CMD_ERRORS" = true ]; then
372365
exit 1

0 commit comments

Comments
 (0)