Skip to content

Commit 8134ffa

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 9d2b4c8 commit 8134ffa

File tree

1 file changed

+123
-42
lines changed

1 file changed

+123
-42
lines changed

install.sh

Lines changed: 123 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
#!/bin/bash
22
LIBRARY_NAME=`grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}'`
3-
CONFIG=/boot/config.txt
3+
CONFIG_FILE=config.txt
4+
CONFIG_DIR="/boot/firmware"
45
DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"`
56
CONFIG_BACKUP=false
67
APT_HAS_UPDATED=false
7-
RESOURCES_TOP_DIR=$HOME/Pimoroni
8-
VENV_BASH_SNIPPET=$RESOURCES_DIR/auto_venv.sh
9-
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"
1011
WD=`pwd`
1112
USAGE="./install.sh (--unstable)"
1213
POSITIONAL_ARGS=()
1314
FORCE=false
1415
UNSTABLE=false
1516
PYTHON="python"
17+
CMD_ERRORS=false
1618

1719

1820
user_check() {
1921
if [ $(id -u) -eq 0 ]; then
20-
printf "Script should not be run as root. Try './install.sh'\n"
21-
exit 1
22+
fatal "Script should not be run as root. Try './install.sh'\n"
2223
fi
2324
}
2425

@@ -53,13 +54,36 @@ inform() {
5354
}
5455

5556
warning() {
56-
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
63+
}
64+
65+
find_config() {
66+
if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then
67+
CONFIG_DIR="/boot"
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!"
75+
fi
76+
fi
77+
inform "Using $CONFIG_FILE in $CONFIG_DIR"
5778
}
5879

