#!/bin/bash LIBRARY_NAME=$(grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}') MODULE_NAME="grow" CONFIG_FILE=config.txt CONFIG_DIR="/boot/firmware" DATESTAMP=$(date "+%Y-%m-%d-%H-%M-%S") CONFIG_BACKUP=false APT_HAS_UPDATED=false RESOURCES_TOP_DIR=$HOME/Pimoroni VENV_BASH_SNIPPET=$RESOURCES_DIR/auto_venv.sh VENV_DIR=$HOME/.virtualenvs/pimoroni WD=$(pwd) USAGE="./install.sh (--unstable)" POSITIONAL_ARGS=() FORCE=false UNSTABLE=false PYTHON="python" user_check() { if [ "$(id -u)" -eq 0 ]; then printf "Script should not be run as root. Try './install.sh'\n" exit 1 fi } confirm() { if $FORCE; then true else read -r -p "$1 [y/N] " response < /dev/tty if [[ $response =~ ^(yes|y|Y)$ ]]; then true else false fi fi } prompt() { read -r -p "$1 [y/N] " response < /dev/tty if [[ $response =~ ^(yes|y|Y)$ ]]; then true else false fi } success() { echo -e "$(tput setaf 2)$1$(tput sgr0)" } inform() { echo -e "$(tput setaf 6)$1$(tput sgr0)" } warning() { echo -e "$(tput setaf 1)$1$(tput sgr0)" } find_config() { if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then CONFIG_DIR="/boot" if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then warning "Could not find $CONFIG_FILE!" exit 1 fi else if [ -f "/boot/$CONFIG_FILE" ] && [ ! -L "/boot/$CONFIG_FILE" ]; then warning "Oops! It looks like /boot/$CONFIG_FILE is not a link to $CONFIG_DIR/$CONFIG_FILE" warning "You might want to fix this!" fi fi inform "Using $CONFIG_FILE in $CONFIG_DIR" } venv_bash_snippet() { if [ ! -f "$VENV_BASH_SNIPPET" ]; then cat << EOF > "$VENV_BASH_SNIPPET" # Add `source $RESOURCES_DIR/auto_venv.sh` to your ~/.bashrc to activate # the Pimoroni virtual environment automagically! VENV_DIR="$VENV_DIR" if [ ! -f \$VENV_DIR/bin/activate ]; then printf "Creating user Python environment in \$VENV_DIR, please wait...\n" mkdir -p \$VENV_DIR python3 -m venv --system-site-packages \$VENV_DIR fi printf " ↓ ↓ ↓ ↓ Hello, we've activated a Python venv for you. To exit, type \"deactivate\".\n" source \$VENV_DIR/bin/activate EOF fi } venv_check() { PYTHON_BIN=$(which "$PYTHON") if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then printf "This script should be run in a virtual Python environment.\n" if confirm "Would you like us to create one for you?"; then if [ ! -f "$VENV_DIR/bin/activate" ]; then inform "Creating virtual Python environment in $VENV_DIR, please wait...\n" mkdir -p "$VENV_DIR" /usr/bin/python3 -m venv "$VENV_DIR" --system-site-packages venv_bash_snippet else inform "Found existing virtual Python environment in $VENV_DIR\n" fi inform "Activating virtual Python environment in $VENV_DIR..." inform "source $VENV_DIR/bin/activate\n" source "$VENV_DIR/bin/activate" else exit 1 fi fi } function do_config_backup { if [ ! $CONFIG_BACKUP == true ]; then CONFIG_BACKUP=true FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt" inform "Backing up $CONFIG_DIR/$CONFIG_FILE to $CONFIG_DIR/$FILENAME\n" sudo cp "$CONFIG_DIR/$CONFIG_FILE $CONFIG_DIR/$FILENAME" mkdir -p "$RESOURCES_TOP_DIR/config-backups/" cp $CONFIG_DIR/$CONFIG_FILE "$RESOURCES_TOP_DIR/config-backups/$FILENAME" if [ -f "$UNINSTALLER" ]; then echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG_DIR/$CONFIG_FILE" >> "$UNINSTALLER" fi fi } function apt_pkg_install { PACKAGES=() PACKAGES_IN=("$@") for ((i = 0; i < ${#PACKAGES_IN[@]}; i++)); do PACKAGE="${PACKAGES_IN[$i]}" if [ "$PACKAGE" == "" ]; then continue; fi printf "Checking for %s\n" "$PACKAGE" dpkg -L "$PACKAGE" > /dev/null 2>&1 if [ "$?" == "1" ]; then PACKAGES+=("$PACKAGE") fi done PACKAGES="${PACKAGES[@]}" if ! [ "$PACKAGES" == "" ]; then echo "Installing missing packages: $PACKAGES" if [ ! $APT_HAS_UPDATED ]; then sudo apt update APT_HAS_UPDATED=true fi sudo apt install -y $PACKAGES if [ -f "$UNINSTALLER" ]; then echo "apt uninstall -y $PACKAGES" >> "$UNINSTALLER" fi fi } function pip_pkg_install { PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring $PYTHON -m pip install --upgrade "$@" } while [[ $# -gt 0 ]]; do K="$1" case $K in -u|--unstable) UNSTABLE=true shift ;; -f|--force) FORCE=true shift ;; -p|--python) PYTHON=$2 shift shift ;; *) if [[ $1 == -* ]]; then printf "Unrecognised option: %s\n" "$1"; printf "Usage: %s\n" "$USAGE"; exit 1 fi POSITIONAL_ARGS+=("$1") shift esac done user_check venv_check if [ ! -f "$(which $PYTHON)" ]; then printf "Python path %s not found!\n" "$PYTHON" exit 1 fi PYTHON_VER=$($PYTHON --version) printf "%s Python Library: Installer\n\n" $LIBRARY_NAME inform "Checking Dependencies. Please wait..." pip_pkg_install toml CONFIG_VARS=`$PYTHON - < "$UNINSTALLER" printf "It's recommended you run these steps manually.\n" printf "If you want to run the full script, open it in\n" printf "an editor and remove 'exit 1' from below.\n" exit 1 source $VIRTUAL_ENV/bin/activate EOF if $UNSTABLE; then warning "Installing unstable library from source.\n\n" else printf "Installing stable library from pypi.\n\n" fi inform "Installing for $PYTHON_VER...\n" apt_pkg_install "${APT_PACKAGES[@]}" if $UNSTABLE; then pip_pkg_install . else pip_pkg_install "$LIBRARY_NAME" fi if [ $? -eq 0 ]; then success "Done!\n" echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> "$UNINSTALLER" fi cd "$WD" || exit 1 find_config for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do CMD="${SETUP_CMDS[$i]}" # Attempt to catch anything that touches config.txt and trigger a backup if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG_DIR/$CONFIG_FILE"* ]] || [[ "$CMD" == *"\$CONFIG_DIR/\$CONFIG_FILE"* ]]; then do_config_backup fi eval "$CMD" done for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do CONFIG_LINE="${CONFIG_TXT[$i]}" if ! [ "$CONFIG_LINE" == "" ]; then do_config_backup inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE\n" sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG_DIR/$CONFIG_FILE if ! grep -q "^$CONFIG_LINE" $CONFIG_DIR/$CONFIG_FILE; then printf "%s\n" "$CONFIG_LINE" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE fi fi done if [ -d "examples" ]; then if confirm "Would you like to copy examples to $RESOURCES_DIR?"; then inform "Copying examples to $RESOURCES_DIR" cp -r examples/ "$RESOURCES_DIR" echo "rm -r $RESOURCES_DIR" >> "$UNINSTALLER" success "Done!" fi fi printf "\n" if confirm "Would you like to generate documentation?"; then pip_pkg_install pdoc printf "Generating documentation.\n" $PYTHON -m pdoc $MODULE_NAME -o "$RESOURCES_DIR/docs" > /dev/null if [ $? -eq 0 ]; then inform "Documentation saved to $RESOURCES_DIR/docs" success "Done!" else warning "Error: Failed to generate documentation." fi fi success "\nAll done!" inform "If this is your first time installing you should reboot for hardware changes to take effect.\n" inform "Find uninstall steps in $UNINSTALLER\n"