From 29dc078ab0c0c9db1a8756d7f27fc776b1e0c982 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Wed, 10 Jan 2024 21:21:22 +0000 Subject: [PATCH 1/4] Add Shellcheck action Signed-off-by: Dan Webb --- .github/workflows/linting.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/linting.yml diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 0000000..ca67b9c --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,15 @@ +--- +name: "Lint" + +"on": + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 From 3c3d03991d504172a657a3a5bfb63194e116de32 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Thu, 11 Jan 2024 12:09:30 +0000 Subject: [PATCH 2/4] Fix install.sh Signed-off-by: Dan Webb --- .github/workflows/test.yml | 6 +- install.sh | 209 +++++++++++++++++++------------------ uninstall.sh | 7 +- 3 files changed, 116 insertions(+), 106 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 016a678..353e86b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,12 +12,15 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ['3.9', '3.10', '3.11'] + python: ["3.9", "3.10", "3.11"] steps: - name: Checkout Code uses: actions/checkout@v3 + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 + - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v3 with: @@ -38,4 +41,3 @@ jobs: run: | python -m pip install coveralls coveralls --service=github - diff --git a/install.sh b/install.sh index 26f0f4f..9523898 100755 --- a/install.sh +++ b/install.sh @@ -1,4 +1,6 @@ #!/bin/bash +#shellcheck disable=SC2312,SC1091 + LIBRARY_NAME=$(grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}') MODULE_NAME="grow" CONFIG_FILE=config.txt @@ -6,9 +8,9 @@ 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 +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=() @@ -16,20 +18,19 @@ FORCE=false UNSTABLE=false PYTHON="python" - user_check() { - if [ "$(id -u)" -eq 0 ]; then + 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 + if ${FORCE}; then true else read -r -p "$1 [y/N] " response < /dev/tty - if [[ $response =~ ^(yes|y|Y)$ ]]; then + if [[ ${response} =~ ^(yes|y|Y)$ ]]; then true else false @@ -39,7 +40,7 @@ confirm() { prompt() { read -r -p "$1 [y/N] " response < /dev/tty - if [[ $response =~ ^(yes|y|Y)$ ]]; then + if [[ ${response} =~ ^(yes|y|Y)$ ]]; then true else false @@ -47,67 +48,66 @@ prompt() { } success() { - echo -e "$(tput setaf 2)$1$(tput sgr0)" + echo -e "$(tput setaf 2)${1}$(tput sgr0)" } inform() { - echo -e "$(tput setaf 6)$1$(tput sgr0)" + echo -e "$(tput setaf 6)${1}$(tput sgr0)" } warning() { - echo -e "$(tput setaf 1)$1$(tput sgr0)" + echo -e "$(tput setaf 1)${1}$(tput sgr0)" } find_config() { - if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then + if [[ ! -f "${CONFIG_DIR}/${CONFIG_FILE}" ]]; then CONFIG_DIR="/boot" - if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then - warning "Could not find $CONFIG_FILE!" + 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" + 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" + 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 + 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 +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 +source \${VENV_DIR}/bin/activate EOF fi } venv_check() { PYTHON_BIN=$(which "$PYTHON") - if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then + 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 + 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" + 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" - + inform "Activating virtual Python environment in ${VENV_DIR}..." + inform "source ${VENV_DIR}/bin/activate\n" + source "${VENV_DIR}/bin/activate" else exit 1 fi @@ -115,15 +115,15 @@ venv_check() { } function do_config_backup { - if [ ! $CONFIG_BACKUP == true ]; then + 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" + FILENAME="config.preinstall-$L{IBRARY_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 } @@ -131,36 +131,39 @@ function do_config_backup { 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") + 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 + + 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" + 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 "$@" + PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring ${PYTHON} -m pip install --upgrade "$@" } while [[ $# -gt 0 ]]; do - K="$1" - case $K in + K="${1}" + case ${K} in -u|--unstable) UNSTABLE=true shift @@ -188,20 +191,20 @@ done user_check venv_check -if [ ! -f "$(which $PYTHON)" ]; then - printf "Python path %s not found!\n" "$PYTHON" +if [[ ! -f $(command -v "${PYTHON}") ]]; then + printf "Python path %s not found!\n" "${PYTHON}" exit 1 fi -PYTHON_VER=$($PYTHON --version) +PYTHON_VER=$(${PYTHON} --version) -printf "%s Python Library: Installer\n\n" $LIBRARY_NAME +printf "%s Python Library: Installer\n\n" "${LIBRARY_NAME}" inform "Checking Dependencies. Please wait..." pip_pkg_install toml -CONFIG_VARS=`$PYTHON - < "$UNINSTALLER" +cat << EOF > "${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 +source ${VIRTUAL_ENV}/bin/activate EOF -if $UNSTABLE; then +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" +inform "Installing for ${PYTHON_VER}...\n" +# shellcheck disable=SC2154 apt_pkg_install "${APT_PACKAGES[@]}" -if $UNSTABLE; then + +if ${UNSTABLE}; then pip_pkg_install . else - pip_pkg_install "$LIBRARY_NAME" + pip_pkg_install "${LIBRARY_NAME}" fi -if [ $? -eq 0 ]; then + +if [[ $? -eq 0 ]]; then success "Done!\n" - echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> "$UNINSTALLER" + echo "${PYTHON} -m pip uninstall ${LIBRARY_NAME}" >> "${UNINSTALLER}" fi -cd "$WD" || exit 1 +cd "${WD}" || exit 1 find_config +#shellcheck disable=SC2154 for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do - CMD="${SETUP_CMDS[$i]}" + 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 + if [[ "${CMD}" == *"raspi-config"* ]] || [[ "${CMD}" == *"${CONFIG_DIR}/${CONFIG_FILE}"* ]] || [[ "${CMD}" == *"\${CONFIG_DIR}/\${CONFIG_FILE}"* ]]; then do_config_backup fi - eval "$CMD" + eval "${CMD}" done +#shellcheck disable=SC2154 for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do - CONFIG_LINE="${CONFIG_TXT[$i]}" - if ! [ "$CONFIG_LINE" == "" ]; then + 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 + 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" +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 @@ -300,9 +309,9 @@ 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" + + if ${PYTHON} -m pdoc "${MODULE_NAME}" -o "${RESOURCES_DIR}/docs" > /dev/null; then + inform "Documentation saved to ${RESOURCES_DIR}/docs" success "Done!" else warning "Error: Failed to generate documentation." @@ -311,4 +320,4 @@ 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" +inform "Find uninstall steps in ${UNINSTALLER}\n" diff --git a/uninstall.sh b/uninstall.sh index f213fc5..330377e 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,13 +1,12 @@ #!/bin/bash FORCE=false -LIBRARY_NAME=`grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}'` -RESOURCES_DIR=$HOME/Pimoroni/$LIBRARY_NAME +LIBRARY_NAME=$(grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}') +RESOURCES_DIR="$HOME/Pimoroni/${LIBRARY_NAME}" PYTHON="python" - venv_check() { - PYTHON_BIN=`which $PYTHON` + PYTHON_BIN=$(command -v "${PYTHON}") if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then printf "This script should be run in a virtual Python environment.\n" exit 1 From bfabc14ab1da588b4b929b3d0891ff78249241d6 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Thu, 11 Jan 2024 12:16:09 +0000 Subject: [PATCH 3/4] Fix check.sh Signed-off-by: Dan Webb --- check.sh | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/check.sh b/check.sh index 4395d89..ce469e6 100755 --- a/check.sh +++ b/check.sh @@ -1,11 +1,12 @@ #!/bin/bash +#shellcheck disable=SC2312 # This script handles some basic QA checks on the source NOPOST=$1 -LIBRARY_NAME=`hatch project metadata name` -LIBRARY_VERSION=`hatch version | awk -F "." '{print $1"."$2"."$3}'` -POST_VERSION=`hatch version | awk -F "." '{print substr($4,0,length($4))}'` +LIBRARY_NAME=$(hatch project metadata name) +LIBRARY_VERSION=$(hatch version | awk -F "." '{print $1"."$2"."$3}') +POST_VERSION=$(hatch version | awk -F "." '{print substr($4,0,length($4))}') TERM=${TERM:="xterm-256color"} success() { @@ -21,15 +22,15 @@ warning() { } while [[ $# -gt 0 ]]; do - K="$1" - case $K in + K="${1}" + case ${K} in -p|--nopost) NOPOST=true shift ;; *) if [[ $1 == -* ]]; then - printf "Unrecognised option: $1\n"; + printf "Unrecognised option: %s\n" "${1}" exit 1 fi POSITIONAL_ARGS+=("$1") @@ -37,11 +38,10 @@ while [[ $# -gt 0 ]]; do esac done -inform "Checking $LIBRARY_NAME $LIBRARY_VERSION\n" - +inform "Checking ${LIBRARY_NAME} ${LIBRARY_VERSION}\n" inform "Checking for trailing whitespace..." -grep -IUrn --color "[[:blank:]]$" --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO -if [[ $? -eq 0 ]]; then + +if grep -IUrn --color "[[:blank:]]$" --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO; then warning "Trailing whitespace found!" exit 1 else @@ -50,8 +50,8 @@ fi printf "\n" inform "Checking for DOS line-endings..." -grep -lIUrn --color $'\r' --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile -if [[ $? -eq 0 ]]; then + +if grep -lIUrn --color $'\r' --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile; then warning "DOS line-endings found!" exit 1 else @@ -60,7 +60,8 @@ fi printf "\n" inform "Checking CHANGELOG.md..." -cat CHANGELOG.md | grep ^${LIBRARY_VERSION} > /dev/null 2>&1 +cat CHANGELOG.md | grep ^"${LIBRARY_VERSION}" > /dev/null 2>&1 + if [[ $? -eq 1 ]]; then warning "Changes missing for version ${LIBRARY_VERSION}! Please update CHANGELOG.md." exit 1 @@ -76,10 +77,10 @@ if [[ $? -eq 1 ]]; then fi printf "\n" -if [[ $NOPOST ]]; then +if [[ ${NOPOST} ]]; then inform "Checking for .postN on library version..." - if [[ "$POST_VERSION" != "" ]]; then - warning "Found .$POST_VERSION on library version." + if [[ "${POST_VERSION}" != "" ]]; then + warning "Found .${POST_VERSION} on library version." inform "Please only use these for testpypi releases." exit 1 else From ea18bbc13e036ce4ad6cbfe686fe36f5b944b531 Mon Sep 17 00:00:00 2001 From: Dan Webb Date: Thu, 11 Jan 2024 12:16:55 +0000 Subject: [PATCH 4/4] Fix service/install.sh Signed-off-by: Dan Webb --- service/install.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/service/install.sh b/service/install.sh index d2f0bd5..ef98eb9 100755 --- a/service/install.sh +++ b/service/install.sh @@ -1,22 +1,23 @@ #!/bin/bash +#shellcheck disable=SC2312 user_check() { - if [ $(id -u) -ne 0 ]; then + if [[ $(id -u) -ne 0 ]]; then printf "Script must be run as root. Try 'sudo ./install.sh'\n" exit 1 fi } success() { - echo -e "$(tput setaf 2)$1$(tput sgr0)" + echo -e "$(tput setaf 2)${1}$(tput sgr0)" } inform() { - echo -e "$(tput setaf 6)$1$(tput sgr0)" + echo -e "$(tput setaf 6)${1}$(tput sgr0)" } warning() { - echo -e "$(tput setaf 1)$1$(tput sgr0)" + echo -e "$(tput setaf 1)${1}$(tput sgr0)" } user_check