Skip to content

Commit e6cd19c

Browse files
committed
install.sh: rework for better error reporting and fix some bugs.
Fix a bug where auto_venv.sh was being created in a non-existent directory. Trap exit codes for some commands and add some help text + GitHUb url at the end of the install process. Try to comment what some sections do, and insert linebreaks so they are more logically broken up in the installer output. Try to be more consistent with colours. Try to be more friendly with colours- remove full red warning text in favour of a prefix so the errors/warnings are easier to read. Return a failure exit code if bits of the script have failed. Try to re-order output so it's more logical. Re-word venv creation message.
1 parent a1f67c9 commit e6cd19c

File tree

1 file changed

+102
-42
lines changed

1 file changed

+102
-42
lines changed

install.sh

Lines changed: 102 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ CONFIG_DIR="/boot/firmware"
55
DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"`
66
CONFIG_BACKUP=false
77
APT_HAS_UPDATED=false
8-
RESOURCES_TOP_DIR=$HOME/Pimoroni
9-
VENV_BASH_SNIPPET=$RESOURCES_TOP_DIR/auto_venv.sh
10-
VENV_DIR=$HOME/.virtualenvs/pimoroni
8+
RESOURCES_TOP_DIR="$HOME/Pimoroni"
9+
VENV_BASH_SNIPPET="$RESOURCES_TOP_DIR/auto_venv.sh"
10+
VENV_DIR="$HOME/.virtualenvs/pimoroni"
1111
WD=`pwd`
1212
USAGE="./install.sh (--unstable)"
1313
POSITIONAL_ARGS=()
1414
FORCE=false
1515
UNSTABLE=false
1616
PYTHON="python"
17+
CMD_ERRORS=false
1718

1819

1920
user_check() {
2021
if [ $(id -u) -eq 0 ]; then
21-
printf "Script should not be run as root. Try './install.sh'\n"
22-
exit 1
22+
fatal "Script should not be run as root. Try './install.sh'\n"
2323
fi
2424
}
2525

@@ -54,29 +54,34 @@ inform() {
5454
}
5555

5656
warning() {
57-
echo -e "$(tput setaf 1)$1$(tput sgr0)"
57+
echo -e "$(tput setaf 1)⚠ WARNING:$(tput sgr0) $1"
58+
}
59+
60+
fatal() {
61+
echo -e "$(tput setaf 1)⚠ FATAL:$(tput sgr0) $1"
62+
exit 1
5863
}
5964

6065
find_config() {
6166
if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then
6267
CONFIG_DIR="/boot"
63-
if [ ! -f "$CONFIG_DIR/$CONFIG_FILE"]; then
64-
warning "Could not find $CONFIG_FILE!"
65-
exit 1
68+
if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then
69+
fatal "Could not find $CONFIG_FILE!"
70+
fi
71+
else
72+
if [ -f "/boot/$CONFIG_FILE" ] && [ ! -L "/boot/$CONFIG_FILE" ]; then
73+
warning "Oops! It looks like /boot/$CONFIG_FILE is not a link to $CONFIG_DIR/$CONFIG_FILE"
74+
warning "You might want to fix this!"
6675
fi
67-
else
68-
if [ -f "/boot/$CONFIG_FILE" ] && [ ! -L "/boot/$CONFIG_FILE" ]; then
69-
warning "Oops! It looks like /boot/$CONFIG_FILE is not a link to $CONFIG_DIR/$CONFIG_FILE"
70-
warning "You might want to fix this!"
71-
fi
7276
fi
73-
inform "Using $CONFIG_FILE in $CONFIG_DIR"
77+
inform "Using $CONFIG_FILE in $CONFIG_DIR"
7478
}
7579

