|
| 1 | +#!/bin/bash |
| 2 | +CONFIG=/boot/config.txt |
| 3 | +DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"` |
| 4 | +CONFIG_BACKUP=false |
| 5 | +APT_HAS_UPDATED=false |
| 6 | +USER_HOME=/home/$SUDO_USER |
| 7 | +RESOURCES_TOP_DIR=$USER_HOME/Pimoroni |
| 8 | +WD=`pwd` |
| 9 | +USAGE="sudo ./install.sh (--unstable)" |
| 10 | +POSITIONAL_ARGS=() |
| 11 | +UNSTABLE=false |
| 12 | +PYTHON="/usr/bin/python3" |
| 13 | +CODENAME=`lsb_release -sc` |
| 14 | + |
| 15 | +distro_check() { |
| 16 | + if [[ $CODENAME != "bullseye" ]]; then |
| 17 | + printf "This installer is for Raspberry Pi OS: Bullseye only, current distro: $CODENAME\n" |
| 18 | + exit 1 |
| 19 | + fi |
| 20 | +} |
| 21 | + |
| 22 | +user_check() { |
| 23 | + if [ $(id -u) -ne 0 ]; then |
| 24 | + printf "Script must be run as root. Try 'sudo ./install.sh'\n" |
| 25 | + exit 1 |
| 26 | + fi |
| 27 | +} |
| 28 | + |
| 29 | +confirm() { |
| 30 | + if [ "$FORCE" == '-y' ]; then |
| 31 | + true |
| 32 | + else |
| 33 | + read -r -p "$1 [y/N] " response < /dev/tty |
| 34 | + if [[ $response =~ ^(yes|y|Y)$ ]]; then |
| 35 | + true |
| 36 | + else |
| 37 | + false |
| 38 | + fi |
| 39 | + fi |
| 40 | +} |
| 41 | + |
| 42 | +prompt() { |
| 43 | + read -r -p "$1 [y/N] " response < /dev/tty |
| 44 | + if [[ $response =~ ^(yes|y|Y)$ ]]; then |
| 45 | + true |
| 46 | + else |
| 47 | + false |
| 48 | + fi |
| 49 | +} |
| 50 | + |
| 51 | +success() { |
| 52 | + echo -e "$(tput setaf 2)$1$(tput sgr0)" |
| 53 | +} |
| 54 | + |
| 55 | +inform() { |
| 56 | + echo -e "$(tput setaf 6)$1$(tput sgr0)" |
| 57 | +} |
| 58 | + |
| 59 | +warning() { |
| 60 | + echo -e "$(tput setaf 1)$1$(tput sgr0)" |
| 61 | +} |
| 62 | + |
| 63 | +function do_config_backup { |
| 64 | + if [ ! $CONFIG_BACKUP == true ]; then |
| 65 | + CONFIG_BACKUP=true |
| 66 | + FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt" |
| 67 | + inform "Backing up $CONFIG to /boot/$FILENAME\n" |
| 68 | + cp $CONFIG /boot/$FILENAME |
| 69 | + mkdir -p $RESOURCES_TOP_DIR/config-backups/ |
| 70 | + cp $CONFIG $RESOURCES_TOP_DIR/config-backups/$FILENAME |
| 71 | + if [ -f "$UNINSTALLER" ]; then |
| 72 | + echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG" >> $UNINSTALLER |
| 73 | + fi |
| 74 | + fi |
| 75 | +} |
| 76 | + |
| 77 | +function apt_pkg_install { |
| 78 | + PACKAGES=() |
| 79 | + PACKAGES_IN=("$@") |
| 80 | + for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do |
| 81 | + PACKAGE="${PACKAGES_IN[$i]}" |
| 82 | + if [ "$PACKAGE" == "" ]; then continue; fi |
| 83 | + printf "Checking for $PACKAGE\n" |
| 84 | + dpkg -L $PACKAGE > /dev/null 2>&1 |
| 85 | + if [ "$?" == "1" ]; then |
| 86 | + PACKAGES+=("$PACKAGE") |
| 87 | + fi |
| 88 | + done |
| 89 | + PACKAGES="${PACKAGES[@]}" |
| 90 | + if ! [ "$PACKAGES" == "" ]; then |
| 91 | + echo "Installing missing packages: $PACKAGES" |
| 92 | + if [ ! $APT_HAS_UPDATED ]; then |
| 93 | + apt update |
| 94 | + APT_HAS_UPDATED=true |
| 95 | + fi |
| 96 | + apt install -y $PACKAGES |
| 97 | + if [ -f "$UNINSTALLER" ]; then |
| 98 | + echo "apt uninstall -y $PACKAGES" |
| 99 | + fi |
| 100 | + fi |
| 101 | +} |
| 102 | + |
| 103 | +while [[ $# -gt 0 ]]; do |
| 104 | + K="$1" |
| 105 | + case $K in |
| 106 | + -u|--unstable) |
| 107 | + UNSTABLE=true |
| 108 | + shift |
| 109 | + ;; |
| 110 | + -p|--python) |
| 111 | + PYTHON=$2 |
| 112 | + shift |
| 113 | + shift |
| 114 | + ;; |
| 115 | + *) |
| 116 | + if [[ $1 == -* ]]; then |
| 117 | + printf "Unrecognised option: $1\n"; |
| 118 | + printf "Usage: $USAGE\n"; |
| 119 | + exit 1 |
| 120 | + fi |
| 121 | + POSITIONAL_ARGS+=("$1") |
| 122 | + shift |
| 123 | + esac |
| 124 | +done |
| 125 | + |
| 126 | +distro_check |
| 127 | +user_check |
| 128 | + |
| 129 | +if [ ! -f "$PYTHON" ]; then |
| 130 | + printf "Python path $PYTHON not found!\n" |
| 131 | + exit 1 |
| 132 | +fi |
| 133 | + |
| 134 | +PYTHON_VER=`$PYTHON --version` |
| 135 | + |
| 136 | +inform "Installing. Please wait..." |
| 137 | + |
| 138 | +$PYTHON -m pip install --upgrade configparser |
| 139 | + |
| 140 | +CONFIG_VARS=`$PYTHON - <<EOF |
| 141 | +from configparser import ConfigParser |
| 142 | +c = ConfigParser() |
| 143 | +c.read('library/setup.cfg') |
| 144 | +p = dict(c['pimoroni']) |
| 145 | +# Convert multi-line config entries into bash arrays |
| 146 | +for k in p.keys(): |
| 147 | + fmt = '"{}"' |
| 148 | + if '\n' in p[k]: |
| 149 | + p[k] = "'\n\t'".join(p[k].split('\n')[1:]) |
| 150 | + fmt = "('{}')" |
| 151 | + p[k] = fmt.format(p[k]) |
| 152 | +print(""" |
| 153 | +LIBRARY_NAME="{name}" |
| 154 | +LIBRARY_VERSION="{version}" |
| 155 | +""".format(**c['metadata'])) |
| 156 | +print(""" |
| 157 | +PY3_DEPS={py3deps} |
| 158 | +PY2_DEPS={py2deps} |
| 159 | +SETUP_CMDS={commands} |
| 160 | +CONFIG_TXT={configtxt} |
| 161 | +""".format(**p)) |
| 162 | +EOF` |
| 163 | +
|
| 164 | +if [ $? -ne 0 ]; then |
| 165 | + warning "Error parsing configuration...\n" |
| 166 | + exit 1 |
| 167 | +fi |
| 168 | +
|
| 169 | +eval $CONFIG_VARS |
| 170 | +
|
| 171 | +RESOURCES_DIR=$RESOURCES_TOP_DIR/$LIBRARY_NAME |
| 172 | +UNINSTALLER=$RESOURCES_DIR/uninstall.sh |
| 173 | +
|
| 174 | +mkdir -p $RESOURCES_DIR |
| 175 | +
|
| 176 | +cat << EOF > $UNINSTALLER |
| 177 | +printf "It's recommended you run these steps manually.\n" |
| 178 | +printf "If you want to run the full script, open it in\n" |
| 179 | +printf "an editor and remove 'exit 1' from below.\n" |
| 180 | +exit 1 |
| 181 | +EOF |
| 182 | +
|
| 183 | +printf "$LIBRARY_NAME $LIBRARY_VERSION Python Library: Installer\n\n" |
| 184 | +
|
| 185 | +if $UNSTABLE; then |
| 186 | + warning "Installing unstable library from source.\n\n" |
| 187 | +else |
| 188 | + printf "Installing stable library from pypi.\n\n" |
| 189 | +fi |
| 190 | +
|
| 191 | +cd library |
| 192 | +
|
| 193 | +printf "Installing for $PYTHON_VER...\n" |
| 194 | +apt_pkg_install "${PY3_DEPS[@]}" |
| 195 | +if $UNSTABLE; then |
| 196 | + $PYTHON setup.py install > /dev/null |
| 197 | +else |
| 198 | + $PYTHON -m pip install --upgrade $LIBRARY_NAME |
| 199 | +fi |
| 200 | +if [ $? -eq 0 ]; then |
| 201 | + success "Done!\n" |
| 202 | + echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> $UNINSTALLER |
| 203 | +fi |
| 204 | +
|
| 205 | +cd $WD |
| 206 | +
|
| 207 | +for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do |
| 208 | + CMD="${SETUP_CMDS[$i]}" |
| 209 | + # Attempt to catch anything that touches /boot/config.txt and trigger a backup |
| 210 | + if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG"* ]] || [[ "$CMD" == *"\$CONFIG"* ]]; then |
| 211 | + do_config_backup |
| 212 | + fi |
| 213 | + eval $CMD |
| 214 | +done |
| 215 | +
|
| 216 | +for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do |
| 217 | + CONFIG_LINE="${CONFIG_TXT[$i]}" |
| 218 | + if ! [ "$CONFIG_LINE" == "" ]; then |
| 219 | + do_config_backup |
| 220 | + inform "Adding $CONFIG_LINE to $CONFIG\n" |
| 221 | + sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG |
| 222 | + if ! grep -q "^$CONFIG_LINE" $CONFIG; then |
| 223 | + printf "$CONFIG_LINE\n" >> $CONFIG |
| 224 | + fi |
| 225 | + fi |
| 226 | +done |
| 227 | +
|
| 228 | +if [ -d "examples" ]; then |
| 229 | + if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then |
| 230 | + inform "Copying examples to $RESOURCES_DIR" |
| 231 | + cp -r examples/ $RESOURCES_DIR |
| 232 | + echo "rm -r $RESOURCES_DIR" >> $UNINSTALLER |
| 233 | + success "Done!" |
| 234 | + fi |
| 235 | +fi |
| 236 | +
|
| 237 | +printf "\n" |
| 238 | +
|
| 239 | +if [ -f "/usr/bin/pydoc" ]; then |
| 240 | + printf "Generating documentation.\n" |
| 241 | + pydoc -w $LIBRARY_NAME > /dev/null |
| 242 | + if [ -f "$LIBRARY_NAME.html" ]; then |
| 243 | + cp $LIBRARY_NAME.html $RESOURCES_DIR/docs.html |
| 244 | + rm -f $LIBRARY_NAME.html |
| 245 | + inform "Documentation saved to $RESOURCES_DIR/docs.html" |
| 246 | + success "Done!" |
| 247 | + else |
| 248 | + warning "Error: Failed to generate documentation." |
| 249 | + fi |
| 250 | +fi |
| 251 | +
|
| 252 | +success "\nAll done!" |
| 253 | +inform "If this is your first time installing you should reboot for hardware changes to take effect.\n" |
| 254 | +inform "Find uninstall steps in $UNINSTALLER\n" |
0 commit comments