5980
venv_bash_snippet() {
81+
inform "Checking for $VENV_BASH_SNIPPET\n"
6082
if [ ! -f $VENV_BASH_SNIPPET ]; then
83+
inform "Creating $VENV_BASH_SNIPPET\n"
84+
mkdir -p $RESOURCES_TOP_DIR
6185
cat << EOF > $VENV_BASH_SNIPPET
62-
# Add `source $RESOURCES_DIR/auto_venv.sh` to your ~/.bashrc to activate
86+
# Add "source $VENV_BASH_SNIPPET" to your ~/.bashrc to activate
6387
# the Pimoroni virtual environment automagically!
6488
VENV_DIR="$VENV_DIR"
6589
if [ ! -f \$VENV_DIR/bin/activate ]; then
@@ -77,42 +101,52 @@ venv_check() {
77101
PYTHON_BIN=`which $PYTHON`
78102
if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then
79103
printf "This script should be run in a virtual Python environment.\n"
80-
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"
81106
if [ ! -f $VENV_DIR/bin/activate ]; then
82-
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"
83108
mkdir -p $VENV_DIR
84109
/usr/bin/python3 -m venv $VENV_DIR --system-site-packages
85110
venv_bash_snippet
111+
source $VENV_DIR/bin/activate
86112
else
87-
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
88116
fi
89-
inform "Activating virtual Python environment in $VENV_DIR..."
90-
inform "source $VENV_DIR/bin/activate\n"
91-
source $VENV_DIR/bin/activate
92-
93117
else
94-
exit 1
118+
printf "\n"
119+
fatal "Please create and/or activate a virtual Python environment and try again!\n"
95120
fi
96121
fi
122+
printf "\n"
123+
}
124+
125+
check_for_error() {
126+
if [ $? -ne 0 ]; then
127+
CMD_ERRORS=true
128+
warning "^^^ 😬"
129+
fi
97130
}
98131

99132
function do_config_backup {
100133
if [ ! $CONFIG_BACKUP == true ]; then
101134
CONFIG_BACKUP=true
102135
FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt"
103-
inform "Backing up $CONFIG to /boot/$FILENAME\n"
104-
sudo cp $CONFIG /boot/$FILENAME
136+
inform "Backing up $CONFIG_DIR/$CONFIG_FILE to $CONFIG_DIR/$FILENAME\n"
137+
sudo cp $CONFIG_DIR/$CONFIG_FILE $CONFIG_DIR/$FILENAME
105138
mkdir -p $RESOURCES_TOP_DIR/config-backups/
106-
cp $CONFIG $RESOURCES_TOP_DIR/config-backups/$FILENAME
139+
cp $CONFIG_DIR/$CONFIG_FILE $RESOURCES_TOP_DIR/config-backups/$FILENAME
107140
if [ -f "$UNINSTALLER" ]; then
108-
echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG" >> $UNINSTALLER
141+
echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG_DIR/$CONFIG_FILE" >> $UNINSTALLER
109142
fi
110143
fi
111144
}
112145

113146
function apt_pkg_install {
114147
PACKAGES=()
115148
PACKAGES_IN=("$@")
149+
# Check the list of packages and only run update/install if we need to
116150
for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do
117151
PACKAGE="${PACKAGES_IN[$i]}"
118152
if [ "$PACKAGE" == "" ]; then continue; fi
@@ -124,20 +158,24 @@ function apt_pkg_install {
124158
done
125159
PACKAGES="${PACKAGES[@]}"
126160
if ! [ "$PACKAGES" == "" ]; then
127-
echo "Installing missing packages: $PACKAGES"
161+
printf "\n"
162+
inform "Installing missing packages: $PACKAGES"
128163
if [ ! $APT_HAS_UPDATED ]; then
129164
sudo apt update
130165
APT_HAS_UPDATED=true
131166
fi
132167
sudo apt install -y $PACKAGES
168+
check_for_error
133169
if [ -f "$UNINSTALLER" ]; then
134170
echo "apt uninstall -y $PACKAGES" >> $UNINSTALLER
135171
fi
136172
fi
137173
}
138174

139175
function pip_pkg_install {
176+
# A null Keyring prevents pip stalling in the background
140177
PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring $PYTHON -m pip install --upgrade "$@"
178+
check_for_error
141179
}
142180

143181
while [[ $# -gt 0 ]]; do
@@ -167,30 +205,33 @@ while [[ $# -gt 0 ]]; do
167205
esac
168206
done
169207

208+
printf "Installing $LIBRARY_NAME...\n\n"
209+
170210
user_check
171211
venv_check
172212

173213
if [ ! -f `which $PYTHON` ]; then
174-
printf "Python path $PYTHON not found!\n"
175-
exit 1
214+
fatal "Python path $PYTHON not found!\n"
176215
fi
177216

178217
PYTHON_VER=`$PYTHON --version`
179218

180-
printf "$LIBRARY_NAME Python Library: Installer\n\n"
181-
182219
inform "Checking Dependencies. Please wait..."
183220

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

186225
CONFIG_VARS=`$PYTHON - <<EOF
187226
import toml
188227
config = toml.load("pyproject.toml")
228+
github_url = config['project']['urls']['GitHub']
189229
p = dict(config['tool']['pimoroni'])
190230
# Convert list config entries into bash arrays
191231
for k, v in p.items():
192232
v = "'\n\t'".join(v)
193233
p[k] = f"('{v}')"
234+
print(f'GITHUB_URL="{github_url}"')
194235
print("""
195236
APT_PACKAGES={apt_packages}
196237
SETUP_CMDS={commands}
@@ -199,8 +240,8 @@ CONFIG_TXT={configtxt}
199240
EOF`
200241
201242
if [ $? -ne 0 ]; then
202-
warning "Error parsing configuration...\n"
203-
exit 1
243+
# This is bad, this should not happen in production!
244+
fatal "Error parsing configuration...\n"
204245
fi
205246
206247
eval $CONFIG_VARS
@@ -210,13 +251,17 @@ UNINSTALLER=$RESOURCES_DIR/uninstall.sh
210251
211252
RES_DIR_OWNER=`stat -c "%U" $RESOURCES_TOP_DIR`
212253
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.
213256
if [[ "$RES_DIR_OWNER" == "root" ]]; then
214257
warning "\n\nFixing $RESOURCES_TOP_DIR permissions!\n\n"
215258
sudo chown -R $USER:$USER $RESOURCES_TOP_DIR
216259
fi
217260
218261
mkdir -p $RESOURCES_DIR
219262
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.
220265
cat << EOF > $UNINSTALLER
221266
printf "It's recommended you run these steps manually.\n"
222267
printf "If you want to run the full script, open it in\n"
@@ -225,47 +270,64 @@ exit 1
225270
source $VIRTUAL_ENV/bin/activate
226271
EOF
227272
228-
if $UNSTABLE; then
229-
warning "Installing unstable library from source.\n\n"
230-
else
231-
printf "Installing stable library from pypi.\n\n"
232-
fi
273+
printf "\n"
233274
234275
inform "Installing for $PYTHON_VER...\n"
276+
277+
# Install apt packages from pyproject.toml / tool.pimoroni.apt_packages
235278
apt_pkg_install "${APT_PACKAGES[@]}"
279+
280+
printf "\n"
281+
236282
if $UNSTABLE; then
283+
warning "Installing unstable library from source.\n"
237284
pip_pkg_install .
238285
else
286+
inform "Installing stable library from pypi.\n"
239287
pip_pkg_install $LIBRARY_NAME
240288
fi
289+
241290
if [ $? -eq 0 ]; then
242291
success "Done!\n"
243292
echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> $UNINSTALLER
244293
fi
245294
246295
cd $WD
247296
297+
find_config
298+
299+
# Run the setup commands from pyproject.toml / tool.pimoroni.commands
300+
248301
for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do
249302
CMD="${SETUP_CMDS[$i]}"
250-
# Attempt to catch anything that touches /boot/config.txt and trigger a backup
251-
if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG"* ]] || [[ "$CMD" == *"\$CONFIG"* ]]; then
303+
# Attempt to catch anything that touches config.txt and trigger a backup
304+
if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG_DIR/$CONFIG_FILE"* ]] || [[ "$CMD" == *"\$CONFIG_DIR/\$CONFIG_FILE"* ]]; then
252305
do_config_backup
253306
fi
254307
eval $CMD
308+
check_for_error
255309
done
256310
311+
printf "\n"
312+
313+
# Add the config.txt entries from pyproject.toml / tool.pimoroni.configtxt
314+
257315
for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do
258316
CONFIG_LINE="${CONFIG_TXT[$i]}"
259317
if ! [ "$CONFIG_LINE" == "" ]; then
260318
do_config_backup
261-
inform "Adding $CONFIG_LINE to $CONFIG\n"
262-
sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG
263-
if ! grep -q "^$CONFIG_LINE" $CONFIG; then
264-
printf "$CONFIG_LINE\n" | sudo tee --append $CONFIG
319+
inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE"
320+
sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG_DIR/$CONFIG_FILE
321+
if ! grep -q "^$CONFIG_LINE" $CONFIG_DIR/$CONFIG_FILE; then
322+
printf "$CONFIG_LINE\n" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE
265323
fi
266324
fi
267325
done
268326
327+
printf "\n"
328+
329+
# Just a straight copy of the examples/ dir into ~/Pimoroni/board/examples
330+
269331
if [ -d "examples" ]; then
270332
if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then
271333
inform "Copying examples to $RESOURCES_DIR"
@@ -277,9 +339,12 @@ fi
277339
278340
printf "\n"
279341
342+
# Use pdoc to generate basic documentation from the installed module
343+
280344
if confirm "Would you like to generate documentation?"; then
345+
inform "Installing pdoc. Please wait..."
281346
pip_pkg_install pdoc
282-
printf "Generating documentation.\n"
347+
inform "Generating documentation.\n"
283348
$PYTHON -m pdoc $LIBRARY_NAME -o $RESOURCES_DIR/docs > /dev/null
284349
if [ $? -eq 0 ]; then
285350
inform "Documentation saved to $RESOURCES_DIR/docs"
@@ -289,6 +354,22 @@ if confirm "Would you like to generate documentation?"; then
289354
fi
290355
fi
291356
292-
success "\nAll done!"
293-
inform "If this is your first time installing you should reboot for hardware changes to take effect.\n"
294-
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)