7680
venv_bash_snippet() {
77-
inform "Checking for $VENV_BASH_SNIPPET\n"
81+
inform "Checking for $VENV_BASH_SNIPPET\n"
7882
if [ ! -f $VENV_BASH_SNIPPET ]; then
79-
inform "Creating $VENV_BASH_SNIPPET\n"
83+
inform "Creating $VENV_BASH_SNIPPET\n"
84+
mkdir -p $RESOURCES_TOP_DIR
8085
cat << EOF > $VENV_BASH_SNIPPET
8186
# Add "source $VENV_BASH_SNIPPET" to your ~/.bashrc to activate
8287
# the Pimoroni virtual environment automagically!
@@ -96,23 +101,32 @@ venv_check() {
96101
PYTHON_BIN=`which $PYTHON`
97102
if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then
98103
printf "This script should be run in a virtual Python environment.\n"
99-
if confirm "Would you like us to create one for you?"; then
104+
if confirm "Would you like us to create and/or use a default one?"; then
105+
printf "\n"
100106
if [ ! -f $VENV_DIR/bin/activate ]; then
101-
inform "Creating virtual Python environment in $VENV_DIR, please wait...\n"
107+
inform "Creating a new virtual Python environment in $VENV_DIR, please wait...\n"
102108
mkdir -p $VENV_DIR
103109
/usr/bin/python3 -m venv $VENV_DIR --system-site-packages
104110
venv_bash_snippet
111+
source $VENV_DIR/bin/activate
105112
else
106-
inform "Found existing virtual Python environment in $VENV_DIR\n"
113+
inform "Activating existing virtual Python environment in $VENV_DIR\n"
114+
printf "source $VENV_DIR/bin/activate\n"
115+
source $VENV_DIR/bin/activate
107116
fi
108-
inform "Activating virtual Python environment in $VENV_DIR..."
109-
inform "source $VENV_DIR/bin/activate\n"
110-
source $VENV_DIR/bin/activate
111-
112117
else
113-
exit 1
118+
printf "\n"
119+
fatal "Please create and/or activate a virtual Python environment and try again!\n"
114120
fi
115121
fi
122+
printf "\n"
123+
}
124+
125+
check_for_error() {
126+
if [ $? -ne 0 ]; then
127+
CMD_ERRORS=true
128+
warning "^^^ 😬"
129+
fi
116130
}
117131

118132
function do_config_backup {
@@ -132,6 +146,7 @@ function do_config_backup {
132146
function apt_pkg_install {
133147
PACKAGES=()
134148
PACKAGES_IN=("$@")
149+
# Check the list of packages and only run update/install if we need to
135150
for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do
136151
PACKAGE="${PACKAGES_IN[$i]}"
137152
if [ "$PACKAGE" == "" ]; then continue; fi
@@ -143,20 +158,24 @@ function apt_pkg_install {
143158
done
144159
PACKAGES="${PACKAGES[@]}"
145160
if ! [ "$PACKAGES" == "" ]; then
146-
echo "Installing missing packages: $PACKAGES"
161+
printf "\n"
162+
inform "Installing missing packages: $PACKAGES"
147163
if [ ! $APT_HAS_UPDATED ]; then
148164
sudo apt update
149165
APT_HAS_UPDATED=true
150166
fi
151167
sudo apt install -y $PACKAGES
168+
check_for_error
152169
if [ -f "$UNINSTALLER" ]; then
153170
echo "apt uninstall -y $PACKAGES" >> $UNINSTALLER
154171
fi
155172
fi
156173
}
157174

158175
function pip_pkg_install {
176+
# A null Keyring prevents pip stalling in the background
159177
PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring $PYTHON -m pip install --upgrade "$@"
178+
check_for_error
160179
}
161180

162181
while [[ $# -gt 0 ]]; do
@@ -186,30 +205,33 @@ while [[ $# -gt 0 ]]; do
186205
esac
187206
done
188207

208+
printf "Installing $LIBRARY_NAME...\n\n"
209+
189210
user_check
190211
venv_check
191212

192213
if [ ! -f `which $PYTHON` ]; then
193-
printf "Python path $PYTHON not found!\n"
194-
exit 1
214+
fatal "Python path $PYTHON not found!\n"
195215
fi
196216

197217
PYTHON_VER=`$PYTHON --version`
198218

199-
printf "$LIBRARY_NAME Python Library: Installer\n\n"
200-
201219
inform "Checking Dependencies. Please wait..."
202220

221+
# Install toml and try to read pyproject.toml into bash variables
222+
203223
pip_pkg_install toml
204224

205225
CONFIG_VARS=`$PYTHON - <<EOF
206226
import toml
207227
config = toml.load("pyproject.toml")
228+
github_url = config['project']['urls']['GitHub']
208229
p = dict(config['tool']['pimoroni'])
209230
# Convert list config entries into bash arrays
210231
for k, v in p.items():
211232
v = "'\n\t'".join(v)
212233
p[k] = f"('{v}')"
234+
print(f'GITHUB_URL="{github_url}"')
213235
print("""
214236
APT_PACKAGES={apt_packages}
215237
SETUP_CMDS={commands}
@@ -218,8 +240,8 @@ CONFIG_TXT={configtxt}
218240
EOF`
219241
220242
if [ $? -ne 0 ]; then
221-
warning "Error parsing configuration...\n"
222-
exit 1
243+
# This is bad, this should not happen in production!
244+
fatal "Error parsing configuration...\n"
223245
fi
224246
225247
eval $CONFIG_VARS
@@ -229,13 +251,17 @@ UNINSTALLER=$RESOURCES_DIR/uninstall.sh
229251
230252
RES_DIR_OWNER=`stat -c "%U" $RESOURCES_TOP_DIR`
231253
254+
# Previous install.sh scripts were run as root with sudo, which caused
255+
# the ~/Pimoroni dir to be created with root ownership. Try and fix it.
232256
if [[ "$RES_DIR_OWNER" == "root" ]]; then
233257
warning "\n\nFixing $RESOURCES_TOP_DIR permissions!\n\n"
234258
sudo chown -R $USER:$USER $RESOURCES_TOP_DIR
235259
fi
236260
237261
mkdir -p $RESOURCES_DIR
238262
263+
# Create a stub uninstaller file, we'll try to add the inverse of every
264+
# install command run to here, though it's not complete.
239265
cat << EOF > $UNINSTALLER
240266
printf "It's recommended you run these steps manually.\n"
241267
printf "If you want to run the full script, open it in\n"
@@ -244,19 +270,23 @@ exit 1
244270
source $VIRTUAL_ENV/bin/activate
245271
EOF
246272
247-
if $UNSTABLE; then
248-
warning "Installing unstable library from source.\n\n"
249-
else
250-
printf "Installing stable library from pypi.\n\n"
251-
fi
273+
printf "\n"
252274
253275
inform "Installing for $PYTHON_VER...\n"
276+
277+
# Install apt packages from pyproject.toml / tool.pimoroni.apt_packages
254278
apt_pkg_install "${APT_PACKAGES[@]}"
279+
280+
printf "\n"
281+
255282
if $UNSTABLE; then
283+
warning "Installing unstable library from source.\n"
256284
pip_pkg_install .
257285
else
286+
inform "Installing stable library from pypi.\n"
258287
pip_pkg_install $LIBRARY_NAME
259288
fi
289+
260290
if [ $? -eq 0 ]; then
261291
success "Done!\n"
262292
echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> $UNINSTALLER
@@ -266,27 +296,38 @@ cd $WD
266296
267297
find_config
268298
299+
# Run the setup commands from pyproject.toml / tool.pimoroni.commands
300+
269301
for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do
270302
CMD="${SETUP_CMDS[$i]}"
271303
# Attempt to catch anything that touches config.txt and trigger a backup
272304
if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG_DIR/$CONFIG_FILE"* ]] || [[ "$CMD" == *"\$CONFIG_DIR/\$CONFIG_FILE"* ]]; then
273305
do_config_backup
274306
fi
275307
eval $CMD
308+
check_for_error
276309
done
277310
311+
printf "\n"
312+
313+
# Add the config.txt entries from pyproject.toml / tool.pimoroni.configtxt
314+
278315
for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do
279316
CONFIG_LINE="${CONFIG_TXT[$i]}"
280317
if ! [ "$CONFIG_LINE" == "" ]; then
281318
do_config_backup
282-
inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE\n"
319+
inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE"
283320
sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG_DIR/$CONFIG_FILE
284321
if ! grep -q "^$CONFIG_LINE" $CONFIG_DIR/$CONFIG_FILE; then
285322
printf "$CONFIG_LINE\n" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE
286323
fi
287324
fi
288325
done
289326
327+
printf "\n"
328+
329+
# Just a straight copy of the examples/ dir into ~/Pimoroni/board/examples
330+
290331
if [ -d "examples" ]; then
291332
if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then
292333
inform "Copying examples to $RESOURCES_DIR"
@@ -298,9 +339,12 @@ fi
298339
299340
printf "\n"
300341
342+
# Use pdoc to generate basic documentation from the installed module
343+
301344
if confirm "Would you like to generate documentation?"; then
345+
inform "Installing pdoc. Please wait..."
302346
pip_pkg_install pdoc
303-
printf "Generating documentation.\n"
347+
inform "Generating documentation.\n"
304348
$PYTHON -m pdoc $LIBRARY_NAME -o $RESOURCES_DIR/docs > /dev/null
305349
if [ $? -eq 0 ]; then
306350
inform "Documentation saved to $RESOURCES_DIR/docs"
@@ -310,6 +354,22 @@ if confirm "Would you like to generate documentation?"; then
310354
fi
311355
fi
312356
313-
success "\nAll done!"
314-
inform "If this is your first time installing you should reboot for hardware changes to take effect.\n"
315-
inform "Find uninstall steps in $UNINSTALLER\n"
357+
printf "\n"
358+
359+
if [ "$CMD_ERRORS" = true ]; then
360+
warning "One or more setup commands appear to have failed."
361+
printf "This might prevent things from working properly.\n"
362+
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"
364+
else
365+
success "\nAll done!"
366+
fi
367+
368+
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"
370+
371+
if [ "$CMD_ERRORS" = true ]; then
372+
exit 1
373+
else
374+
exit 0
375+
fi

0 commit comments

Comments
 (0)