From 234cc3c883951b822343c517a392c60e499cbc90 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:32:53 +0100 Subject: [PATCH 01/28] Add installation checks + CI Workflow (#2119) * add ci workflow * add check for user home * changes for docker tests * added verify functions * exit on failed update * add check for samba setup * add check for mpd setup * add check for jukebox core setup * add check for git setup * add check for kiosk mode setup * add check for optimize boot setup * add check for webapp setup * add check for autohotspot setup * make rfid reader setup an optional step * Add Option for No Rfid Reader * moved setup checks to individual scripts * fix missing iw package * refactored get_reader_descriptions into function. be more consistent by using same var for display and index access * moved function to specific routine script * make sure verify parameters are all set. fix functionnames * added fix for not available interface in CI runs * check supported os type first * moved exit_on_error function top level * moved logging setup to function and added usage * moved load sources to function * change function name and var usage * updated log output for better logfile readability * harmonize log output * refactored disable onboard audio. only execute if flag is true. inlined function * add restart nginx.service again. use HOME_PATH * fix and check adding samba user * fix logging mpd setup routine * fix Disable boot logs error on existing file * added timer to log frame * add core package installation from file used also for ci optimization * Dont let remove packages fail install. ignore for ci * Update test scripts use robust path determination move noninteractive to dockerfile * fix clear in mpd option * fix bug in rfid configure * fix error on uninitialized rfid_reader settings * add checks for static ip config * Added test for webapp download in prod. Update test descriptions. * renamend workflow files to not interfere with develop branch * Update install links --- .dockerignore | 1 - .../test_docker_debian_codename_sub_v3.yml | 183 ++++++++++++ .github/workflows/test_docker_debian_v3.yml | 31 +++ README.md | 6 +- ci/ci-debian.Dockerfile | 100 +++++++ ci/installation/run_install_common.sh | 43 +++ ci/installation/run_install_faststartup.sh | 39 +++ ci/installation/run_install_user_not_pi.sh | 25 ++ .../run_install_webapp_download.sh | 41 +++ ci/installation/run_install_webapp_local.sh | 42 +++ installation/README.md | 8 +- installation/includes/00_constants.sh | 4 + installation/includes/01_default_config.sh | 2 + installation/includes/02_helpers.sh | 261 ++++++++++++++++-- installation/includes/04_cleanup.sh | 8 +- installation/includes/05_finish.sh | 25 +- installation/install-jukebox.sh | 141 +++++++--- installation/routines/customize_options.sh | 74 ++++- installation/routines/install.sh | 15 +- installation/routines/optimize_boot_time.sh | 135 ++++++--- installation/routines/set_raspi_config.sh | 26 +- installation/routines/set_ssh_qos.sh | 12 +- installation/routines/setup_autohotspot.sh | 76 +++-- installation/routines/setup_git.sh | 32 ++- installation/routines/setup_jukebox_core.sh | 80 ++++-- installation/routines/setup_jukebox_webapp.sh | 59 ++-- installation/routines/setup_kiosk_mode.sh | 59 +++- installation/routines/setup_mpd.sh | 77 +++--- installation/routines/setup_rfid_reader.sh | 12 +- installation/routines/setup_samba.sh | 48 +++- installation/routines/update_raspi_os.sh | 15 +- packages-core.txt | 17 ++ requirements.txt | 3 +- .../components/rfid/configure/__init__.py | 78 ++++-- .../components/rfid/reader/__init__.py | 24 +- 35 files changed, 1439 insertions(+), 363 deletions(-) create mode 100644 .github/workflows/test_docker_debian_codename_sub_v3.yml create mode 100644 .github/workflows/test_docker_debian_v3.yml create mode 100644 ci/ci-debian.Dockerfile create mode 100644 ci/installation/run_install_common.sh create mode 100644 ci/installation/run_install_faststartup.sh create mode 100644 ci/installation/run_install_user_not_pi.sh create mode 100644 ci/installation/run_install_webapp_download.sh create mode 100644 ci/installation/run_install_webapp_local.sh create mode 100644 packages-core.txt diff --git a/.dockerignore b/.dockerignore index 55fe62a70..a587de477 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,7 +7,6 @@ # Application docker docs -installation shared # webapp diff --git a/.github/workflows/test_docker_debian_codename_sub_v3.yml b/.github/workflows/test_docker_debian_codename_sub_v3.yml new file mode 100644 index 000000000..54abd142a --- /dev/null +++ b/.github/workflows/test_docker_debian_codename_sub_v3.yml @@ -0,0 +1,183 @@ +name: Subworkflow Test Install Scripts Debian V3 + +on: + workflow_call: + inputs: + debian_codename: + required: true + type: string + docker_image_name: + required: false + type: string + default: rpi-jukebox-rfid-v3 + platform: + required: false + type: string + default: linux/arm/v7 + cache_scope: + required: false + type: string + default: ${{ github.ref }}-test-debian-v3 + local_registry_port: + required: false + type: number + default: 5000 + runs_on: + required: false + type: string + default: ubuntu-latest + +# let only one instance run the test so cache is not corrupted. +# cancel already running instances as only the last run will be relevant +concurrency: + group: ${{ inputs.cache_scope }}-${{ inputs.debian_codename }} + cancel-in-progress: true + +jobs: + + # Build container for test execution + build: + runs-on: ${{ inputs.runs_on }} + + outputs: + cache_key: ${{ steps.vars.outputs.cache_key }} + image_file_name: ${{ steps.vars.outputs.image_file_name }} + image_tag_name: ${{ steps.vars.outputs.image_tag_name }} + + # create local docker registry to use locally build images + services: + registry: + image: registry:2 + ports: + - ${{ inputs.local_registry_port }}:5000 + + steps: + - uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + with: + # network=host driver-opt needed to push to local registry + driver-opts: network=host + + - name: Set Output pre-vars + id: pre-vars + env: + DEBIAN_CODENAME: ${{ inputs.debian_codename }} + DOCKER_IMAGE_NAME: ${{ inputs.docker_image_name }} + CACHE_SCOPE: ${{ inputs.cache_scope }} + run: | + echo "image_tag_name=${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEBIAN_CODENAME }}-test" >> $GITHUB_OUTPUT + echo "image_file_name=${{ env.DOCKER_IMAGE_NAME }}-${{ env.DEBIAN_CODENAME }}.tar" >> $GITHUB_OUTPUT + echo "cache_scope=${{ env.CACHE_SCOPE }}-${{ env.DEBIAN_CODENAME }}" >> $GITHUB_OUTPUT + + - name: Set Output vars + id: vars + env: + LOCAL_REGISTRY_PORT: ${{ inputs.local_registry_port }} + run: | + echo "image_tag_name=${{ steps.pre-vars.outputs.image_tag_name }}" >> $GITHUB_OUTPUT + echo "image_tag_name_local_base=localhost:${{ env.LOCAL_REGISTRY_PORT }}/${{ steps.pre-vars.outputs.image_tag_name }}-base" >> $GITHUB_OUTPUT + echo "image_file_name=${{ steps.pre-vars.outputs.image_file_name }}" >> $GITHUB_OUTPUT + echo "image_file_path=./${{ steps.pre-vars.outputs.image_file_name }}" >> $GITHUB_OUTPUT + echo "cache_scope=${{ steps.pre-vars.outputs.cache_scope }}" >> $GITHUB_OUTPUT + echo "cache_key=${{ steps.pre-vars.outputs.cache_scope }}-${{ github.sha }}#${{ github.run_attempt }}" >> $GITHUB_OUTPUT + + # Build base image for debian version name. Layers will be cached and image pushes to local registry + - name: Build Image - Base + uses: docker/build-push-action@v5 + with: + context: . + load: false + push: true + file: ./ci/ci-debian.Dockerfile + target: test-code + platforms: ${{ inputs.platform }} + tags: ${{ steps.vars.outputs.image_tag_name_local_base }} + cache-from: type=gha,scope=${{ steps.vars.outputs.cache_scope }} + cache-to: type=gha,mode=max,scope=${{ steps.vars.outputs.cache_scope }} + build-args: | + DEBIAN_CODENAME=${{ inputs.debian_codename }} + GIT_BRANCH=${{ github.head_ref || github.ref_name }} + GIT_USER=${{ github.event.pull_request.head.user.login || github.repository_owner }} + + # Build new image with updates packages based on base image. Layers will NOT be chached. Result is written to file. + - name: Build Image - Update + uses: docker/build-push-action@v5 + with: + context: . + load: false + push: false + file: ./ci/ci-debian.Dockerfile + target: test-update + platforms: ${{ inputs.platform }} + tags: ${{ steps.vars.outputs.image_tag_name }} + cache-from: type=gha,scope=${{ steps.vars.outputs.cache_scope }} + # DON'T use 'cache-to' here as the layer is then cached and this build would be useless + outputs: type=docker,dest=${{ steps.vars.outputs.image_file_path }} + build-args: | + BASE_TEST_IMAGE=${{ steps.vars.outputs.image_tag_name_local_base }} + + - name: Artifact Upload Docker Image + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.vars.outputs.image_file_name }} + path: ${{ steps.vars.outputs.image_file_path }} + retention-days: 1 + + + # Run tests with build image + test: + needs: [build] + runs-on: ${{ inputs.runs_on }} + + strategy: + fail-fast: false + matrix: + username: ['pi'] + test_script: ['run_install_common.sh', 'run_install_faststartup.sh', 'run_install_webapp_local.sh', 'run_install_webapp_download.sh'] + include: + - username: hans + test_script: run_install_user_not_pi.sh + + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v3.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.0.0 + + - name: Artifact Download Docker Image + uses: actions/download-artifact@v3 + with: + name: ${{ needs.build.outputs.image_file_name }} + + - name: Load Docker Image + run: | + docker load --input ${{ needs.build.outputs.image_file_name }} + + # Run test + - name: Run Test ${{ inputs.debian_codename }}-${{ matrix.username }}-${{ matrix.test_script }} + uses: tj-actions/docker-run@v2 + with: + image: ${{ needs.build.outputs.image_tag_name }} + options: --platform ${{ inputs.platform }} --user ${{ matrix.username }} --init + name: ${{ matrix.test_script }} + args: | + ./${{ matrix.test_script }} + + # cleanup after test execution + cleanup: + # run only if tests didn't fail: keep the artifact to make job reruns possible + if: ${{ !failure() }} + needs: [build, test] + runs-on: ${{ inputs.runs_on }} + + steps: + - name: Artifact Delete Docker Image + uses: geekyeggo/delete-artifact@v2 + with: + name: ${{ needs.build.outputs.image_file_name }} diff --git a/.github/workflows/test_docker_debian_v3.yml b/.github/workflows/test_docker_debian_v3.yml new file mode 100644 index 000000000..6cf1648aa --- /dev/null +++ b/.github/workflows/test_docker_debian_v3.yml @@ -0,0 +1,31 @@ +name: Test Install Scripts Debian v3 + +on: + schedule: + # run at 17:00 every sunday + - cron: '0 17 * * 0' + push: + pull_request: + # The branches below must be a subset of the branches above + branches: [ future3/develop ] + +# let only one instance run the test so cache is not corrupted. +# cancel already running instances as only the last run will be relevant +concurrency: + group: ${{ github.ref }}-test-debian-v3 + cancel-in-progress: true + +jobs: + + # Build container and run tests. Duplication of job intended for better visualization. + run_bookworm: + name: 'bookworm' + uses: ./.github/workflows/test_docker_debian_codename_sub_v3.yml + with: + debian_codename: 'bookworm' + + run_bullseye: + name: 'bullseye' + uses: ./.github/workflows/test_docker_debian_codename_sub_v3.yml + with: + debian_codename: 'bullseye' diff --git a/README.md b/README.md index 8b494698d..3731c7e06 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,4 @@ The documentation can be found [here](./documentation/README.md) ## Installation? -Run the following one-liner in a shell and follow the instructions - -~~~bash -cd; bash <(wget -qO- https://raw.githubusercontent.com/MiczFlor/RPi-Jukebox-RFID/future3/develop/installation/install-jukebox.sh) -~~~ +[Install Phoniebox software](documentation/builders/installation.md#install-phoniebox-software) diff --git a/ci/ci-debian.Dockerfile b/ci/ci-debian.Dockerfile new file mode 100644 index 000000000..1a227755a --- /dev/null +++ b/ci/ci-debian.Dockerfile @@ -0,0 +1,100 @@ +# Base Target to build and install all needed base configuration and packages. Specifie the needed platform with the docker '--platform XXX' option +ARG DEBIAN_CODENAME=bookworm +ARG BASE_TEST_IMAGE=test-code +FROM debian:${DEBIAN_CODENAME}-slim as base +ARG DEBIAN_CODENAME + +ENV TERM=xterm DEBIAN_FRONTEND=noninteractive +ENV CI_RUNNING=true + +# create pi configs to test installation +RUN touch /boot/config.txt +RUN echo "logo.nologo" > /boot/cmdline.txt + +RUN echo "--- install packages (1) ---" \ + && apt-get update \ + && apt-get -y install \ + apt-utils \ + curl \ + gnupg \ + && echo "--- add sources ---" \ + && curl -fsSL http://raspbian.raspberrypi.org/raspbian.public.key | gpg --dearmor > /usr/share/keyrings/raspberrypi-raspbian-keyring.gpg \ + && curl -fsSL http://archive.raspberrypi.org/debian/raspberrypi.gpg.key | gpg --dearmor > /usr/share/keyrings/raspberrypi-archive-debian-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/raspberrypi-raspbian-keyring.gpg] http://raspbian.raspberrypi.org/raspbian/ ${DEBIAN_CODENAME} main contrib non-free rpi" > /etc/apt/sources.list.d/raspi.list \ + && echo "deb [signed-by=/usr/share/keyrings/raspberrypi-archive-debian-keyring.gpg] http://archive.raspberrypi.org/debian/ ${DEBIAN_CODENAME} main" >> /etc/apt/sources.list.d/raspi.list \ + && echo "--- install packages (2) ---" \ + && apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install \ + build-essential \ + iproute2 \ + openssh-client \ + sudo \ + systemd \ + wireless-tools \ + wget \ + wpasupplicant \ + && rm -rf /var/lib/apt/lists/* + +# Set NonInteractive for sudo usage in container. 'sudo' package needed +RUN echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections +# ------ + +# Base Target for setting up the default user. user can be selected with the docker '--user YYY' option +FROM base as user +ARG USER_NAME=pi +ARG USER_GROUP=$USER_NAME +ARG USER_ID=1000 + +ENV TEST_USER_GROUP=test +RUN groupadd --gid 1002 $TEST_USER_GROUP + +RUN groupadd --gid 1000 $USER_GROUP \ + && useradd -u $USER_ID -g $USER_GROUP -G sudo,$TEST_USER_GROUP -d /home/$USER_NAME -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' $USER_NAME \ + && echo "$USER_NAME ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER_NAME + +ENV XDG_RUNTIME_DIR=/run/user/$USER_ID DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$USER_ID/bus +# ------ + + +# Target for setting up an alternativ user 'hans:wurst'. user can be selected with the docker '--user YYY' option +FROM user as test-user + +RUN export USER_ALT=hans \ + && export USER_ALT_GROUP=wurst \ + && groupadd --gid 1001 $USER_ALT_GROUP \ + && useradd -u 1001 -g $USER_ALT_GROUP -G sudo,$TEST_USER_GROUP -d /home/$USER_ALT -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' $USER_ALT \ + && echo "$USER_ALT ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER_ALT +# ------ + + +# Target for adding envs and scripts from the repo to test installation +FROM test-user as test-code +ARG GIT_BRANCH +ARG GIT_USER + +ENV GIT_BRANCH=$GIT_BRANCH GIT_USER=$GIT_USER + +COPY --chown=root:$TEST_USER_GROUP --chmod=770 packages-core.txt ./ + +RUN echo "--- install internal packages ---" \ + && apt-get update \ + && sed 's/#.*//g' packages-core.txt | xargs apt-get -y install \ + && rm -rf /var/lib/apt/lists/* + +ENV INSTALL_SCRIPT_PATH=/code + +WORKDIR ${INSTALL_SCRIPT_PATH} +COPY --chown=root:$TEST_USER_GROUP --chmod=770 installation/install-jukebox.sh ./ + +WORKDIR ${INSTALL_SCRIPT_PATH}/tests +COPY --chown=root:$TEST_USER_GROUP --chmod=770 ci/installation/*.sh ./ +# ------ + + +# Target for applying latest updates (should not be cached!) +FROM $BASE_TEST_IMAGE as test-update +RUN apt-get update \ + && apt-get -y upgrade \ + && rm -rf /var/lib/apt/lists/* +# ------ diff --git a/ci/installation/run_install_common.sh b/ci/installation/run_install_common.sh new file mode 100644 index 000000000..102c71aa4 --- /dev/null +++ b/ci/installation/run_install_common.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# Install Phoniebox and test it +# Used e.g. for tests on Docker + +# Objective: +# Test for a common installation path. Including autohotspot + +SOURCE="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SOURCE")" +LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" +LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + +export ENABLE_WEBAPP_PROD_DOWNLOAD=true +# Run installation (in interactive mode) +# y - start setup +# n - use static ip +# n - deactivate ipv6 +# y - setup autohotspot +# n - use custom password +# n - deactivate bluetooth +# n - disable on-chip audio +# - - mpd overwrite config (only with existing installation) +# n - setup rfid reader +# y - setup samba +# y - setup webapp +# n - setup kiosk mode +# - - install node (forced WebApp Download) +# n - reboot + +"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" <<< 'y +n +n +y +n +n +n +n +y +y +n +n +' diff --git a/ci/installation/run_install_faststartup.sh b/ci/installation/run_install_faststartup.sh new file mode 100644 index 000000000..46cda25ec --- /dev/null +++ b/ci/installation/run_install_faststartup.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +# Install Phoniebox and test it +# Used e.g. for tests on Docker + +# Objective: +# Test for disabling features (suggestions for faststartup). Skips installing all additionals. + +SOURCE="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SOURCE")" +LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" +LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + +# Run installation (in interactive mode) +# y - start setup +# y - use static ip +# y - deactivate ipv6 +# n - setup autohotspot +# y - deactivate bluetooth +# y - disable on-chip audio +# - - mpd overwrite config (only with existing installation) +# n - setup rfid reader +# n - setup samba +# n - setup webapp +# - - setup kiosk mode (only with webapp = y) +# - - install node (only with webapp = y) +# n - reboot + +"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" <<< 'y +y +y +n +y +y +n +n +n +n +' diff --git a/ci/installation/run_install_user_not_pi.sh b/ci/installation/run_install_user_not_pi.sh new file mode 100644 index 000000000..76a8cd576 --- /dev/null +++ b/ci/installation/run_install_user_not_pi.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Install Phoniebox and test it +# Used e.g. for tests on Docker + +# Objective: Test installation with script using a simple configuration + +SOURCE="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SOURCE")" +LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" +LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + +# Run installation (in interactive mode) +# - - Installation must abort early + +"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" +INSTALLATION_EXITCODE=$? + +# only count abortion due to "not user pi" as success +if [ "${INSTALLATION_EXITCODE}" -eq 2 ]; then + INSTALLATION_EXITCODE=0 +else + INSTALLATION_EXITCODE=1 +fi +exit "${INSTALLATION_EXITCODE}" diff --git a/ci/installation/run_install_webapp_download.sh b/ci/installation/run_install_webapp_download.sh new file mode 100644 index 000000000..69496e8e4 --- /dev/null +++ b/ci/installation/run_install_webapp_download.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# Install Phoniebox and test it +# Used e.g. for tests on Docker + +# Objective: +# Test for the WebApp (download) and dependent features path. + +SOURCE="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SOURCE")" +LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" +LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + +export ENABLE_WEBAPP_PROD_DOWNLOAD=true +# Run installation (in interactive mode) +# y - start setup +# n - use static ip +# n - deactivate ipv6 +# n - setup autohotspot +# n - deactivate bluetooth +# n - disable on-chip audio +# - - mpd overwrite config (only with existing installation) +# n - setup rfid reader +# n - setup samba +# y - setup webapp +# y - setup kiosk mode +# - - install node (forced webapp download) +# n - reboot + +"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" <<< 'y +n +n +n +n +n +n +n +y +y +n +' diff --git a/ci/installation/run_install_webapp_local.sh b/ci/installation/run_install_webapp_local.sh new file mode 100644 index 000000000..d4f122fd5 --- /dev/null +++ b/ci/installation/run_install_webapp_local.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +# Install Phoniebox and test it +# Used e.g. for tests on Docker + +# Objective: +# Test for the WebApp (build locally) and dependent features path. + +SOURCE="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SOURCE")" +LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" +LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + +export ENABLE_WEBAPP_PROD_DOWNLOAD=false +# Run installation (in interactive mode) +# y - start setup +# n - use static ip +# n - deactivate ipv6 +# n - setup autohotspot +# n - deactivate bluetooth +# n - disable on-chip audio +# - - mpd overwrite config (only with existing installation) +# n - setup rfid reader +# n - setup samba +# y - setup webapp +# y - setup kiosk mode +# y - install node +# n - reboot + +"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" <<< 'y +n +n +n +n +n +n +n +y +y +y +n +' diff --git a/installation/README.md b/installation/README.md index aff262bd8..b2a496348 100644 --- a/installation/README.md +++ b/installation/README.md @@ -11,10 +11,6 @@ No output to both console and logfile: "$ command > /dev/null" [Learn more about bash script outputs](https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console) -## Quick Installation +## Installation -Note: Replace the branch in this command to be the one you like to install depending on your needs. Release branch is preset. - -```bash -cd; bash <(wget -qO- https://raw.githubusercontent.com/MiczFlor/RPi-Jukebox-RFID/future3/main/installation/install-jukebox.sh) -``` +[Install Phoniebox software](../documentation/builders/installation.md#install-phoniebox-software) diff --git a/installation/includes/00_constants.sh b/installation/includes/00_constants.sh index e19dd1327..380e1de2e 100644 --- a/installation/includes/00_constants.sh +++ b/installation/includes/00_constants.sh @@ -1,7 +1,11 @@ RPI_BOOT_CONFIG_FILE="/boot/config.txt" +RPI_BOOT_CMDLINE_FILE="/boot/cmdline.txt" SHARED_PATH="${INSTALLATION_PATH}/shared" SETTINGS_PATH="${SHARED_PATH}/settings" SYSTEMD_USR_PATH="/usr/lib/systemd/user" +VIRTUAL_ENV="${INSTALLATION_PATH}/.venv" +# Do not change this directory! It must match MPDs expectation where to find the user configuration +MPD_CONF_PATH="${HOME}/.config/mpd/mpd.conf" # The default upstream user, release branch, and develop branch # These are used to prepare the repo for developers diff --git a/installation/includes/01_default_config.sh b/installation/includes/01_default_config.sh index eb6e45a91..b2f37a1de 100644 --- a/installation/includes/01_default_config.sh +++ b/installation/includes/01_default_config.sh @@ -11,7 +11,9 @@ DISABLE_SSH_QOS=true DISABLE_BOOT_SCREEN=true DISABLE_BOOT_LOGS_PRINT=true SETUP_MPD=true +ENABLE_MPD_OVERWRITE_INSTALL=true UPDATE_RASPI_OS=${UPDATE_RASPI_OS:-"true"} +ENABLE_RFID_READER=true ENABLE_SAMBA=true ENABLE_WEBAPP=true ENABLE_KIOSK_MODE=false diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index 9ad8e71b8..4a39ae07e 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Helpers +### Helpers # $1->start, $2->end calc_runtime_and_print() { @@ -9,7 +9,7 @@ calc_runtime_and_print() { ((m=(${runtime}%3600)/60)) ((s=${runtime}%60)) - echo "Done in ${h}h ${m}m ${s}s." + echo "Done in ${h}h ${m}m ${s}s" } run_with_timer() { @@ -18,7 +18,20 @@ run_with_timer() { $1; # Executes the function passed as an argument calc_runtime_and_print time_start $(date +%s) | tee /dev/fd/3 - echo "--------------------------------------" +} + +run_with_log_frame() { + local time_start=$(date +%s); + local description="$2" + echo -e "\n\n" + echo "#########################################################" + echo "${description}" | tee /dev/fd/3 + + $1; # Executes the function passed as an argument + + local done_in=$(calc_runtime_and_print time_start $(date +%s)) + echo -e "\n${done_in} - ${description}" + echo "#########################################################" } _download_file_from_google_drive() { @@ -28,31 +41,231 @@ _download_file_from_google_drive() { echo "Downloaded from Google Drive ID ${GD_SHARING_ID} into ${TAR_FILENAME}" } -get_onboard_audio() { - if grep -q -E "^dtparam=([^,]*,)*audio=(on|true|yes|1).*" ${RPI_BOOT_CONFIG_FILE} - then - echo 1 - else - echo 0 - fi + +### Verify helpers + +print_verify_installation() { + echo "" + echo " -------------------------------------------------------" + echo " Check installation" + echo "" +} + +# Check if the file(s) exists +verify_files_exists() { + local files="$@" + echo " Verify '${files}' exists" + + if [[ -z "${files}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + for file in $files + do + test ! -f ${file} && exit_on_error "ERROR: '${file}' does not exists or is not a file!" + done + echo " CHECK" +} + +# Check if the dir(s) exists +verify_dirs_exists() { + local dirs="$@" + echo " Verify '${dirs}' exists" + + if [[ -z "${dirs}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + for dir in $dirs + do + test ! -d ${dir} && exit_on_error "ERROR: '${dir}' does not exists or is not a dir!" + done + echo " CHECK" +} + +# Check if the file(s) has/have the expected owner and modifications +verify_files_chmod_chown() { + local mod_expected=$1 + local user_expected=$2 + local group_expected=$3 + local files="${@:4}" + echo " Verify '${mod_expected}' '${user_expected}:${group_expected}' is set for '${files}'" + + if [[ -z "${mod_expected}" || -z "${user_expected}" || -z "${group_expected}" || -z "${files}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + for file in $files + do + test ! -f ${file} && exit_on_error "ERROR: '${file}' does not exists or is not a file!" + + mod_actual=$(stat --format '%a' "${file}") + user_actual=$(stat -c '%U' "${file}") + group_actual=$(stat -c '%G' "${file}") + test ! "${mod_expected}" -eq "${mod_actual}" && exit_on_error "ERROR: '${file}' actual mod '${mod_actual}' differs from expected '${mod_expected}'!" + test ! "${user_expected}" == "${user_actual}" && exit_on_error "ERROR: '${file}' actual owner '${user_actual}' differs from expected '${user_expected}'!" + test ! "${group_expected}" == "${group_actual}" && exit_on_error "ERROR: '${file}' actual group '${group_actual}' differs from expected '${group_expected}'!" + done + echo " CHECK" +} + +# Check if the dir(s) has/have the expected owner and modifications +verify_dirs_chmod_chown() { + local mod_expected=$1 + local user_expected=$2 + local group_expected=$3 + local dirs="${@:4}" + echo " Verify '${mod_expected}' '${user_expected}:${group_expected}' is set for '${dirs}'" + + if [[ -z "${mod_expected}" || -z "${user_expected}" || -z "${group_expected}" || -z "${dirs}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + for dir in $dirs + do + test ! -d ${dir} && exit_on_error "ERROR: '${dir}' does not exists or is not a dir!" + + mod_actual=$(stat --format '%a' "${dir}") + user_actual=$(stat -c '%U' "${dir}") + group_actual=$(stat -c '%G' "${dir}") + test ! "${mod_expected}" -eq "${mod_actual}" && exit_on_error "ERROR: '${dir}' actual mod '${mod_actual}' differs from expected '${mod_expected}'!" + test ! "${user_expected}" == "${user_actual}" && exit_on_error "ERROR: '${dir}' actual owner '${user_actual}' differs from expected '${user_expected}'!" + test ! "${group_expected}" == "${group_actual}" && exit_on_error "ERROR: '${dir}' actual group '${group_actual}' differs from expected '${group_expected}'!" + done + echo " CHECK" +} + +verify_file_contains_string() { + local string="$1" + local file="$2" + echo " Verify '${string}' found in '${file}'" + + if [[ -z "${string}" || -z "${file}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + if [[ ! $(grep -iw "${string}" "${file}") ]]; then + exit_on_error "ERROR: '${string}' not found in '${file}'" + fi + echo " CHECK" +} + +verify_file_contains_string_once() { + local string="$1" + local file="$2" + echo " Verify '${string}' found in '${file}'" + + if [[ -z "${string}" || -z "${file}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + local file_contains_string_count=$(grep -oiw "${string}" "${file}" | wc -l) + if [ "$file_contains_string_count" -lt 1 ]; then + exit_on_error "ERROR: '${string}' not found in '${file}'" + elif [ "$file_contains_string_count" -gt 1 ]; then + exit_on_error "ERROR: '${string}' found more than once in '${file}'" + fi + echo " CHECK" +} + +verify_service_state() { + local service="$1" + local desired_state="$2" + local option="${3:+$3 }" # optional, dont't quote in next call! + echo " Verify service '${option}${service}' is '${desired_state}'" + + if [[ -z "${service}" || -z "${desired_state}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + local actual_state=$(systemctl is-active ${option}${service}) + if [[ ! "${actual_state}" == "${desired_state}" ]]; then + exit_on_error "ERROR: service '${option}${service}' is not '${desired_state}' (state: '${actual_state}')." + fi + echo " CHECK" +} + +verify_service_enablement() { + local service="$1" + local desired_enablement="$2" + local option="${3:+$3 }" # optional, dont't quote in next call! + echo " Verify service ${option}${service} is ${desired_enablement}" + + if [[ -z "${service}" || -z "${desired_enablement}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + local actual_enablement=$(systemctl is-enabled ${option}${service}) + if [[ ! "${actual_enablement}" == "${desired_enablement}" ]]; then + exit_on_error "ERROR: service ${option}${service} is not ${desired_enablement} (state: ${actual_enablement})." + fi + echo " CHECK" +} + +verify_optional_service_enablement() { + local service="$1" + local desired_enablement="$2" + local option="${3:+$3 }" # optional, dont't quote in next call! + echo " Verify service ${option}${service} is ${desired_enablement}" + + if [[ -z "${service}" || -z "${desired_enablement}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + local actual_enablement=$(systemctl is-enabled ${option}${service}) 2>/dev/null + if [[ -z "${actual_enablement}" ]]; then + echo " INFO: optional service ${option}${service} is not installed." + elif [[ "${actual_enablement}" == "static" ]]; then + echo " INFO: optional service ${option}${service} is set static." + elif [[ ! "${actual_enablement}" == "${desired_enablement}" ]]; then + exit_on_error "ERROR: service ${option}${service} is not ${desired_enablement} (state: ${actual_enablement})." + fi + echo " CHECK" +} + +# Reads a textfile and returns all lines as args. +# Does filter out comments, egg-prefixes and version suffixes +# Arguments: +# 1 : textfile to read +get_args_from_file() { + local package_file="$1" + sed 's/.*#egg=//g' ${package_file} | sed -E 's/(#|=|>|<).*//g' | xargs echo } -check_os_type() { - # Check if current distro is a 32 bit version - # Support for 64 bit Distros has not been checked (or precisely: is known not to work) - # All RaspianOS versions report as machine "armv6l" or "armv7l", if 32 bit (even the ARMv8 cores!) +# Check if all passed packages are installed. Fail on first missing. +verify_apt_packages() { + local packages="$@" + echo " Verify packages are installed: '${packages}'" + + if [[ -z "${packages}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi - local os_type - os_type=$(uname -m) + local apt_list_installed=$(apt -qq list --installed 2>/dev/null) + for package in ${packages} + do + if [[ ! $(echo "${apt_list_installed}" | grep -i "^${package}/.*installed") ]]; then + exit_on_error "ERROR: ${package} is not installed" + fi + done + echo " CHECK" +} - echo -e "\nChecking OS type '$os_type'" | tee /dev/fd/3 +# Check if all passed modules are installed. Fail on first missing. +verify_pip_modules() { + local modules="$@" + echo " Verify modules are installed: '${modules}'" - if [[ $os_type == "armv7l" || $os_type == "armv6l" ]]; then - echo -e " ... OK!\n" | tee /dev/fd/3 - else - echo "ERROR: Only 32 bit operating systems supported. Please use a 32bit version of RaspianOS!" | tee /dev/fd/3 - echo "You can fix this problem for 64bit kernels: https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/2041" | tee /dev/fd/3 - exit 1 - fi + if [[ -z "${modules}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + local pip_list_installed=$(pip list 2>/dev/null) + for module in ${modules} + do + if [[ ! $(echo "${pip_list_installed}" | grep -i "^${module} ") ]]; then + exit_on_error "ERROR: ${module} is not installed" + fi + done + echo " CHECK" } diff --git a/installation/includes/04_cleanup.sh b/installation/includes/04_cleanup.sh index fd714132f..d6e39266c 100644 --- a/installation/includes/04_cleanup.sh +++ b/installation/includes/04_cleanup.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash -cleanup() { - sudo rm -rf /var/lib/apt/lists/* +_run_cleanup() { + sudo rm -rf /var/lib/apt/lists/* +} - echo "DONE: cleanup" +cleanup() { + run_with_log_frame _run_cleanup "Cleanup" } diff --git a/installation/includes/05_finish.sh b/installation/includes/05_finish.sh index 50c2f6d9d..55489ff46 100644 --- a/installation/includes/05_finish.sh +++ b/installation/includes/05_finish.sh @@ -14,8 +14,8 @@ Your SSH connection will disconnect. After the reboot, you can access the WebApp in your browser at http://${local_hostname}.local or http://${CURRENT_IP_ADDRESS} Don't forget to upload files. - -Do you want to reboot now? [Y/n]" 1>&3 +" | tee /dev/fd/3 +echo "Do you want to reboot now? [Y/n]" 1>&3 read -r response case "$response" in @@ -31,24 +31,3 @@ Do you want to reboot now? [Y/n]" 1>&3 ;; esac } - -# Generic emergency error handler that exits the script immediately -# Print additional custom message if passed as first argument -# Examples: -# cd some-dir || exit_on_error -# cd some-dir || exit_on_error "During installation of some" -exit_on_error () { - - echo -e "\n****************************************" | tee /dev/fd/3 - echo "ERROR OCCURRED! -A non-recoverable error occurred. -Check install log for details:" | tee /dev/fd/3 - echo "$INSTALLATION_LOGFILE" | tee /dev/fd/3 - echo "****************************************" | tee /dev/fd/3 - if [[ -n $1 ]]; then - echo "$1" | tee /dev/fd/3 - echo "****************************************" | tee /dev/fd/3 - fi - echo "Abort!" - exit 1 -} diff --git a/installation/install-jukebox.sh b/installation/install-jukebox.sh index 44b03fca0..b72dd32ff 100755 --- a/installation/install-jukebox.sh +++ b/installation/install-jukebox.sh @@ -20,17 +20,36 @@ GIT_URL="https://github.com/${GIT_USER}/${GIT_REPO_NAME}" echo GIT_BRANCH $GIT_BRANCH echo GIT_URL $GIT_URL -CURRENT_USER="${SUDO_USER:-$USER}" +CURRENT_USER="${SUDO_USER:-$(whoami)}" +CURRENT_USER_GROUP=$(id -gn "$CURRENT_USER") HOME_PATH=$(getent passwd "$CURRENT_USER" | cut -d: -f6) echo "Current User: $CURRENT_USER" echo "User home dir: $HOME_PATH" INSTALLATION_PATH="${HOME_PATH}/${GIT_REPO_NAME}" INSTALL_ID=$(date +%s) +INSTALLATION_LOGFILE="${HOME_PATH}/INSTALL-${INSTALL_ID}.log" + +# Check if current distro is a 32 bit version +# Support for 64 bit Distros has not been checked (or precisely: is known not to work) +# All RaspianOS versions report as machine "armv6l" or "armv7l", if 32 bit (even the ARMv8 cores!) +_check_os_type() { + local os_type=$(uname -m) + + echo -e "\nChecking OS type '$os_type'" + + if [[ $os_type == "armv7l" || $os_type == "armv6l" ]]; then + echo -e " ... OK!\n" + else + echo "ERROR: Only 32 bit operating systems supported. Please use a 32bit version of RaspianOS!" + echo "You can fix this problem for 64bit kernels: https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/2041" + exit 1 + fi +} -checkPrerequisite() { - #currently the user 'pi' is mandatory - #https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/1785 +# currently the user 'pi' is mandatory +# https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/1785 +_check_user() { if [ "${CURRENT_USER}" != "pi" ]; then echo echo "ERROR: User must be 'pi'!" @@ -46,52 +65,104 @@ checkPrerequisite() { echo " Please check the wiki for further information" exit 2 fi + + if [ ! -d "${HOME_PATH}" ]; then + echo + echo "ERROR: HomeDir ${HOME_PATH} does not exist." + echo " Please create it and start again." + exit 2 + fi +} + +# Manipulate file descriptor for logging +# Behavior: +# Write To logfile: +# default stdout will only write to logfile +# default stderr will only write to logfile +# e.g echo "write only to logfile" +# Write To console (user window): +# redirect to fd 3 will only write to the console +# e.g. echo "write only to console" 1>&3 +# Write To both: +# use tee to write output to logfile and console +# e.g. echo "write to both" | tee /dev/fd/3 +_setup_logging(){ + if [ "$CI_RUNNING" == "true" ]; then + exec 3>&1 2>&1 + else + exec 3>&1 1>>"${INSTALLATION_LOGFILE}" 2>&1 || { echo "ERROR: Cannot create log file."; exit 1; } + fi + echo "Log start: ${INSTALL_ID}" +} + +# Generic emergency error handler that exits the script immediately +# Print additional custom message if passed as first argument +# Examples: +# a command || exit_on_error +# a command || exit_on_error "Execution of command failed" +exit_on_error () { + echo -e "\n****************************************" | tee /dev/fd/3 + echo "ERROR OCCURRED! +A non-recoverable error occurred. +Check install log for details:" | tee /dev/fd/3 + echo "$INSTALLATION_LOGFILE" | tee /dev/fd/3 + echo "****************************************" | tee /dev/fd/3 + if [[ -n $1 ]]; then + echo "$1" | tee /dev/fd/3 + echo "****************************************" | tee /dev/fd/3 + fi + echo "Abort!" + exit 1 } -download_jukebox_source() { +_download_jukebox_source() { + echo -e "\n\n" + echo "#########################################################" + echo "Downloading Phoniebox software from Github ..." 1>&3 + echo "Download Source: ${GIT_URL}/${GIT_BRANCH}" | tee /dev/fd/3 + + cd "${HOME_PATH}" || exit_on_error "ERROR: Changing to home dir failed." wget -qO- "${GIT_URL}/tarball/${GIT_BRANCH}" | tar xz # Use case insensitive search/sed because user names in Git Hub are case insensitive - GIT_REPO_DOWNLOAD=$(find . -maxdepth 1 -type d -iname "${GIT_USER}-${GIT_REPO_NAME}-*") - echo "GIT REPO DOWNLOAD = $GIT_REPO_DOWNLOAD" - GIT_HASH=$(echo "$GIT_REPO_DOWNLOAD" | sed -rn "s/.*${GIT_USER}-${GIT_REPO_NAME}-([0-9a-fA-F]+)/\1/ip") + local git_repo_download=$(find . -maxdepth 1 -type d -iname "${GIT_USER}-${GIT_REPO_NAME}-*") + echo "GIT REPO DOWNLOAD = $git_repo_download" + GIT_HASH=$(echo "$git_repo_download" | sed -rn "s/.*${GIT_USER}-${GIT_REPO_NAME}-([0-9a-fA-F]+)/\1/ip") # Save the git hash for this particular download for later git repo initialization echo "GIT HASH = $GIT_HASH" - if [[ -z ${GIT_REPO_DOWNLOAD} ]]; then - echo "ERROR in finding git download. Panic." - exit 1 + if [[ -z "${git_repo_download}" ]]; then + exit_on_error "ERROR: Couldn't find git download." fi - if [[ -z ${GIT_HASH} ]]; then - echo "ERROR in determining git hash from download. Panic." - exit 1 + if [[ -z "${GIT_HASH}" ]]; then + exit_on_error "ERROR: Couldn't determine git hash from download." fi - mv "$GIT_REPO_DOWNLOAD" "$GIT_REPO_NAME" - unset GIT_REPO_DOWNLOAD + mv "$git_repo_download" "$GIT_REPO_NAME" + echo -e "\nDONE: Downloading Phoniebox software from Github" + echo "#########################################################" } +_load_sources() { + # Load / Source dependencies + for i in "${INSTALLATION_PATH}"/installation/includes/*; do + source "$i" + done -### CHECK PREREQUISITE -checkPrerequisite - -### RUN INSTALLATION -INSTALLATION_LOGFILE="${HOME_PATH}/INSTALL-${INSTALL_ID}.log" -exec 3>&1 1>>"${INSTALLATION_LOGFILE}" 2>&1 || { echo "Cannot create log file. Panic."; exit 1; } -echo "Log start: ${INSTALL_ID}" + for j in "${INSTALLATION_PATH}"/installation/routines/*; do + source "$j" + done +} -clear 1>&3 -echo "Downloading Phoniebox software from Github ..." 1>&3 -echo "Download Source: ${GIT_URL}/${GIT_BRANCH}" | tee /dev/fd/3 -download_jukebox_source -cd "${INSTALLATION_PATH}" || { echo "ERROR in changing to install dir. Panic."; exit 1; } +### CHECK PREREQUISITE +_check_os_type +_check_user -# Load / Source dependencies -for i in "${INSTALLATION_PATH}"/installation/includes/*; do - source "$i" -done +### SETUP LOGGING +_setup_logging -for j in "${INSTALLATION_PATH}"/installation/routines/*; do - source "$j" -done +### RUN INSTALLATION +_download_jukebox_source +cd "${INSTALLATION_PATH}" || exit_on_error "ERROR: Changing to install dir failed." +_load_sources welcome run_with_timer install diff --git a/installation/routines/customize_options.sh b/installation/routines/customize_options.sh index d5ac7c547..50df075fe 100644 --- a/installation/routines/customize_options.sh +++ b/installation/routines/customize_options.sh @@ -118,6 +118,54 @@ Do you want to disable Bluetooth? [Y/n]" 1>&3 echo "DISABLE_BLUETOOTH=${DISABLE_BLUETOOTH}" } +_option_mpd() { + clear 1>&3 + if [[ "$SETUP_MPD" == true ]]; then + if [[ -f "${MPD_CONF_PATH}" || -f "${SYSTEMD_USR_PATH}/mpd.service" ]]; then + echo "-------------------------- MPD -------------------------- + +It seems there is a MPD already installed. +Note: It is important that MPD runs as a user service! +Would you like to overwrite your configuration? [Y/n]" 1>&3 + read -r response + case "$response" in + [nN][oO]|[nN]) + ENABLE_MPD_OVERWRITE_INSTALL=false + ;; + *) + ;; + esac + fi + fi + + echo "SETUP_MPD=${SETUP_MPD}" + if [ "$SETUP_MPD" == true ]; then + echo "ENABLE_MPD_OVERWRITE_INSTALL=${ENABLE_MPD_OVERWRITE_INSTALL}" + fi +} + +_option_rfid_reader() { + # ENABLE_RFID_READER + clear 1>&3 + echo "---------------------- RFID READER ---------------------- + +Phoniebox can be controlled with rfid cards/tags, if you +have a rfid reader connected. +Choose yes to setup a reader. You get prompted for +the type selection and configuration later on. + +Do you want to setup a rfid reader? [Y/n]" 1>&3 + read -r response + case "$response" in + [nN][oO]|[nN]) + ENABLE_RFID_READER=false + ;; + *) + ;; + esac + echo "ENABLE_RFID_READER=${ENABLE_RFID_READER}" +} + _option_samba() { # ENABLE_SAMBA clear 1>&3 @@ -133,7 +181,6 @@ Do you want to install Samba? [Y/n]" 1>&3 case "$response" in [nN][oO]|[nN]) ENABLE_SAMBA=false - ENABLE_KIOSK_MODE=false ;; *) ;; @@ -237,13 +284,13 @@ Disable Pi's on-chip audio (headphone / jack output)? [y/N]" 1>&3 _option_webapp_devel_build() { # Let's detect if we are on the official release branch - if [[ "$GIT_BRANCH" != "${GIT_BRANCH_RELEASE}" || "$GIT_USER" != "$GIT_UPSTREAM_USER" ]]; then + if [[ "$GIT_BRANCH" != "${GIT_BRANCH_RELEASE}" || "$GIT_USER" != "$GIT_UPSTREAM_USER" || "$CI_RUNNING" == "true" ]]; then ENABLE_INSTALL_NODE=true # Unless ENABLE_WEBAPP_PROD_DOWNLOAD is forced to true by user override, do not download a potentially stale build - if [[ "$ENABLE_WEBAPP_PROD_DOWNLOAD" = "release-only" ]]; then + if [[ "$ENABLE_WEBAPP_PROD_DOWNLOAD" == "release-only" ]]; then ENABLE_WEBAPP_PROD_DOWNLOAD=false fi - if [[ "$ENABLE_WEBAPP_PROD_DOWNLOAD" = false ]]; then + if [[ "$ENABLE_WEBAPP_PROD_DOWNLOAD" == false ]]; then clear 1>&3 echo "--------------------- WEBAPP NODE --------------------- @@ -261,22 +308,23 @@ Do you want to install Node? [Y/n]" 1>&3 ;; esac # This message will be displayed at the end of the installation process - FIN_MESSAGE="$FIN_MESSAGE\nATTENTION: You need to build the web app locally with - $ cd ~/RPi-Jukebox-RFID/src/webapp && ./run_rebuild.sh -u - This must be done after reboot, due to memory restrictions. - Read the documentation regarding local Web App builds!" + local tmp_fin_message="ATTENTION: You need to build the web app locally with + $ cd ~/RPi-Jukebox-RFID/src/webapp && ./run_rebuild.sh -u + This must be done after reboot, due to memory restrictions. + Read the documentation regarding local Web App builds!" + FIN_MESSAGE="${FIN_MESSAGE:+$FIN_MESSAGE\n}${tmp_fin_message}" fi fi } -customize_options() { - echo "Customize Options starts" - +_run_customize_options() { _option_ipv6 _option_static_ip _option_autohotspot _option_bluetooth _option_disable_onboard_audio + _option_mpd + _option_rfid_reader _option_samba _option_webapp if [[ $ENABLE_WEBAPP == true ]] ; then @@ -286,6 +334,8 @@ customize_options() { # Bullseye is currently under active development and should be updated in any case. # Hence, removing the step below as it becomse mandatory # _options_update_raspi_os +} - echo "Customize Options ends" +customize_options() { + run_with_log_frame _run_customize_options "Customize Options" } diff --git a/installation/routines/install.sh b/installation/routines/install.sh index ca25a17a3..d241658b6 100644 --- a/installation/routines/install.sh +++ b/installation/routines/install.sh @@ -1,19 +1,18 @@ install() { - check_os_type clear 1>&3 customize_options clear 1>&3 set_raspi_config - if [ "$DISABLE_SSH_QOS" = true ] ; then set_ssh_qos; fi; - if [ "$UPDATE_RASPI_OS" = true ] ; then update_raspi_os; fi; + set_ssh_qos + update_raspi_os init_git_repo_from_tardir setup_jukebox_core - if [ "$SETUP_MPD" = true ] ; then setup_mpd; fi; - if [ "$ENABLE_SAMBA" = true ] ; then setup_samba; fi; - if [ "$ENABLE_WEBAPP" = true ] ; then setup_jukebox_webapp; fi; - if [ "$ENABLE_KIOSK_MODE" = true ] ; then setup_kiosk_mode; fi; + setup_mpd + setup_samba + setup_jukebox_webapp + setup_kiosk_mode setup_rfid_reader optimize_boot_time - if [ "$ENABLE_AUTOHOTSPOT" = true ] ; then setup_autohotspot; fi; + setup_autohotspot cleanup } diff --git a/installation/routines/optimize_boot_time.sh b/installation/routines/optimize_boot_time.sh index 2fea66a86..383f790c0 100644 --- a/installation/routines/optimize_boot_time.sh +++ b/installation/routines/optimize_boot_time.sh @@ -2,18 +2,24 @@ # Reference: https://panther.software/configuration-code/raspberry-pi-3-4-faster-boot-time-in-few-easy-steps/ +OPTIMIZE_DHCP_CONF="/etc/dhcpcd.conf" +OPTIMIZE_BOOT_CMDLINE_OPTIONS="consoleblank=1 logo.nologo quiet loglevel=0 plymouth.enable=0 vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fastboot noatime nodiratime noram" +OPTIMIZE_DHCP_CONF_HEADER="## Jukebox DHCP Config" +OPTIMIZE_IPV6_CONF_HEADER="## Jukebox IPV6 Config" +OPTIMIZE_BOOT_CONF_HEADER="## Jukebox Boot Config" + _optimize_disable_irrelevant_services() { - echo " * Disable keyboard-setup.service" + echo " Disable keyboard-setup.service" sudo systemctl disable keyboard-setup.service - echo " * Disable triggerhappy.service" + echo " Disable triggerhappy.service" sudo systemctl disable triggerhappy.service sudo systemctl disable triggerhappy.socket - echo " * Disable raspi-config.service" + echo " Disable raspi-config.service" sudo systemctl disable raspi-config.service - echo " * Disable apt-daily.service & apt-daily-upgrade.service" + echo " Disable apt-daily.service & apt-daily-upgrade.service" sudo systemctl disable apt-daily.service sudo systemctl disable apt-daily-upgrade.service sudo systemctl disable apt-daily.timer @@ -23,30 +29,28 @@ _optimize_disable_irrelevant_services() { # TODO: If false, actually make sure bluetooth is enabled _optimize_handle_bluetooth() { if [ "$DISABLE_BLUETOOTH" = true ] ; then - echo " * Disable hciuart.service and bluetooth" + echo " Disable bluetooth" | tee /dev/fd/3 sudo systemctl disable hciuart.service sudo systemctl disable bluetooth.service fi } # TODO: Allow options to enable/disable wifi, Dynamic/Static IP etc. -_optimize_handle_network_connection() { +_optimize_static_ip() { # Static IP Address and DHCP optimizations - local DHCP_CONF="/etc/dhcpcd.conf" - if [ "$ENABLE_STATIC_IP" = true ] ; then - echo " * Set static IP address" | tee /dev/fd/3 - if grep -q "## Jukebox DHCP Config" "$DHCP_CONF"; then - echo " Skipping. Already set up!" | tee /dev/fd/3 + echo " Set static IP address" | tee /dev/fd/3 + if grep -q "${OPTIMIZE_DHCP_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then + echo " Skipping. Already set up!" else # DHCP has not been configured - echo " * ${CURRENT_INTERFACE} is the default network interface" | tee /dev/fd/3 - echo " * ${CURRENT_GATEWAY} is the Router Gateway address" | tee /dev/fd/3 - echo " * Using ${CURRENT_IP_ADDRESS} as the static IP for now" | tee /dev/fd/3 + echo " ${CURRENT_INTERFACE} is the default network interface" + echo " ${CURRENT_GATEWAY} is the Router Gateway address" + echo " Using ${CURRENT_IP_ADDRESS} as the static IP for now" - sudo tee -a $DHCP_CONF <<-EOF + sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF -## Jukebox DHCP Config +${OPTIMIZE_DHCP_CONF_HEADER} interface ${CURRENT_INTERFACE} static ip_address=${CURRENT_IP_ADDRESS}/24 static routers=${CURRENT_GATEWAY} @@ -55,59 +59,114 @@ static domain_name_servers=${CURRENT_GATEWAY} EOF fi - else - echo " * Skipped static IP address" fi } # TODO: Allow both Enable and Disable _optimize_ipv6_arp() { if [ "$DISABLE_IPv6" = true ] ; then - echo " * Disabling IPV6 and ARP" - sudo tee -a $DHCP_CONF <<-EOF + echo " Disabling IPV6" | tee /dev/fd/3 + if grep -q "${OPTIMIZE_IPV6_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then + echo " Skipping. Already set up!" + else + sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF -## Jukebox boot speed-up settings +${OPTIMIZE_IPV6_CONF_HEADER} noarp ipv4only noipv6 EOF - + fi fi } # TODO: Allow both Enable and Disable _optimize_handle_boot_screen() { if [ "$DISABLE_BOOT_SCREEN" = true ] ; then - echo " * Disable RPi rainbow screen" - BOOT_CONFIG='/boot/config.txt' - sudo tee -a $BOOT_CONFIG <<-EOF + echo " Disable RPi rainbow screen" + if grep -q "${OPTIMIZE_BOOT_CONF_HEADER}" "$RPI_BOOT_CONFIG_FILE"; then + echo " Skipping. Already set up!" + else + sudo tee -a $RPI_BOOT_CONFIG_FILE <<-EOF -## Jukebox Settings +${OPTIMIZE_BOOT_CONF_HEADER} disable_splash=1 EOF + fi fi } # TODO: Allow both Enable and Disable _optimize_handle_boot_logs() { if [ "$DISABLE_BOOT_LOGS_PRINT" = true ] ; then - echo " * Disable boot logs" - BOOT_CMDLINE='/boot/cmdline.txt' - sudo sed -i "$ s/$/ consoleblank=1 logo.nologo quiet loglevel=0 plymouth.enable=0 vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fastboot noatime nodiratime noram/" $BOOT_CMDLINE + echo " Disable boot logs" + + if [ ! -s "${RPI_BOOT_CMDLINE_FILE}" ];then + sudo tee "${RPI_BOOT_CMDLINE_FILE}" <<-EOF +${OPTIMIZE_BOOT_CMDLINE_OPTIONS} +EOF + else + for option in $OPTIMIZE_BOOT_CMDLINE_OPTIONS + do + if ! grep -qiw "$option" "${RPI_BOOT_CMDLINE_FILE}" ; then + sudo sed -i "s/$/ $option/" "${RPI_BOOT_CMDLINE_FILE}" + fi + done + fi fi } -optimize_boot_time() { - echo "Optimize boot time" | tee /dev/fd/3 - _optimize_disable_irrelevant_services - _optimize_handle_bluetooth - _optimize_handle_network_connection - _optimize_ipv6_arp - _optimize_handle_boot_screen - _optimize_handle_boot_logs +_optimize_check() { + print_verify_installation + + verify_optional_service_enablement keyboard-setup.service disabled + verify_optional_service_enablement triggerhappy.service disabled + verify_optional_service_enablement triggerhappy.socket disabled + verify_optional_service_enablement raspi-config.service disabled + verify_optional_service_enablement apt-daily.service disabled + verify_optional_service_enablement apt-daily-upgrade.service disabled + verify_optional_service_enablement apt-daily.timer disabled + verify_optional_service_enablement apt-daily-upgrade.timer disabled - echo "DONE: optimize_boot_time" + if [ "$DISABLE_BLUETOOTH" = true ] ; then + verify_optional_service_enablement hciuart.service disabled + verify_optional_service_enablement bluetooth.service disabled + fi + + if [ "$ENABLE_STATIC_IP" = true ] ; then + verify_file_contains_string_once "${OPTIMIZE_DHCP_CONF_HEADER}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string "${CURRENT_INTERFACE}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string "${CURRENT_IP_ADDRESS}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string "${CURRENT_GATEWAY}" "${OPTIMIZE_DHCP_CONF}" + fi + if [ "$DISABLE_IPv6" = true ] ; then + verify_file_contains_string_once "${OPTIMIZE_IPV6_CONF_HEADER}" "${OPTIMIZE_DHCP_CONF}" + fi + if [ "$DISABLE_BOOT_SCREEN" = true ] ; then + verify_file_contains_string_once "${OPTIMIZE_BOOT_CONF_HEADER}" "${RPI_BOOT_CONFIG_FILE}" + fi + + if [ "$DISABLE_BOOT_LOGS_PRINT" = true ] ; then + for option in $OPTIMIZE_BOOT_CMDLINE_OPTIONS + do + verify_file_contains_string_once $option "${RPI_BOOT_CMDLINE_FILE}" + done + fi +} + +_run_optimize_boot_time() { + _optimize_disable_irrelevant_services + _optimize_handle_bluetooth + _optimize_static_ip + _optimize_ipv6_arp + _optimize_handle_boot_screen + _optimize_handle_boot_logs + _optimize_check +} + +optimize_boot_time() { + run_with_log_frame _run_optimize_boot_time "Optimize boot time" } diff --git a/installation/routines/set_raspi_config.sh b/installation/routines/set_raspi_config.sh index 1b1c3ee55..a9cb7b6f1 100644 --- a/installation/routines/set_raspi_config.sh +++ b/installation/routines/set_raspi_config.sh @@ -1,33 +1,33 @@ #!/usr/bin/env bash - -set_raspi_config() { - echo "Set default raspi-config" | tee /dev/fd/3 +_run_set_raspi_config() { # Source: https://raspberrypi.stackexchange.com/a/66939 # Autologin - echo " * Enable Autologin for user" + echo " Enable Autologin for user" sudo raspi-config nonint do_boot_behaviour B2 # Wait for network at boot - # echo " * Enable 'Wait for network at boot'" + # echo " Enable 'Wait for network at boot'" # sudo raspi-config nonint do_boot_wait 1 # power management of wifi: switch off to avoid disconnecting - echo " * Disable Wifi power management to avoid disconnecting" + echo " Disable Wifi power management to avoid disconnecting" sudo iwconfig wlan0 power off # On-board audio - if [[ $(get_onboard_audio) -eq 1 ]]; then - DISABLE_ONBOARD_AUDIO=${DISABLE_ONBOARD_AUDIO:-false} - if [[ $DISABLE_ONBOARD_AUDIO = true ]]; then - echo " * Disable on-chip BCM audio" - echo "Backup ${RPI_BOOT_CONFIG_FILE} --> ${DISABLE_ONBOARD_AUDIO_BACKUP}" + if [ "$DISABLE_ONBOARD_AUDIO" == true ]; then + echo " Disable on-chip BCM audio" + if grep -q -E "^dtparam=([^,]*,)*audio=(on|true|yes|1).*" "${RPI_BOOT_CONFIG_FILE}" ; then + echo " Backup ${RPI_BOOT_CONFIG_FILE} --> ${DISABLE_ONBOARD_AUDIO_BACKUP}" sudo cp "${RPI_BOOT_CONFIG_FILE}" "${DISABLE_ONBOARD_AUDIO_BACKUP}" sudo sed -i "s/^\(dtparam=\([^,]*,\)*\)audio=\(on\|true\|yes\|1\)\(.*\)/\1audio=off\4/g" "${RPI_BOOT_CONFIG_FILE}" + else + echo " On board audio seems to be off already. Not touching ${RPI_BOOT_CONFIG_FILE}" fi - else - echo "On board audio seems to be off already. Not touching ${RPI_BOOT_CONFIG_FILE}" fi +} +set_raspi_config() { + run_with_log_frame _run_set_raspi_config "Set default raspi-config" } diff --git a/installation/routines/set_ssh_qos.sh b/installation/routines/set_ssh_qos.sh index ad67ddc41..eaca62fed 100644 --- a/installation/routines/set_ssh_qos.sh +++ b/installation/routines/set_ssh_qos.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash set_ssh_qos() { - # The latest version of SSH installed on the Raspberry Pi 3 uses QoS headers, which disagrees with some - # routers and other hardware. This causes immense delays when remotely accessing the RPi over ssh. - echo " * Set SSH QoS to best effort" - echo -e "IPQoS 0x00 0x00\n" | sudo tee -a /etc/ssh/sshd_config - echo -e "IPQoS 0x00 0x00\n" | sudo tee -a /etc/ssh/ssh_config + if [ "$DISABLE_SSH_QOS" == true ] ; then + # The latest version of SSH installed on the Raspberry Pi 3 uses QoS headers, which disagrees with some + # routers and other hardware. This causes immense delays when remotely accessing the RPi over ssh. + echo " Set SSH QoS to best effort" + echo -e "IPQoS 0x00 0x00\n" | sudo tee -a /etc/ssh/sshd_config + echo -e "IPQoS 0x00 0x00\n" | sudo tee -a /etc/ssh/ssh_config + fi } diff --git a/installation/routines/setup_autohotspot.sh b/installation/routines/setup_autohotspot.sh index 214a90e0f..a385352dd 100644 --- a/installation/routines/setup_autohotspot.sh +++ b/installation/routines/setup_autohotspot.sh @@ -1,14 +1,34 @@ #!/usr/bin/env bash +# inspired by +# https://www.raspberryconnect.com/projects/65-raspberrypi-hotspot-accesspoints/158-raspberry-pi-auto-wifi-hotspot-switch-direct-connection + + +AUTOHOTSPOT_HOSTAPD_CONF_FILE="/etc/hostapd/hostapd.conf" +AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE="/etc/default/hostapd" +AUTOHOTSPOT_DNSMASQ_CONF_FILE="/etc/dnsmasq.conf" +AUTOHOTSPOT_DHCPD_CONF_FILE="/etc/dhcpcd.conf" + +AUTOHOTSPOT_TARGET_PATH="/usr/bin/autohotspot" + _get_interface() { # interfaces may vary WIFI_INTERFACE=$(iw dev | grep "Interface"| awk '{ print $2 }') WIFI_REGION=$(iw reg get | grep country | awk '{ print $2}' | cut -d: -f1) -} + # fix for CI runs on docker + if [ "${CI_RUNNING}" == "true" ]; then + if [ -z "${WIFI_INTERFACE}" ]; then + WIFI_INTERFACE="CI TEST INTERFACE" + fi + if [ -z "${WIFI_REGION}" ]; then + WIFI_REGION="CI TEST REGION" + fi + fi +} _install_packages() { - sudo apt-get -y install hostapd dnsmasq + sudo apt-get -y install hostapd dnsmasq iw # disable services. We want to start them manually sudo systemctl unmask hostapd @@ -17,18 +37,18 @@ _install_packages() { } _configure_hostapd() { - HOSTAPD_CUSTOM_FILE="${INSTALLATION_PATH}"/resources/autohotspot/hostapd.conf - HOSTAPD_CONF_FILE="/etc/hostapd/hostapd.conf" + local HOSTAPD_CUSTOM_FILE="${INSTALLATION_PATH}"/resources/autohotspot/hostapd.conf + sed -i "s/WIFI_INTERFACE/${WIFI_INTERFACE}/g" "${HOSTAPD_CUSTOM_FILE}" sed -i "s/AUTOHOTSPOT_PASSWORD/${AUTOHOTSPOT_PASSWORD}/g" "${HOSTAPD_CUSTOM_FILE}" sed -i "s/WIFI_REGION/${WIFI_REGION}/g" "${HOSTAPD_CUSTOM_FILE}" - sudo cp "${HOSTAPD_CUSTOM_FILE}" "${HOSTAPD_CONF_FILE}" + sudo cp "${HOSTAPD_CUSTOM_FILE}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" - sudo sed -i "s@^#DAEMON_CONF=.*@DAEMON_CONF=\"${HOSTAPD_CONF_FILE}\"@g" /etc/default/hostapd + sudo sed -i "s@^#DAEMON_CONF=.*@DAEMON_CONF=\"${AUTOHOTSPOT_HOSTAPD_CONF_FILE}\"@g" "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" } _configure_dnsmasq() { - sudo tee -a /etc/dnsmasq.conf <<-EOF + sudo tee -a "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" <<-EOF #AutoHotspot Config #stop DNSmasq from using resolv.conf no-resolv @@ -42,7 +62,7 @@ EOF _other_configuration() { sudo mv /etc/network/interfaces /etc/network/interfaces.bak sudo touch /etc/network/interfaces - echo nohook wpa_supplicant | sudo tee -a /etc/dhcpcd.conf + echo nohook wpa_supplicant | sudo tee -a "${AUTOHOTSPOT_DHCPD_CONF_FILE}" } _install_service_and_timer() { @@ -52,23 +72,45 @@ _install_service_and_timer() { } _install_autohotspot_script() { - TARGET_PATH="/usr/bin/autohotspot" - sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot "${TARGET_PATH}" - sudo chmod +x "${TARGET_PATH}" + sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot "${AUTOHOTSPOT_TARGET_PATH}" + sudo chmod +x "${AUTOHOTSPOT_TARGET_PATH}" } -setup_autohotspot() { - echo "Install AutoHotspot functionality" | tee /dev/fd/3 - # inspired by - # https://www.raspberryconnect.com/projects/65-raspberrypi-hotspot-accesspoints/158-raspberry-pi-auto-wifi-hotspot-switch-direct-connection - _get_interface +_autohotspot_check() { + print_verify_installation + + verify_apt_packages hostapd dnsmasq iw + + verify_service_enablement hostapd.service disabled + verify_service_enablement dnsmasq.service disabled + verify_service_enablement autohotspot.service enabled + + verify_files_exists "/etc/cron.d/autohotspot" + verify_files_exists "${AUTOHOTSPOT_TARGET_PATH}" + + verify_file_contains_string "${WIFI_INTERFACE}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "${AUTOHOTSPOT_PASSWORD}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "${WIFI_REGION}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + + verify_file_contains_string "${WIFI_INTERFACE}" "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + verify_file_contains_string "nohook wpa_supplicant" "${AUTOHOTSPOT_DHCPD_CONF_FILE}" +} + +_run_setup_autohotspot() { _install_packages + _get_interface _configure_hostapd _configure_dnsmasq _other_configuration _install_autohotspot_script _install_service_and_timer + _autohotspot_check +} - echo "DONE: setup_autohotspot" +setup_autohotspot() { + if [ "$ENABLE_AUTOHOTSPOT" == true ] ; then + run_with_log_frame _run_setup_autohotspot "Install AutoHotspot" + fi } diff --git a/installation/routines/setup_git.sh b/installation/routines/setup_git.sh index 740d43ae3..613062f43 100644 --- a/installation/routines/setup_git.sh +++ b/installation/routines/setup_git.sh @@ -2,7 +2,7 @@ GIT_ABORT_MSG="Aborting dir to git repo conversion. Your directory content is untouched, you simply cannot use git for updating / developing" _git_install_os_dependencies() { - echo "Install Git dependencies" + echo " Install Git dependencies" sudo apt-get -y update; sudo apt-get -y install \ git \ --no-install-recommends \ @@ -30,6 +30,7 @@ _git_convert_tardir_git_repo() { # We simply get everything from the beginning of future 3 development but excluding Version 2.X if [[ $GIT_USE_SSH == true ]]; then git remote add origin "git@github.com:${GIT_USER}/${GIT_REPO_NAME}.git" + echo "" echo "*** Git fetch (SSH) *******************************" # Prevent: The authenticity of host 'github.com (140.82.121.4)' can't be established. # Do only for this one command, so we do not disable the checks forever @@ -43,6 +44,7 @@ _git_convert_tardir_git_repo() { echo "* Defaulting to HTTPS protocol. You can change back to SSH later with" echo "* git remote set-url origin git@github.com:${GIT_USER}/${GIT_REPO_NAME}.git" echo "* git remote set-url upstream git@github.com:${GIT_UPSTREAM_USER}/${GIT_REPO_NAME}.git" + echo "" git remote remove origin GIT_USE_SSH=false else @@ -58,7 +60,8 @@ _git_convert_tardir_git_repo() { if [[ "$GIT_USER" != "$GIT_UPSTREAM_USER" ]]; then git remote add upstream "https://github.com/${GIT_UPSTREAM_USER}/${GIT_REPO_NAME}.git" fi - echo "*** Git fetch (HTTPS) *****************************" + echo "" + echo "*** Git fetch (HTTPS) *****************************" if ! git fetch origin --set-upstream --shallow-since=2021-04-21 --tags "${GIT_BRANCH}"; then echo "Error: Could not fetch repository!" echo -e "$GIT_ABORT_MSG" @@ -66,6 +69,7 @@ _git_convert_tardir_git_repo() { fi fi HASH_BRANCH=$(git rev-parse FETCH_HEAD) || { echo -e "$GIT_ABORT_MSG"; return; } + echo "" echo "*** FETCH_HEAD ($GIT_BRANCH) = $HASH_BRANCH" git add . @@ -113,12 +117,14 @@ _git_convert_tardir_git_repo() { # Provide some status outputs to the user if [[ "${HASH_BRANCH}" != "${HASH_HEAD}" ]]; then + echo "" echo "*** IMPORTANT NOTICE *******************************" echo "* Your requested branch has moved on while you were installing." - echo "* Don't worry! We will stay within the the exact download version!" + echo "* Don't worry! We will stay within the exact download version!" echo "* But we set up the git repo to be ready for updating." echo "* To start updating (observe updating guidelines!), do:" echo "* $ git pull origin $GIT_BRANCH" + echo "" fi echo "*** Git remotes ************************************" @@ -137,12 +143,20 @@ _git_convert_tardir_git_repo() { unset HASH_BRANCH } -init_git_repo_from_tardir() { - echo "Install Git & init repository" | tee /dev/fd/3 +_git_repo_check() { + print_verify_installation + + verify_apt_packages git + verify_dirs_chmod_chown 755 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${INSTALLATION_PATH}/.git" +} - cd "${INSTALLATION_PATH}" || exit_on_error - _git_install_os_dependencies - _git_convert_tardir_git_repo +_run_init_git_repo_from_tardir() { + cd "${INSTALLATION_PATH}" || exit_on_error + _git_install_os_dependencies + _git_convert_tardir_git_repo + _git_repo_check +} - echo "DONE: init_git_repo_from_tardir" +init_git_repo_from_tardir() { + run_with_log_frame _run_init_git_repo_from_tardir "Install Git & init repository" } diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index e6dfa6d8f..3daa53081 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -9,6 +9,9 @@ GD_ID_COMPILED_PYZMQ_ARMV6="1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n" # https://drive.g ZMQ_TMP_DIR="libzmq" ZMQ_PREFIX="/usr/local" +JUKEBOX_PULSE_CONFIG="${HOME_PATH}"/.config/pulse/default.pa +JUKEBOX_SERVICE_NAME="${SYSTEMD_USR_PATH}/jukebox-daemon.service" + _show_slow_hardware_message() { echo " -------------------------------------------------------------------- | Your hardware is a little slower so this step will take a while. | @@ -19,14 +22,11 @@ echo " -------------------------------------------------------------------- # Functions _jukebox_core_install_os_dependencies() { - echo " Install Jukebox OS dependencies" + echo " Install Jukebox OS dependencies" | tee /dev/fd/3 + + local apt_packages=$(get_args_from_file "${INSTALLATION_PATH}/packages-core.txt") sudo apt-get -y update && sudo apt-get -y install \ - at \ - alsa-utils \ - python3 python3-venv python3-dev \ - espeak ffmpeg mpg123 \ - pulseaudio pulseaudio-module-bluetooth pulseaudio-utils caps \ - libasound2-dev \ + $apt_packages \ --no-install-recommends \ --allow-downgrades \ --allow-remove-essential \ @@ -34,11 +34,10 @@ _jukebox_core_install_os_dependencies() { } _jukebox_core_install_python_requirements() { - echo " Install Python requirements" + echo " Install Python requirements" | tee /dev/fd/3 cd "${INSTALLATION_PATH}" || exit_on_error - VIRTUAL_ENV="${INSTALLATION_PATH}/.venv" python3 -m venv $VIRTUAL_ENV source "$VIRTUAL_ENV/bin/activate" @@ -47,9 +46,9 @@ _jukebox_core_install_python_requirements() { } _jukebox_core_configure_pulseaudio() { - echo "Copy PulseAudio configuration" - mkdir -p ~/.config/pulse - cp -f "${INSTALLATION_PATH}/resources/default-settings/pulseaudio.default.pa" ~/.config/pulse/default.pa + echo " Copy PulseAudio configuration" | tee /dev/fd/3 + mkdir -p $(dirname "$JUKEBOX_PULSE_CONFIG") + cp -f "${INSTALLATION_PATH}/resources/default-settings/pulseaudio.default.pa" "${JUKEBOX_PULSE_CONFIG}" } _jukebox_core_build_libzmq_with_drafts() { @@ -87,7 +86,7 @@ _jukebox_core_build_and_install_pyzmq() { # Sources: # https://pyzmq.readthedocs.io/en/latest/howto/draft.html # https://github.com/MonsieurV/ZeroMQ-RPi/blob/master/README.md - echo " Build and install pyzmq with WebSockets Support" + echo " Build and install pyzmq with WebSockets Support" | tee /dev/fd/3 if ! pip list | grep -F pyzmq >> /dev/null; then # Download pre-compiled libzmq from Google Drive because RPi has trouble compiling it @@ -112,37 +111,60 @@ _jukebox_core_build_and_install_pyzmq() { ZMQ_PREFIX="${ZMQ_PREFIX}" ZMQ_DRAFT_API=1 \ pip install --no-cache-dir --no-binary "pyzmq" --pre pyzmq else - echo " Skipping. pyzmq already installed" + echo " Skipping. pyzmq already installed" | tee /dev/fd/3 fi } _jukebox_core_install_settings() { - echo " Register Jukebox settings" + echo " Register Jukebox settings" | tee /dev/fd/3 cp -f "${INSTALLATION_PATH}/resources/default-settings/jukebox.default.yaml" "${SETTINGS_PATH}/jukebox.yaml" cp -f "${INSTALLATION_PATH}/resources/default-settings/logger.default.yaml" "${SETTINGS_PATH}/logger.yaml" } _jukebox_core_register_as_service() { - echo " Register Jukebox Core user service" + echo " Register Jukebox Core user service" | tee /dev/fd/3 - local jukebox_service="${SYSTEMD_USR_PATH}/jukebox-daemon.service" - sudo cp -f "${INSTALLATION_PATH}/resources/default-services/jukebox-daemon.service" "${jukebox_service}" - sudo sed -i "s|%%INSTALLATION_PATH%%|${INSTALLATION_PATH}|g" "${jukebox_service}" - sudo chmod 644 "${jukebox_service}" + sudo cp -f "${INSTALLATION_PATH}/resources/default-services/jukebox-daemon.service" "${JUKEBOX_SERVICE_NAME}" + sudo sed -i "s|%%INSTALLATION_PATH%%|${INSTALLATION_PATH}|g" "${JUKEBOX_SERVICE_NAME}" + sudo chmod 644 "${JUKEBOX_SERVICE_NAME}" systemctl --user daemon-reload systemctl --user enable jukebox-daemon.service } -setup_jukebox_core() { - echo "Install Jukebox Core" | tee /dev/fd/3 +_jukebox_core_check() { + print_verify_installation + + local apt_packages=$(get_args_from_file "${INSTALLATION_PATH}/packages-core.txt") + verify_apt_packages $apt_packages + + verify_dirs_exists "${VIRTUAL_ENV}" + + local pip_modules=$(get_args_from_file "${INSTALLATION_PATH}/requirements.txt") + verify_pip_modules pyzmq $pip_modules + + verify_files_chmod_chown 644 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${JUKEBOX_PULSE_CONFIG}" - _jukebox_core_install_os_dependencies - _jukebox_core_install_python_requirements - _jukebox_core_configure_pulseaudio - _jukebox_core_build_and_install_pyzmq - _jukebox_core_install_settings - _jukebox_core_register_as_service + verify_files_chmod_chown 644 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${SETTINGS_PATH}/jukebox.yaml" + verify_files_chmod_chown 644 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${SETTINGS_PATH}/logger.yaml" - echo "DONE: setup_jukebox_core" + verify_files_chmod_chown 644 root root "${SYSTEMD_USR_PATH}/jukebox-daemon.service" + + verify_file_contains_string "${INSTALLATION_PATH}" "${JUKEBOX_SERVICE_NAME}" + + verify_service_enablement jukebox-daemon.service enabled --user +} + +_run_setup_jukebox_core() { + _jukebox_core_install_os_dependencies + _jukebox_core_install_python_requirements + _jukebox_core_configure_pulseaudio + _jukebox_core_build_and_install_pyzmq + _jukebox_core_install_settings + _jukebox_core_register_as_service + _jukebox_core_check +} + +setup_jukebox_core() { + run_with_log_frame _run_setup_jukebox_core "Install Jukebox Core" } diff --git a/installation/routines/setup_jukebox_webapp.sh b/installation/routines/setup_jukebox_webapp.sh index 54be3119c..df58188fb 100644 --- a/installation/routines/setup_jukebox_webapp.sh +++ b/installation/routines/setup_jukebox_webapp.sh @@ -2,6 +2,7 @@ # Constants GD_ID_COMPILED_WEBAPP="1um-smyfsVPzVZn18hhwuFt97XR3PjAbB" # https://drive.google.com/file/d/1um-smyfsVPzVZn18hhwuFt97XR3PjAbB/view?usp=sharing +WEBAPP_NGINX_SITE_DEFAULT_CONF="/etc/nginx/sites-available/default" # For ARMv7+ NODE_MAJOR=20 @@ -39,14 +40,13 @@ _jukebox_webapp_install_node() { sudo apt-get update sudo apt-get install -y nodejs fi - fi } # TODO: Avoid building the app locally # Instead implement a Github Action that prebuilds on commititung a git tag _jukebox_webapp_build() { - echo " Building web application" + echo " Building web application" | tee /dev/fd/3 cd "${INSTALLATION_PATH}/src/webapp" || exit_on_error npm ci --prefer-offline --no-audit --production rm -rf build @@ -70,30 +70,47 @@ _jukebox_webapp_register_as_system_service_with_nginx() { sudo apt-get -y purge apache2 sudo apt-get -y install nginx - sudo service nginx start - - sudo mv -f /etc/nginx/sites-available/default /etc/nginx/sites-available/default.orig - sudo cp -f "${INSTALLATION_PATH}/resources/default-settings/nginx.default" /etc/nginx/sites-available/default + sudo mv -f "${WEBAPP_NGINX_SITE_DEFAULT_CONF}" "${WEBAPP_NGINX_SITE_DEFAULT_CONF}.orig" + sudo cp -f "${INSTALLATION_PATH}/resources/default-settings/nginx.default" "${WEBAPP_NGINX_SITE_DEFAULT_CONF}" # make sure nginx can access the home directory of the user - sudo chmod o+x /home/pi + sudo chmod o+x "${HOME_PATH}" - sudo service nginx restart + sudo systemctl restart nginx.service } -setup_jukebox_webapp() { - echo "Install web application" | tee /dev/fd/3 +_jukebox_webapp_check() { + print_verify_installation - if [[ $ENABLE_WEBAPP_PROD_DOWNLOAD == true || $ENABLE_WEBAPP_PROD_DOWNLOAD == release-only ]] ; then - _jukebox_webapp_download - fi - if [[ $ENABLE_INSTALL_NODE == true ]] ; then - _jukebox_webapp_install_node - # Local Web App build during installation does not work at the moment - # Needs to be done after reboot! There will be a message at the end of the installation process - # _jukebox_webapp_build - fi - _jukebox_webapp_register_as_system_service_with_nginx + if [[ $ENABLE_WEBAPP_PROD_DOWNLOAD == true || $ENABLE_WEBAPP_PROD_DOWNLOAD == release-only ]] ; then + verify_dirs_exists "${INSTALLATION_PATH}/src/webapp/build" + fi + if [[ $ENABLE_INSTALL_NODE == true ]] ; then + verify_apt_packages nodejs + fi + + verify_apt_packages nginx + verify_files_exists "${WEBAPP_NGINX_SITE_DEFAULT_CONF}" - echo "DONE: setup_jukebox_webapp" + verify_service_enablement nginx.service enabled +} + +_run_setup_jukebox_webapp() { + if [[ $ENABLE_WEBAPP_PROD_DOWNLOAD == true || $ENABLE_WEBAPP_PROD_DOWNLOAD == release-only ]] ; then + _jukebox_webapp_download + fi + if [[ $ENABLE_INSTALL_NODE == true ]] ; then + _jukebox_webapp_install_node + # Local Web App build during installation does not work at the moment + # Needs to be done after reboot! There will be a message at the end of the installation process + # _jukebox_webapp_build + fi + _jukebox_webapp_register_as_system_service_with_nginx + _jukebox_webapp_check +} + +setup_jukebox_webapp() { + if [ "$ENABLE_WEBAPP" == true ] ; then + run_with_log_frame _run_setup_jukebox_webapp "Install web application" + fi } diff --git a/installation/routines/setup_kiosk_mode.sh b/installation/routines/setup_kiosk_mode.sh index b2857b624..f8d07971c 100644 --- a/installation/routines/setup_kiosk_mode.sh +++ b/installation/routines/setup_kiosk_mode.sh @@ -1,6 +1,13 @@ #!/usr/bin/env bash +KIOSK_MODE_CONF_HEADER="## Jukebox Kiosk Mode" +KIOSK_MODE_XINITRC='/etc/xdg/openbox/autostart' +KIOSK_MODE_BASHRC="${HOME_PATH}/.bashrc" +KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK='/etc/chromium-browser/customizations/01-disable-update-check' +KIOSK_MODE_CHROMIUM_FLAG_UPDATE_INTERVAL='--check-for-update-interval=31536000' + _kiosk_mode_install_os_dependencies() { + echo " Install Kiosk Mode dependencies" | tee /dev/fd/3 # Resource: # https://blog.r0b.io/post/minimal-rpi-kiosk/ sudo apt-get -qq -y install --no-install-recommends \ @@ -12,19 +19,20 @@ _kiosk_mode_install_os_dependencies() { } _kiosk_mode_set_autostart() { + echo " Configure Kiosk Mode" | tee /dev/fd/3 local _DISPLAY='$DISPLAY' local _XDG_VTNR='$XDG_VTNR' - cat << EOF >> /home/pi/.bashrc -## Jukebox kiosk autostart + tee -a "${KIOSK_MODE_BASHRC}" <<-EOF + +${KIOSK_MODE_CONF_HEADER} [[ -z $_DISPLAY && $_XDG_VTNR -eq 1 ]] && startx -- -nocursor EOF - local XINITRC='/etc/xdg/openbox/autostart' - cat << EOF | sudo tee -a $XINITRC + sudo tee -a "${KIOSK_MODE_XINITRC}" <<-EOF -## Jukebox Kiosk Mode +${KIOSK_MODE_CONF_HEADER} # Disable any form of screen saver / screen blanking / power management xset s off xset s noblank @@ -46,16 +54,43 @@ EOF _kiosk_mode_update_settings() { # Resource: https://github.com/Thyraz/Sonos-Kids-Controller/blob/d1f061f4662c54ae9b8dc8b545f9c3ba39f670eb/README.md#kiosk-mode-installation - sudo touch /etc/chromium-browser/customizations/01-disable-update-check;echo CHROMIUM_FLAGS=\"\$\{CHROMIUM_FLAGS\} --check-for-update-interval=31536000\" | sudo tee /etc/chromium-browser/customizations/01-disable-update-check + sudo mkdir -p $(dirname "${KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK}") + sudo rm -f "${KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK}" + sudo tee -a "${KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK}" <<-EOF +${KIOSK_MODE_CONF_HEADER} +CHROMIUM_FLAGS=\"\$\{CHROMIUM_FLAGS\} --check-for-update-interval=31536000\" +EOF +} + +_kiosk_mode_check() { + print_verify_installation + + verify_apt_packages xserver-xorg \ + x11-xserver-utils \ + xinit \ + openbox \ + chromium-browser + verify_files_exists "${KIOSK_MODE_BASHRC}" + verify_file_contains_string "${KIOSK_MODE_CONF_HEADER}" "${KIOSK_MODE_BASHRC}" + + verify_files_exists "${KIOSK_MODE_XINITRC}" + verify_file_contains_string "${KIOSK_MODE_CONF_HEADER}" "${KIOSK_MODE_XINITRC}" + + verify_files_exists "${KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK}" + verify_file_contains_string "${KIOSK_MODE_CONF_HEADER}" "${KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK}" } -setup_kiosk_mode() { - echo "Setup Kiosk Mode" | tee /dev/fd/3 +_run_setup_kiosk_mode() { + _kiosk_mode_install_os_dependencies + _kiosk_mode_set_autostart + _kiosk_mode_update_settings + _kiosk_mode_check +} - _kiosk_mode_install_os_dependencies - _kiosk_mode_set_autostart - _kiosk_mode_update_settings - echo "DONE: setup_kiosk_mode" +setup_kiosk_mode() { + if [ "$ENABLE_KIOSK_MODE" == true ] ; then + run_with_log_frame _run_setup_kiosk_mode "Setup Kiosk Mode" + fi } diff --git a/installation/routines/setup_mpd.sh b/installation/routines/setup_mpd.sh index 53b9ac01b..40ffe8aac 100644 --- a/installation/routines/setup_mpd.sh +++ b/installation/routines/setup_mpd.sh @@ -3,13 +3,11 @@ AUDIOFOLDERS_PATH="${SHARED_PATH}/audiofolders" PLAYLISTS_PATH="${SHARED_PATH}/playlists" -# Do not change this directory! It must match MPDs expectation where to find the user configuration -MPD_CONF_PATH="$HOME/.config/mpd/mpd.conf" - _mpd_install_os_dependencies() { + echo " Install MPD OS dependencies" sudo apt-get -y update - echo "Install MPD OS dependencies" - echo "Note: Installing MPD will cause a message: 'Job failed. See journalctl -xe for details'" + + echo "Note: Installing MPD might cause a message: 'Job failed. See journalctl -xe for details'" echo "It can be ignored! It's an artefact of the MPD installation - nothing we can do about it." sudo apt-get -y install \ mpd mpc \ @@ -20,8 +18,15 @@ _mpd_install_os_dependencies() { } _mpd_configure() { + echo " Configure MPD as user local service" | tee /dev/fd/3 + + # Make sure system-wide mpd is disabled + sudo systemctl stop mpd.socket + sudo systemctl stop mpd.service + sudo systemctl disable mpd.socket + sudo systemctl disable mpd.service # MPD will be setup as user process (rather than a system-wide process) - mkdir -p ~/.config/mpd + mkdir -p $(dirname "$MPD_CONF_PATH") cp -f "${INSTALLATION_PATH}/resources/default-settings/mpd.default.conf" "${MPD_CONF_PATH}" @@ -29,48 +34,38 @@ _mpd_configure() { sed -i 's|%%JUKEBOX_AUDIOFOLDERS_PATH%%|'"$AUDIOFOLDERS_PATH"'|' "${MPD_CONF_PATH}" sed -i 's|%%JUKEBOX_PLAYLISTS_PATH%%|'"$PLAYLISTS_PATH"'|' "${MPD_CONF_PATH}" + # Prepare user-service MPD to be started at next boot + systemctl --user daemon-reload + systemctl --user enable mpd.socket + systemctl --user enable mpd.service } -setup_mpd() { - echo "Install MPD" | tee /dev/fd/3 +_mpd_check() { + print_verify_installation - local MPD_EXECUTE_INSTALL=true + verify_apt_packages mpd mpc - if [[ -f ${MPD_CONF_PATH} || -f ${SYSTEMD_USR_PATH}/mpd.service ]]; then - echo "It seems there is a MPD already installed. -Note: It is important that MPD runs as a user service! -Would you like to overwrite your configuration? [Y/n]" 1>&3 - read -r response - case "$response" in - [nN][oO]|[nN]) - MPD_EXECUTE_INSTALL=false - ;; - *) - ;; - esac - fi + verify_files_chmod_chown 755 "${CURRENT_USER}" "${CURRENT_USER_GROUP}" "${MPD_CONF_PATH}" - echo "MPD_EXECUTE_INSTALL=${MPD_EXECUTE_INSTALL}" + verify_file_contains_string "${AUDIOFOLDERS_PATH}" "${MPD_CONF_PATH}" + verify_file_contains_string "${PLAYLISTS_PATH}" "${MPD_CONF_PATH}" - if [[ $MPD_EXECUTE_INSTALL == true ]] ; then + verify_service_enablement mpd.socket disabled + verify_service_enablement mpd.service disabled - # Install/update only if enabled: do not stuff up any existing configuration - _mpd_install_os_dependencies + verify_service_enablement mpd.socket enabled --user + verify_service_enablement mpd.service enabled --user +} - # Make sure system-wide mpd is disabled - echo "Configure MPD as user local service" | tee /dev/fd/3 - sudo systemctl stop mpd.socket - sudo systemctl stop mpd - sudo systemctl disable mpd.socket - sudo systemctl disable mpd +_run_setup_mpd() { + _mpd_install_os_dependencies _mpd_configure - # Prepare user-service MPD to be started at next boot - systemctl --user daemon-reload - systemctl --user enable mpd.socket - systemctl --user enable mpd - # Start MPD now, but not the socket: MPD is already started and we expect a reboot anyway - systemctl --user start mpd - fi - - echo "DONE: setup_mpd" + _mpd_check +} + +setup_mpd() { + # Install/update only if enabled: do not stuff up any existing configuration + if [[ "$SETUP_MPD" == true && $ENABLE_MPD_OVERWRITE_INSTALL == true ]] ; then + run_with_log_frame _run_setup_mpd "Install MPD" + fi } diff --git a/installation/routines/setup_rfid_reader.sh b/installation/routines/setup_rfid_reader.sh index 4ae693076..b5e8b4bbc 100644 --- a/installation/routines/setup_rfid_reader.sh +++ b/installation/routines/setup_rfid_reader.sh @@ -1,9 +1,11 @@ #!/usr/bin/env bash -setup_rfid_reader() { - echo "Install RFID Reader" | tee /dev/fd/3 - - python "${INSTALLATION_PATH}/src/jukebox/run_register_rfid_reader.py" | tee /dev/fd/3 +_run_setup_rfid_reader() { + python "${INSTALLATION_PATH}/src/jukebox/run_register_rfid_reader.py" | tee /dev/fd/3 +} - echo "DONE: setup_rfid_reader" +setup_rfid_reader() { + if [ "$ENABLE_RFID_READER" == true ] ; then + run_with_log_frame _run_setup_rfid_reader "Install RFID Reader" + fi } diff --git a/installation/routines/setup_samba.sh b/installation/routines/setup_samba.sh index 0914439b7..4b45b54e1 100644 --- a/installation/routines/setup_samba.sh +++ b/installation/routines/setup_samba.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash +SMB_CONF="/etc/samba/smb.conf" +SMB_CONF_HEADER="## Jukebox Samba Config" + _samba_install_os_dependencies() { - echo "Install Samba Core dependencies" + echo " Install Samba Core dependencies" sudo apt-get -qq -y update; sudo apt-get -qq -y install \ samba samba-common-bin \ --no-install-recommends \ @@ -11,23 +14,22 @@ _samba_install_os_dependencies() { } _samba_set_user() { - local SMB_CONF="/etc/samba/smb.conf" - local SMB_USER="pi" + echo " Configure Samba" | tee /dev/fd/3 local SMB_PASSWD="raspberry" # Samba has not been configured - if grep -q "## Jukebox Samba Config" "$SMB_CONF"; then - echo " Skipping. Already set up!" | tee /dev/fd/3 + if grep -q "$SMB_CONF_HEADER" "$SMB_CONF"; then + echo " Skipping. Already set up!" | tee /dev/fd/3 else # Create Samba user - (echo "${SMB_PASSWD}"; echo "${SMB_PASSWD}") | sudo smbpasswd -s -a $SMB_USER + (echo "${SMB_PASSWD}"; echo "${SMB_PASSWD}") | sudo smbpasswd -s -a "${CURRENT_USER}" sudo chown root:root $SMB_CONF sudo chmod 777 $SMB_CONF # Create Samba Mount Points sudo cat << EOF >> $SMB_CONF -## Jukebox Samba Config +${SMB_CONF_HEADER} [phoniebox] comment= Pi Jukebox path=${SHARED_PATH} @@ -43,13 +45,31 @@ EOF fi } -setup_samba() { - echo "Install Samba and configure user" | tee /dev/fd/3 +_samba_check() { + print_verify_installation + + verify_apt_packages samba samba-common-bin - # Skip interactive Samba WINS config dialog - echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections - _samba_install_os_dependencies - _samba_set_user + verify_files_chmod_chown 644 root root "${SMB_CONF}" - echo "DONE: setup_samba" + verify_file_contains_string "${SMB_CONF_HEADER}" "${SMB_CONF}" + verify_file_contains_string "${SHARED_PATH}" "${SMB_CONF}" + + if ! (sudo pdbedit -L | grep -qw "^${CURRENT_USER}") ; then + exit_on_error "ERROR: samba user not found" + fi +} + +_run_setup_samba() { + # Skip interactive Samba WINS config dialog + echo "samba-common samba-common/dhcp boolean false" | sudo debconf-set-selections + _samba_install_os_dependencies + _samba_set_user + _samba_check +} + +setup_samba() { + if [ "$ENABLE_SAMBA" == true ] ; then + run_with_log_frame _run_setup_samba "Install Samba" + fi } diff --git a/installation/routines/update_raspi_os.sh b/installation/routines/update_raspi_os.sh index b7c356454..f38e975ed 100644 --- a/installation/routines/update_raspi_os.sh +++ b/installation/routines/update_raspi_os.sh @@ -1,9 +1,14 @@ #!/usr/bin/env bash -update_raspi_os() { - echo "Updating Raspberry Pi OS" | tee /dev/fd/3 - - sudo apt-get -qq -y update; sudo apt-get -qq -y full-upgrade; sudo apt-get -qq -y autoremove +_run_update_raspi_os() { + sudo apt-get -qq -y update && sudo apt-get -qq -y full-upgrade || exit_on_error "Failed to Update Raspberry Pi OS" + if [ "$CI_RUNNING" != "true" ]; then + sudo apt-get -qq -y autoremove + fi +} - echo "DONE: update_raspi_os" +update_raspi_os() { + if [ "$UPDATE_RASPI_OS" == true ] ; then + run_with_log_frame _run_update_raspi_os "Updating Raspberry Pi OS" + fi } diff --git a/packages-core.txt b/packages-core.txt new file mode 100644 index 000000000..b2f6779a2 --- /dev/null +++ b/packages-core.txt @@ -0,0 +1,17 @@ +# Define packages for apt-get. These can be installed with +# 'sed 's/#.*//g' packages.txt | xargs sudo apt-get install' + +at +alsa-utils +caps +espeak +ffmpeg +libasound2-dev +mpg123 +pulseaudio +pulseaudio-module-bluetooth +pulseaudio-utils +python3 +python3-venv +python3-dev +rsync diff --git a/requirements.txt b/requirements.txt index f9f452799..0f8c8c86d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ wheel evdev pyalsaaudio pulsectl -python_mpd2 +python-mpd2 ruamel.yaml # For playlistgenerator requests @@ -28,7 +28,6 @@ gpiozero # On regular Linux PCs, Websocket is enabled in the Python package # pyzmq - # Code quality flake8>=4.0.0 pytest diff --git a/src/jukebox/components/rfid/configure/__init__.py b/src/jukebox/components/rfid/configure/__init__.py index 7f9e232f2..0a8ff7aca 100755 --- a/src/jukebox/components/rfid/configure/__init__.py +++ b/src/jukebox/components/rfid/configure/__init__.py @@ -10,6 +10,8 @@ logger = logging.getLogger() +NO_RFID_READER = 'No RFID Reader' + def reader_install_dependencies(reader_path: str, dependency_install: str) -> None: """ @@ -80,6 +82,40 @@ def reader_load_module(reader_name): return reader_module +def _get_reader_descriptions(reader_dirs: list[str]) -> dict[str, tuple[str, str]]: + # Try to load the description modules from all valid directories (as this has no dependencies) + # If unavailable, use placeholder description + reader_descriptions = {} + for reader_type in reader_dirs: + reader_description_module_name = '' + reader_description = '' + if reader_type == NO_RFID_READER: + # Add Option to not add a RFid Reader + reader_description_module_name = reader_type + reader_description = reader_type + else: + reader_description_module_name = f"{reader_type + '/' + reader_type + '.py'}" + try: + reader_description_module = (importlib.import_module('components.rfid.hardware.' + reader_type + + '.description', 'pkg.subpkg')) + reader_description = reader_description_module.DESCRIPTION + except ModuleNotFoundError: + # The developer for this reader simply omitted to provide a description module + # Or there is no valid module in this directory, despite correct naming scheme. + # But this we will only find out later, because we want to be as lenient as possible + # and don't already load and check reader modules the user is + # not selecting (and thus no interested in) + logger.warning(f"No module 'description.py' available for reader subpackage '{reader_type}'") + reader_description = '(No description provided!)' + except AttributeError: + # The module loaded ok, but has no identifier 'DESCRIPTION' + logger.warning(f"Module 'description.py' of reader subpackage '{reader_type}' is missing 'DESCRIPTION'. " + f"Spelling error?") + reader_description = '(No description provided!)' + reader_descriptions[reader_type] = (reader_description, reader_description_module_name) + return reader_descriptions + + def query_user_for_reader(dependency_install='query') -> dict: """ Ask the user to select a RFID reader and prompt for the reader's configuration @@ -115,39 +151,20 @@ def query_user_for_reader(dependency_install='query') -> dict: package_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + '/../hardware') logger.debug(f"Package location: {package_dir}") # For known included readers, specify manual order - included_readers = ['generic_usb', 'rdm6300_serial', 'rc522_spi', 'pn532_i2c_py532', 'fake_reader_gui'] + included_readers = [NO_RFID_READER, 'generic_usb', 'rdm6300_serial', 'rc522_spi', 'pn532_i2c_py532', 'fake_reader_gui'] # Get all local directories (i.e subpackages) that conform to naming/structuring convention (except known readers) # Naming convention: modname/modname.py - reader_dirs = [x for x in os.listdir(package_dir) + additional_readers = [x for x in os.listdir(package_dir) if (os.path.isdir(package_dir + '/' + x) and os.path.exists(package_dir + '/' + x + '/' + x + '.py') and os.path.isfile(package_dir + '/' + x + '/' + x + '.py') and not x.endswith('template_new_reader') and x not in included_readers)] - reader_dirs = [*included_readers, *sorted(reader_dirs, key=lambda x: x.casefold())] + reader_dirs = [*included_readers, *sorted(additional_readers, key=lambda x: x.casefold())] + logger.debug(f"reader_dirs = {reader_dirs}") - # Try to load the description modules from all valid directories (as this has no dependencies) - # If unavailable, use placeholder description - reader_description_modules = [] - reader_descriptions = [] - for reader_type in reader_dirs: - try: - reader_description_modules.append(importlib.import_module('components.rfid.hardware.' + reader_type - + '.description', 'pkg.subpkg')) - reader_descriptions.append(reader_description_modules[-1].DESCRIPTION) - except ModuleNotFoundError: - # The developer for this reader simply omitted to provide a description module - # Or there is no valid module in this directory, despite correct naming scheme. But this we will only find out - # later, because we want to be as lenient as possible and don't already load and check reader modules the user is - # not selecting (and thus no interested in) - logger.warning(f"No module 'description.py' available for reader subpackage '{reader_type}'") - reader_descriptions.append('(No description provided!)') - except AttributeError: - # The module loaded ok, but has no identifier 'DESCRIPTION' - logger.warning(f"Module 'description.py' of reader subpackage '{reader_type}' is missing 'DESCRIPTION'. " - f"Spelling error?") - reader_descriptions.append('(No description provided!)') + reader_descriptions = _get_reader_descriptions(reader_dirs) # Prepare the configuration collector with the base values config_dict = {'rfid': {'readers': {}}} @@ -157,14 +174,21 @@ def query_user_for_reader(dependency_install='query') -> dict: while True: # List all modules and query user print("Choose Reader Module from list:\n") - for idx, (des, mod) in enumerate(zip(reader_descriptions, reader_dirs)): + for idx, (des, mod) in enumerate(reader_descriptions.values()): print(f" {Colors.lightgreen}{idx:2d}{Colors.reset}: {Colors.lightcyan}{Colors.bold}{des:40s}{Colors.reset} " - f"(Module: {mod + '/' + mod + '.py'})") + f"(Module: {mod})") print("") reader_id = pyil.input_int("Reader module number?", min=0, max=len(reader_descriptions) - 1, prompt_color=Colors.lightgreen, prompt_hint=True) + # The (short) name of the selected reader module, which is identical to the directory name - reader_select_name.append(reader_dirs[reader_id]) + reader_selected = list(reader_descriptions.keys())[reader_id] + print(f"Reader selected: '{reader_selected}'") + if reader_selected == NO_RFID_READER: + logger.debug(f"Entry '{NO_RFID_READER}' selected. skip") + break + + reader_select_name.append(reader_selected) # If this reader has not been selected before, auto install dependencies if reader_select_name[-1] not in reader_select_name[:-1]: diff --git a/src/jukebox/components/rfid/reader/__init__.py b/src/jukebox/components/rfid/reader/__init__.py index 9245a127a..db0ccb1da 100644 --- a/src/jukebox/components/rfid/reader/__init__.py +++ b/src/jukebox/components/rfid/reader/__init__.py @@ -239,14 +239,22 @@ def run(self): # noqa: C901 @plugs.finalize def finalize(): - jukebox.cfghandler.load_yaml(cfg_rfid, cfg_main.getn('rfid', 'reader_config')) - - # Load all the required modules - # Start a ReaderRunner-Thread for each Reader - for reader_cfg_key in cfg_rfid['rfid']['readers'].keys(): - _READERS[reader_cfg_key] = ReaderRunner(reader_cfg_key) - for reader_cfg_key in cfg_rfid['rfid']['readers'].keys(): - _READERS[reader_cfg_key].start() + try: + reader_config_file = cfg_main.getn('rfid', 'reader_config') + jukebox.cfghandler.load_yaml(cfg_rfid, reader_config_file) + except FileNotFoundError: + cfg_rfid.config_dict({'rfid': {'readers': {}}}) + log.warning(f"rfid reader database file not found. Creating empty database: '{reader_config_file}'") + # Save the empty rfid reader database, to make sure we can create the file and have access to it + cfg_rfid.save(only_if_changed=False) + + if 'rfid' in cfg_rfid and 'readers' in cfg_rfid['rfid']: + # Load all the required modules + # Start a ReaderRunner-Thread for each Reader + for reader_cfg_key in cfg_rfid['rfid']['readers'].keys(): + _READERS[reader_cfg_key] = ReaderRunner(reader_cfg_key) + for reader_cfg_key in cfg_rfid['rfid']['readers'].keys(): + _READERS[reader_cfg_key].start() @plugs.atexit From dbfd58ab7beff1907317534ecc6ed77ae6b6fc54 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Sun, 3 Dec 2023 13:18:03 +0100 Subject: [PATCH 02/28] Bump libzmq version to 4.3.5 for armv7 --- installation/routines/setup_jukebox_core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index e6dfa6d8f..272901de1 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Constants -GD_ID_COMPILED_LIBZMQ_ARMV7="1KP6BqLF-i2dCUsHhOUpOwwuOmKsB5GKY" # ARMv7: https://drive.google.com/file/d/1KP6BqLF-i2dCUsHhOUpOwwuOmKsB5GKY/view?usp=sharing +GD_ID_COMPILED_LIBZMQ_ARMV7="1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F" # ARMv7: https://drive.google.com/file/d/1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F/view?usp=sharing GD_ID_COMPILED_LIBZMQ_ARMV6="1iygOm-G1cg_3YERuVRT6FhGBE34ZkwgV" # ARMv6: https://drive.google.com/file/d/1iygOm-G1cg_3YERuVRT6FhGBE34ZkwgV/view?usp=sharing GD_ID_COMPILED_PYZMQ_ARMV7="" GD_ID_COMPILED_PYZMQ_ARMV6="1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n" # https://drive.google.com/file/d/1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n/view?usp=sharing From f1558a2f2cc9d4c9d5adc6d9bf6956c0e72a51bf Mon Sep 17 00:00:00 2001 From: s-martin Date: Mon, 4 Dec 2023 08:20:55 +0100 Subject: [PATCH 03/28] Add badges to future3 (#2133) * Add badges to future3 * Add python action badge --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3731c7e06..1ada3e8b3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # RFID Jukebox Version 3 (aka future3) +![GitHub last commit (branch)](https://img.shields.io/github/last-commit/MiczFlor/RPi-Jukebox-RFID/future3/develop) + +[![Test Install Scripts Debian v3](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian_v3.yml/badge.svg?branch=future3%2Fdevelop)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian_v3.yml) [![Python + Docs Checks and Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage_future3.yml/badge.svg?branch=future3%2Fdevelop)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage_future3.yml) + +[![Matrix chat](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#phoniebox_community:gitter.im) + ## What is this? The exiting, new **Version 3** of the RPi Jukebox RFID. A complete re-write of the Jukebox. From cf5aa6c92de88396d00a576f6497a6944138c1ab Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Mon, 4 Dec 2023 23:21:24 +0100 Subject: [PATCH 04/28] allow custom username (#2132) * removed hardcoded references to user "pi" * removed check userNotPi * change testuser in workflow and container * updated docs * updated comments and docs * updated comments and docs * remove extra home_path check * changes testuser name and group --- .github/ISSUE_TEMPLATE/bug_template.md | 2 +- .../test_docker_debian_codename_sub_v3.yml | 14 ++++++---- CONTRIBUTING.md | 6 ++-- ci/ci-debian.Dockerfile | 18 ++---------- ci/installation/run_install_user_not_pi.sh | 25 ----------------- documentation/builders/autohotspot.md | 2 +- documentation/builders/installation.md | 4 +-- documentation/builders/system.md | 7 ++--- documentation/developers/known-issues.md | 4 +-- installation/install-jukebox.sh | 28 ------------------- installation/routines/setup_autohotspot.sh | 5 +++- installation/routines/setup_jukebox_webapp.sh | 1 + resources/autohotspot/autohotspot.timer | 4 +-- .../default-settings/jukebox.default.yaml | 2 +- resources/default-settings/nginx.default | 8 +++--- src/webapp/src/config.js | 4 +-- 16 files changed, 36 insertions(+), 98 deletions(-) delete mode 100644 ci/installation/run_install_user_not_pi.sh diff --git a/.github/ISSUE_TEMPLATE/bug_template.md b/.github/ISSUE_TEMPLATE/bug_template.md index 1be942778..508cf50b9 100644 --- a/.github/ISSUE_TEMPLATE/bug_template.md +++ b/.github/ISSUE_TEMPLATE/bug_template.md @@ -50,7 +50,7 @@ Otherwise the output of `cat /etc/os-release` i.e. `master` the following command will help with that -`cd /home/pi/RPi-Jukebox-RFID/ && git status | head -2` +`cd ~/RPi-Jukebox-RFID/ && git status | head -2` --> ### Installscript diff --git a/.github/workflows/test_docker_debian_codename_sub_v3.yml b/.github/workflows/test_docker_debian_codename_sub_v3.yml index 54abd142a..97924c4bf 100644 --- a/.github/workflows/test_docker_debian_codename_sub_v3.yml +++ b/.github/workflows/test_docker_debian_codename_sub_v3.yml @@ -27,6 +27,10 @@ on: type: string default: ubuntu-latest +env: + TEST_USER_NAME: testuser + TEST_USER_GROUP: testusergroup + # let only one instance run the test so cache is not corrupted. # cancel already running instances as only the last run will be relevant concurrency: @@ -101,6 +105,8 @@ jobs: cache-to: type=gha,mode=max,scope=${{ steps.vars.outputs.cache_scope }} build-args: | DEBIAN_CODENAME=${{ inputs.debian_codename }} + USER_NAME=${{ env.TEST_USER_NAME }} + USER_GROUP=${{ env.TEST_USER_GROUP }} GIT_BRANCH=${{ github.head_ref || github.ref_name }} GIT_USER=${{ github.event.pull_request.head.user.login || github.repository_owner }} @@ -137,11 +143,7 @@ jobs: strategy: fail-fast: false matrix: - username: ['pi'] test_script: ['run_install_common.sh', 'run_install_faststartup.sh', 'run_install_webapp_local.sh', 'run_install_webapp_download.sh'] - include: - - username: hans - test_script: run_install_user_not_pi.sh steps: - name: Set up QEMU @@ -160,11 +162,11 @@ jobs: docker load --input ${{ needs.build.outputs.image_file_name }} # Run test - - name: Run Test ${{ inputs.debian_codename }}-${{ matrix.username }}-${{ matrix.test_script }} + - name: Run Test ${{ inputs.debian_codename }}-${{ env.TEST_USER_NAME }}-${{ matrix.test_script }} uses: tj-actions/docker-run@v2 with: image: ${{ needs.build.outputs.image_tag_name }} - options: --platform ${{ inputs.platform }} --user ${{ matrix.username }} --init + options: --platform ${{ inputs.platform }} --user ${{ env.TEST_USER_NAME }} --init name: ${{ matrix.test_script }} args: | ./${{ matrix.test_script }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3bc03705..dbf12f84d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,7 @@ For bug fixes and improvements just open an issue or PR as described below. If y * By default this will get you to the `future3/main` branch. You will move to the `future3/develop` branch, do this: ~~~bash -cd /home/pi/RPi-Jukebox-RFID +cd ~/RPi-Jukebox-RFID git checkout future3/develop git fetch origin git reset --hard origin/future3/develop @@ -122,7 +122,7 @@ If you touched *any* Python file (even if only for fixing spelling errors), run It contains out setup file. ~~~bash -cd /home/pi/RPi-Jukebox-RFID +cd ~/RPi-Jukebox-RFID ./run_flake8.sh ~~~ @@ -135,7 +135,7 @@ Tests are very few at the moment, but it cannot hurt to run them. If you have te them. ~~~bash -cd /home/pi/RPi-Jukebox-RFID/ +cd ~/RPi-Jukebox-RFID/ ./run_pytest.sh ~~~ diff --git a/ci/ci-debian.Dockerfile b/ci/ci-debian.Dockerfile index 1a227755a..5228d83d5 100644 --- a/ci/ci-debian.Dockerfile +++ b/ci/ci-debian.Dockerfile @@ -7,7 +7,7 @@ ARG DEBIAN_CODENAME ENV TERM=xterm DEBIAN_FRONTEND=noninteractive ENV CI_RUNNING=true -# create pi configs to test installation +# create RPi configs to test installation RUN touch /boot/config.txt RUN echo "logo.nologo" > /boot/cmdline.txt @@ -40,8 +40,8 @@ RUN echo "--- install packages (1) ---" \ RUN echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections # ------ -# Base Target for setting up the default user. user can be selected with the docker '--user YYY' option -FROM base as user +# Base Target for setting up a test user. user can be selected with the docker '--user YYY' option +FROM base as test-user ARG USER_NAME=pi ARG USER_GROUP=$USER_NAME ARG USER_ID=1000 @@ -56,18 +56,6 @@ RUN groupadd --gid 1000 $USER_GROUP \ ENV XDG_RUNTIME_DIR=/run/user/$USER_ID DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$USER_ID/bus # ------ - -# Target for setting up an alternativ user 'hans:wurst'. user can be selected with the docker '--user YYY' option -FROM user as test-user - -RUN export USER_ALT=hans \ - && export USER_ALT_GROUP=wurst \ - && groupadd --gid 1001 $USER_ALT_GROUP \ - && useradd -u 1001 -g $USER_ALT_GROUP -G sudo,$TEST_USER_GROUP -d /home/$USER_ALT -m -s /bin/bash -p '$1$iV7TOwOe$6ojkJQXyEA9bHd/SqNLNj0' $USER_ALT \ - && echo "$USER_ALT ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER_ALT -# ------ - - # Target for adding envs and scripts from the repo to test installation FROM test-user as test-code ARG GIT_BRANCH diff --git a/ci/installation/run_install_user_not_pi.sh b/ci/installation/run_install_user_not_pi.sh deleted file mode 100644 index 76a8cd576..000000000 --- a/ci/installation/run_install_user_not_pi.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# Install Phoniebox and test it -# Used e.g. for tests on Docker - -# Objective: Test installation with script using a simple configuration - -SOURCE="${BASH_SOURCE[0]}" -SCRIPT_DIR="$(dirname "$SOURCE")" -LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" -LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" - -# Run installation (in interactive mode) -# - - Installation must abort early - -"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" -INSTALLATION_EXITCODE=$? - -# only count abortion due to "not user pi" as success -if [ "${INSTALLATION_EXITCODE}" -eq 2 ]; then - INSTALLATION_EXITCODE=0 -else - INSTALLATION_EXITCODE=1 -fi -exit "${INSTALLATION_EXITCODE}" diff --git a/documentation/builders/autohotspot.md b/documentation/builders/autohotspot.md index 7f064cb53..69e6f4d6a 100644 --- a/documentation/builders/autohotspot.md +++ b/documentation/builders/autohotspot.md @@ -28,7 +28,7 @@ After connecting to the `Phoniebox_Hotspot` you are able to connect via ssh to your Jukebox ``` bash -ssh pi@10.0.0.5 +ssh @10.0.0.5 ``` ## Changing basic configuration of the hotspot diff --git a/documentation/builders/installation.md b/documentation/builders/installation.md index d0befca29..fadc77aac 100644 --- a/documentation/builders/installation.md +++ b/documentation/builders/installation.md @@ -16,7 +16,7 @@ Before you can install the Phoniebox software, you need to prepare your Raspberr * Click `Edit Settings` * Switch to the `General` tab * Provide a hostname. (When on Mac, you will be able to use it to connect via SSH) - * Username currently MUST be `pi`. Other usernames are currently not supported. + * Username * Password * Wifi * Set locale settings @@ -72,7 +72,7 @@ You will need a terminal, like PuTTY for Windows or the Terminal app for Mac to 7. Eject your SD card and insert it into your Raspberry Pi. 8. Start your Raspberry Pi by attaching a power supply. -9. Login into your Raspberry Pi, username is `pi` and password is `raspberry`. +9. Login into your Raspberry Pi If `raspberrypi.local` does not work, find out your Raspberry Pi's IP address from your router. diff --git a/documentation/builders/system.md b/documentation/builders/system.md index 5b1ce5c0c..873d489f6 100644 --- a/documentation/builders/system.md +++ b/documentation/builders/system.md @@ -10,9 +10,8 @@ The system consists of 4. [Web UI](system.md#web-ui) which is served through an Nginx web server 5. A set of [Configuration Tools](../developers/coreapps.md#configuration-tools) and a set of [Developer Tools](../developers/coreapps.md#developer-tools) -.. note:: The default install puts everything into the folder `/home/pi/RPi-Jukebox-RFID`. - Another folder might work, but is certainly not tested. Things are installed for the default user `pi`. Again, - another user might work, but is not tested. +.. note:: The default install puts everything into the users home folder `~/RPi-Jukebox-RFID`. + Another folder might work, but is certainly not tested. ## Music Player Daemon (MPD) @@ -102,7 +101,7 @@ Starting and stopping the service can be useful for debugging or configuration c The Web UI is served using nginx. Nginx runs as a system service. The home directory is localed at ``` -/home/pi/RPi-Jukebox-RFID/src/webapp/build +~/RPi-Jukebox-RFID/src/webapp/build ``` The Nginx configuration is located at diff --git a/documentation/developers/known-issues.md b/documentation/developers/known-issues.md index 598ecd791..2ec52c3c2 100644 --- a/documentation/developers/known-issues.md +++ b/documentation/developers/known-issues.md @@ -7,7 +7,7 @@ browser for now. ## Configuration -In `jukebox.yaml` (and all other config files): do not use relative paths with `~/some/dir`. -Always use entire explicit path, e.g. `/home/pi/some/dir`. +In `jukebox.yaml` (and all other config files): +Always use relative path from settingsfile `../../`, but do not use relative paths with `~/`. **Sole** exception is in `playermpd.mpd_conf`. diff --git a/installation/install-jukebox.sh b/installation/install-jukebox.sh index b72dd32ff..90f78800f 100755 --- a/installation/install-jukebox.sh +++ b/installation/install-jukebox.sh @@ -47,33 +47,6 @@ _check_os_type() { fi } -# currently the user 'pi' is mandatory -# https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/1785 -_check_user() { - if [ "${CURRENT_USER}" != "pi" ]; then - echo - echo "ERROR: User must be 'pi'!" - echo " Other usernames are currently not supported." - echo " Please check the wiki for further information" - exit 2 - fi - - if [ "${HOME_PATH}" != "/home/pi" ]; then - echo - echo "ERROR: HomeDir must be '/home/pi'!" - echo " Other usernames are currently not supported." - echo " Please check the wiki for further information" - exit 2 - fi - - if [ ! -d "${HOME_PATH}" ]; then - echo - echo "ERROR: HomeDir ${HOME_PATH} does not exist." - echo " Please create it and start again." - exit 2 - fi -} - # Manipulate file descriptor for logging # Behavior: # Write To logfile: @@ -154,7 +127,6 @@ _load_sources() { ### CHECK PREREQUISITE _check_os_type -_check_user ### SETUP LOGGING _setup_logging diff --git a/installation/routines/setup_autohotspot.sh b/installation/routines/setup_autohotspot.sh index a385352dd..cc40b7794 100644 --- a/installation/routines/setup_autohotspot.sh +++ b/installation/routines/setup_autohotspot.sh @@ -68,7 +68,10 @@ _other_configuration() { _install_service_and_timer() { sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot.service /etc/systemd/system/autohotspot.service sudo systemctl enable autohotspot.service - sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot.timer /etc/cron.d/autohotspot + + local cron_autohotspot_file="/etc/cron.d/autohotspot" + sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot.timer "${cron_autohotspot_file}" + sudo sed -i "s|%%USER%%|${CURRENT_USER}|g" "${cron_autohotspot_file}" } _install_autohotspot_script() { diff --git a/installation/routines/setup_jukebox_webapp.sh b/installation/routines/setup_jukebox_webapp.sh index df58188fb..54c573654 100644 --- a/installation/routines/setup_jukebox_webapp.sh +++ b/installation/routines/setup_jukebox_webapp.sh @@ -72,6 +72,7 @@ _jukebox_webapp_register_as_system_service_with_nginx() { sudo mv -f "${WEBAPP_NGINX_SITE_DEFAULT_CONF}" "${WEBAPP_NGINX_SITE_DEFAULT_CONF}.orig" sudo cp -f "${INSTALLATION_PATH}/resources/default-settings/nginx.default" "${WEBAPP_NGINX_SITE_DEFAULT_CONF}" + sudo sed -i "s|%%INSTALLATION_PATH%%|${INSTALLATION_PATH}|g" "${WEBAPP_NGINX_SITE_DEFAULT_CONF}" # make sure nginx can access the home directory of the user sudo chmod o+x "${HOME_PATH}" diff --git a/resources/autohotspot/autohotspot.timer b/resources/autohotspot/autohotspot.timer index a35f15757..eb2acaebe 100644 --- a/resources/autohotspot/autohotspot.timer +++ b/resources/autohotspot/autohotspot.timer @@ -1,3 +1,3 @@ # cron timer for autohotspot -*/5 * * * * pi sudo /usr/bin/autohotspot 2>&1 | logger -t autohotspot -@reboot pi sudo /usr/bin/autohotspot 2>&1 | logger -t autohotspot +*/5 * * * * %%USER%% sudo /usr/bin/autohotspot 2>&1 | logger -t autohotspot +@reboot %%USER%% sudo /usr/bin/autohotspot 2>&1 | logger -t autohotspot diff --git a/resources/default-settings/jukebox.default.yaml b/resources/default-settings/jukebox.default.yaml index 6e565c684..91ada74c6 100644 --- a/resources/default-settings/jukebox.default.yaml +++ b/resources/default-settings/jukebox.default.yaml @@ -1,5 +1,5 @@ # IMPORTANT: -# Do not use paths with '~/some/dir' - always use '/home/pi/some/dir' +# Always use relative path from settingsfile `../../`, but do not use relative paths with `~/`. # Sole (!) exception is in playermpd.mpd_conf system: box_name: Jukebox diff --git a/resources/default-settings/nginx.default b/resources/default-settings/nginx.default index b949beb26..d664f4cdd 100644 --- a/resources/default-settings/nginx.default +++ b/resources/default-settings/nginx.default @@ -2,7 +2,7 @@ server { listen 80 default_server; listen [::]:80 default_server; - root /home/pi/RPi-Jukebox-RFID/src/webapp/build; + root %%INSTALLATION_PATH%%/src/webapp/build; index index.html index.htm; @@ -21,7 +21,7 @@ server { } location /logs { - root /home/pi/RPi-Jukebox-RFID/shared; + root %%INSTALLATION_PATH%%/shared; autoindex on; autoindex_exact_size off; @@ -31,14 +31,14 @@ server { } location @buildwebui { - root /home/pi/RPi-Jukebox-RFID/resources/html; + root %%INSTALLATION_PATH%%/resources/html; try_files /runbuildui.html =404; internal; } error_page 404 = /404.html; location /404.html { - root /home/pi/RPi-Jukebox-RFID/resources/html; + root %%INSTALLATION_PATH%%/resources/html; internal; } } diff --git a/src/webapp/src/config.js b/src/webapp/src/config.js index 4383a7897..35b5a980e 100644 --- a/src/webapp/src/config.js +++ b/src/webapp/src/config.js @@ -17,9 +17,7 @@ const SUBSCRIPTIONS = [ 'volume.level', ]; -// TODO: This is not optimal, we should not know about this path here! -// Let's try to work with relatives paths in the RPC only! -const DEFAULT_AUDIO_DIR = '/home/pi/RPi-Jukebox-RFID/shared/audiofolders'; +const DEFAULT_AUDIO_DIR = '../../shared/audiofolders'; const ROOT_DIRS = ['./', DEFAULT_AUDIO_DIR]; From 01ec0bca88c974f672175562b5fcbb6d60d219be Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:20:39 +0100 Subject: [PATCH 05/28] Allow download of prebuild libzmq-v4.3.5 for Docker --- docker/jukebox.Dockerfile | 17 ++++-- documentation/developers/known-issues.md | 15 ++++- documentation/developers/libzmq.md | 68 +++++++++++++++++++++ installation/routines/setup_jukebox_core.sh | 6 +- 4 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 documentation/developers/libzmq.md diff --git a/docker/jukebox.Dockerfile b/docker/jukebox.Dockerfile index 5e7a08915..44c66cc24 100644 --- a/docker/jukebox.Dockerfile +++ b/docker/jukebox.Dockerfile @@ -1,7 +1,5 @@ FROM debian:bullseye-slim -# Prepare Raspberry Pi like environment - # These are only dependencies that are required to get as close to the # Raspberry Pi environment as possible. RUN apt-get update && apt-get install -y \ @@ -25,7 +23,7 @@ RUN apt-get update && apt-get install -qq -y \ --allow-downgrades --allow-remove-essential --allow-change-held-packages \ gcc at wget \ espeak mpc mpg123 git ffmpeg spi-tools netcat \ - python3 python3-venv python3-dev python3-mutagen + python3 python3-venv python3-dev python3-mutagen build-essential ENV VIRTUAL_ENV=${INSTALLATION_PATH}/.venv RUN python3 -m venv $VIRTUAL_ENV @@ -36,7 +34,18 @@ WORKDIR ${HOME} COPY --chown=${USER}:${USER} . ${INSTALLATION_PATH}/ RUN pip install --no-cache-dir -r ${INSTALLATION_PATH}/requirements.txt -RUN pip install pyzmq + +ENV ZMQ_TMP_DIR libzmq +ENV ZMQ_VERSION 4.3.5 +ENV ZMQ_PREFIX /usr/local + +RUN [ "$(uname -m)" = "aarch64" ] && ARCH="arm64" || ARCH="$(uname -m)"; \ + wget https://github.com/pabera/libzmq/releases/download/v${ZMQ_VERSION}/libzmq5-${ARCH}-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz; \ + tar -xzf libzmq.tar.gz -C ${ZMQ_PREFIX}; \ + rm -f libzmq.tar.gz; + +RUN export ZMQ_PREFIX=${PREFIX} && export ZMQ_DRAFT_API=1 +RUN pip install -v --no-binary pyzmq --pre pyzmq EXPOSE 5555 5556 diff --git a/documentation/developers/known-issues.md b/documentation/developers/known-issues.md index 598ecd791..aec5c027b 100644 --- a/documentation/developers/known-issues.md +++ b/documentation/developers/known-issues.md @@ -1,9 +1,18 @@ # Known Issues -## Browsers +## Installing limzmq in Docker fails -The Web UI will **not** work with Firefox, due to an issue with websockets and pyzmq. Please use a different -browser for now. +To speed up the Docker build process, we are distributing pre-build versions of libzmq with drafts flag at the latest version. In case the download fails because the respective architecture build does not exist, you can build the version yourself. Just replace the command to download the pre-built library with the following command + +``` +# Compile ZMQ +RUN cd ${HOME} && mkdir ${ZMQ_TMP_DIR} && cd ${ZMQ_TMP_DIR}; \ + wget https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz; \ + tar -xzf libzmq.tar.gz; \ + rm -f libzmq.tar.gz; \ + zeromq-${ZMQ_VERSION}/configure --prefix=${ZMQ_PREFIX} --enable-drafts; \ + make && make install +``` ## Configuration diff --git a/documentation/developers/libzmq.md b/documentation/developers/libzmq.md new file mode 100644 index 000000000..f4a58f550 --- /dev/null +++ b/documentation/developers/libzmq.md @@ -0,0 +1,68 @@ +# `libzmq` for Raspberry Pi + +## `libzmp` Releases + +The Jukebox requires `libzmq` to work properly. We provide downloadable builds to speed up the installation process of the Phoniebox. + +* https://github.com/pabera/libzmq/releases + +> [!NOTE] +> We can't use stable builds that are distributed by zeromq directly because the Jukebox requires draft builds to support WebSockets. These draft builds are not officially provided through zeromq for Raspberry Pi architecture (e.g. `armv6` or `armv7`). + +## Building `libzmp` + +If you need to update the `libzmq` version in the future, follow these steps. + +### Install Cross-Compilation Environment + +First, you need to install Dockcross. Dockcross provides Docker images for cross-compilation. + +1. **Pull the Dockcross Image**: For Raspberry Pi B, 4 or Zero 2 we need `linux-armv7`, for older models `linux-armv6`. The following example shows how to compile for `armv7` (32 bit, `arm32v7`). If you want to compile for another target, change the commands accordingly. For Docker Development environments, other targets like `arm64` or `x86_64` become relevant. + +```bash +docker pull dockcross/linux-armv7 +``` + +3. **Create a Dockcross Script**: After pulling the image, you create a Dockcross script which will be used to run the cross-compilation tools in the Docker container. + +```bash +docker run --rm dockcross/linux-armv7 > ./dockcross-linux-armv7 +chmod +x ./dockcross-linux-armv7 +``` + +This command creates a script named `dockcross-linux-armv7` in your current directory. + +### Cross-Compiling libzmq + +With Dockcross installed, you can now modify your `libzmq` compilation process to use the Dockcross environment. + +1. **Download `libzmq` Source**: Similar to your original process, download the `libzmq` source code: + +```bash +ZMQ_VERSION=4.3.5 +wget https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz +tar -xzf libzmq.tar.gz +``` + +2. **Cross-Compilation using Dockcross**: + +Modify your build process to run inside the Dockcross environment: + +```bash +./dockcross-linux-armv7 bash -c '\ +cd zeromq-${ZMQ_VERSION} && \ +./configure --prefix=/usr/local --enable-drafts && \ +make -j$(nproc) && \ +make install DESTDIR=$(pwd)/../installed' +``` + +> [!NOTE] +> In the script above, you need to update ${ZMQ_VERSION} to the actual value as the script does not jave access to your host machine ENV variables. + +This command configures and builds `libzmq` inside the Docker container. The `DESTDIR` variable is used to specify where to install the files inside the container. + +3. **Compress the Compiled Binaries**: After compilation, the binaries are located in the `installed` directory inside your `zeromq-${ZMQ_VERSION}` directory. + +``` +tar -czvf libzmq5-armv7-${ZMQ_VERSION}.tar.gz -C installed/usr/local --exclude='.' include lib +``` diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index 272901de1..2ef0a0a04 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash # Constants -GD_ID_COMPILED_LIBZMQ_ARMV7="1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F" # ARMv7: https://drive.google.com/file/d/1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F/view?usp=sharing -GD_ID_COMPILED_LIBZMQ_ARMV6="1iygOm-G1cg_3YERuVRT6FhGBE34ZkwgV" # ARMv6: https://drive.google.com/file/d/1iygOm-G1cg_3YERuVRT6FhGBE34ZkwgV/view?usp=sharing -GD_ID_COMPILED_PYZMQ_ARMV7="" +GD_ID_COMPILED_LIBZMQ_ARMV6="17VTgriCsYmAm72YKkga97jO0nExtq6G-" # armv6: https://drive.google.com/file/d/17VTgriCsYmAm72YKkga97jO0nExtq6G-/view?usp=sharing +GD_ID_COMPILED_LIBZMQ_ARMV7="1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F" # armv7: https://drive.google.com/file/d/1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F/view?usp=sharing GD_ID_COMPILED_PYZMQ_ARMV6="1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n" # https://drive.google.com/file/d/1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n/view?usp=sharing +GD_ID_COMPILED_PYZMQ_ARMV7="" ZMQ_TMP_DIR="libzmq" ZMQ_PREFIX="/usr/local" From 8ea49cf49508f389d6ba83d50787539950532e79 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:31:40 +0100 Subject: [PATCH 06/28] Remove unnecessary build-essentials from apt-get in Dockerfile --- docker/jukebox.Dockerfile | 2 +- documentation/developers/known-issues.md | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docker/jukebox.Dockerfile b/docker/jukebox.Dockerfile index 44c66cc24..f842a7394 100644 --- a/docker/jukebox.Dockerfile +++ b/docker/jukebox.Dockerfile @@ -23,7 +23,7 @@ RUN apt-get update && apt-get install -qq -y \ --allow-downgrades --allow-remove-essential --allow-change-held-packages \ gcc at wget \ espeak mpc mpg123 git ffmpeg spi-tools netcat \ - python3 python3-venv python3-dev python3-mutagen build-essential + python3 python3-venv python3-dev python3-mutagen ENV VIRTUAL_ENV=${INSTALLATION_PATH}/.venv RUN python3 -m venv $VIRTUAL_ENV diff --git a/documentation/developers/known-issues.md b/documentation/developers/known-issues.md index 32c3e2cd2..25e8b73d2 100644 --- a/documentation/developers/known-issues.md +++ b/documentation/developers/known-issues.md @@ -2,7 +2,9 @@ ## Installing limzmq in Docker fails -To speed up the Docker build process, we are distributing pre-build versions of libzmq with drafts flag at the latest version. In case the download fails because the respective architecture build does not exist, you can build the version yourself. Just replace the command to download the pre-built library with the following command +To speed up the Docker build process, we are distributing pre-build versions of libzmq with drafts flag at the latest version. In case the download fails because the respective architecture build does not exist, you can build the version yourself. + +Add `build-essential` to tbe installed additionally with `apt-get`. Additionally, replace the command to download the pre-built library with the following command. ``` # Compile ZMQ @@ -16,7 +18,7 @@ RUN cd ${HOME} && mkdir ${ZMQ_TMP_DIR} && cd ${ZMQ_TMP_DIR}; \ ## Configuration -In `jukebox.yaml` (and all other config files): +In `jukebox.yaml` (and all other config files): Always use relative path from settingsfile `../../`, but do not use relative paths with `~/`. **Sole** exception is in `playermpd.mpd_conf`. From a32b771014d6a9ee666326ec865b86a1f8bc527e Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:42:03 +0100 Subject: [PATCH 07/28] Fix a few typos --- documentation/developers/known-issues.md | 2 +- documentation/developers/libzmq.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/developers/known-issues.md b/documentation/developers/known-issues.md index 25e8b73d2..cdaf35d4f 100644 --- a/documentation/developers/known-issues.md +++ b/documentation/developers/known-issues.md @@ -4,7 +4,7 @@ To speed up the Docker build process, we are distributing pre-build versions of libzmq with drafts flag at the latest version. In case the download fails because the respective architecture build does not exist, you can build the version yourself. -Add `build-essential` to tbe installed additionally with `apt-get`. Additionally, replace the command to download the pre-built library with the following command. +Add `build-essential` to be installed additionally with `apt-get`. Additionally, replace the command to download the pre-built library with the following command. ``` # Compile ZMQ diff --git a/documentation/developers/libzmq.md b/documentation/developers/libzmq.md index f4a58f550..3407d971e 100644 --- a/documentation/developers/libzmq.md +++ b/documentation/developers/libzmq.md @@ -7,7 +7,7 @@ The Jukebox requires `libzmq` to work properly. We provide downloadable builds t * https://github.com/pabera/libzmq/releases > [!NOTE] -> We can't use stable builds that are distributed by zeromq directly because the Jukebox requires draft builds to support WebSockets. These draft builds are not officially provided through zeromq for Raspberry Pi architecture (e.g. `armv6` or `armv7`). +> We can't use stable builds that are distributed by [zeromq](https://github.com/zeromq/libzmq/releases) directly because the Jukebox requires draft builds to support WebSockets. These [draft builds](https://pyzmq.readthedocs.io/en/latest/howto/draft.html) are not officially provided through zeromq for Raspberry Pi architecture (e.g. `armv6` or `armv7`). ## Building `libzmp` From 78eb0c45e5aac46f707ecc862f24e663dcc0b208 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:04:39 +0100 Subject: [PATCH 08/28] Use wget to download pre-built libzmq from github --- documentation/developers/known-issues.md | 2 +- installation/includes/02_helpers.sh | 15 +++++++++++++++ installation/routines/setup_jukebox_core.sh | 18 +++++++++--------- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/documentation/developers/known-issues.md b/documentation/developers/known-issues.md index cdaf35d4f..1460c1cb4 100644 --- a/documentation/developers/known-issues.md +++ b/documentation/developers/known-issues.md @@ -1,6 +1,6 @@ # Known Issues -## Installing limzmq in Docker fails +## Installing `libzmq` in Docker fails To speed up the Docker build process, we are distributing pre-build versions of libzmq with drafts flag at the latest version. In case the download fails because the respective architecture build does not exist, you can build the version yourself. diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index 4a39ae07e..2da629468 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -34,6 +34,21 @@ run_with_log_frame() { echo "#########################################################" } +get_architecture() { + ARCH="" + if [ "$(uname -m)" = "armv7l" ]; then + ARCH="armv7" + elif [ "$(uname -m)" = "armv6l" ]; then + ARCH="armv6" + elif [ "$(uname -m)" = "aarch64" ]; then + ARCH="arm64" + else + ARCH="$(uname -m)" + fi + + echo $ARCH +} + _download_file_from_google_drive() { GD_SHARING_ID=${1} TAR_FILENAME=${2} diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index dbe5d9115..a62b398ca 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -8,6 +8,7 @@ GD_ID_COMPILED_PYZMQ_ARMV7="" ZMQ_TMP_DIR="libzmq" ZMQ_PREFIX="/usr/local" +ZMQ_VERSION="4.3.5" JUKEBOX_PULSE_CONFIG="${HOME_PATH}"/.config/pulse/default.pa JUKEBOX_SERVICE_NAME="${SYSTEMD_USR_PATH}/jukebox-daemon.service" @@ -52,9 +53,10 @@ _jukebox_core_configure_pulseaudio() { } _jukebox_core_build_libzmq_with_drafts() { - LIBSODIUM_VERSION="1.0.18" - ZMQ_VERSION="4.3.4" + echo " Building libzmq with drafts support" | tee /dev/fd/3 + LIBSODIUM_VERSION="1.0.18" + echo " Building libsodium v${LIBSODIUM_VERSION}" | tee /dev/fd/3 { cd "${HOME_PATH}" && mkdir "${ZMQ_TMP_DIR}" && cd "${ZMQ_TMP_DIR}"; } || exit_on_error wget --quiet https://github.com/jedisct1/libsodium/releases/download/${LIBSODIUM_VERSION}-RELEASE/libsodium-${LIBSODIUM_VERSION}.tar.gz tar -zxvf libsodium-${LIBSODIUM_VERSION}.tar.gz @@ -62,6 +64,7 @@ _jukebox_core_build_libzmq_with_drafts() { ./configure make && make install + echo " Building libzmq v${ZMQ_VERSION}" | tee /dev/fd/3 cd "${HOME}/${ZMQ_TMP_DIR}" || exit_on_error wget https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz tar -xzf libzmq.tar.gz @@ -71,8 +74,9 @@ _jukebox_core_build_libzmq_with_drafts() { _jukebox_core_download_prebuilt_libzmq_with_drafts() { local ZMQ_TAR_FILENAME="libzmq.tar.gz" + ARCH=$(get_architecture) - _download_file_from_google_drive "${LIBZMQ_GD_DOWNLOAD_ID}" "${ZMQ_TAR_FILENAME}" + wget https://github.com/pabera/libzmq/releases/download/v${ZMQ_VERSION}/libzmq5-${ARCH}-${ZMQ_VERSION}.tar.gz -O ${ZMQ_TAR_FILENAME} tar -xzf ${ZMQ_TAR_FILENAME} rm -f ${ZMQ_TAR_FILENAME} sudo rsync -a ./* ${ZMQ_PREFIX}/ @@ -86,7 +90,7 @@ _jukebox_core_build_and_install_pyzmq() { # Sources: # https://pyzmq.readthedocs.io/en/latest/howto/draft.html # https://github.com/MonsieurV/ZeroMQ-RPi/blob/master/README.md - echo " Build and install pyzmq with WebSockets Support" | tee /dev/fd/3 + echo " Install pyzmq with WebSockets Support" | tee /dev/fd/3 if ! pip list | grep -F pyzmq >> /dev/null; then # Download pre-compiled libzmq from Google Drive because RPi has trouble compiling it @@ -94,11 +98,7 @@ _jukebox_core_build_and_install_pyzmq() { { cd "${HOME_PATH}" && mkdir "${ZMQ_TMP_DIR}" && cd "${ZMQ_TMP_DIR}"; } || exit_on_error - # ARMv7 as default - LIBZMQ_GD_DOWNLOAD_ID=${GD_ID_COMPILED_LIBZMQ_ARMV7} if [[ $(uname -m) == "armv6l" ]]; then - # ARMv6 as fallback - LIBZMQ_GD_DOWNLOAD_ID=${GD_ID_COMPILED_LIBZMQ_ARMV6} _show_slow_hardware_message fi @@ -109,7 +109,7 @@ _jukebox_core_build_and_install_pyzmq() { fi ZMQ_PREFIX="${ZMQ_PREFIX}" ZMQ_DRAFT_API=1 \ - pip install --no-cache-dir --no-binary "pyzmq" --pre pyzmq + pip install -v --no-binary pyzmq --pre pyzmq else echo " Skipping. pyzmq already installed" | tee /dev/fd/3 fi From 5a875b87116a3e3151173d1acc271073c30b0a55 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:05:39 +0100 Subject: [PATCH 09/28] Remove unused constants --- installation/routines/setup_jukebox_core.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index a62b398ca..0568feb64 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -1,11 +1,6 @@ #!/usr/bin/env bash # Constants -GD_ID_COMPILED_LIBZMQ_ARMV6="17VTgriCsYmAm72YKkga97jO0nExtq6G-" # armv6: https://drive.google.com/file/d/17VTgriCsYmAm72YKkga97jO0nExtq6G-/view?usp=sharing -GD_ID_COMPILED_LIBZMQ_ARMV7="1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F" # armv7: https://drive.google.com/file/d/1950psO7Mbs4GdWBMqIzdTAZPLnKhDg7F/view?usp=sharing -GD_ID_COMPILED_PYZMQ_ARMV6="1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n" # https://drive.google.com/file/d/1lDsV_pVcXbg6YReHb9AldMkyRZCpc6-n/view?usp=sharing -GD_ID_COMPILED_PYZMQ_ARMV7="" - ZMQ_TMP_DIR="libzmq" ZMQ_PREFIX="/usr/local" ZMQ_VERSION="4.3.5" From 54681dabf22de96e2c17dbc37003b123c8091785 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:24:50 +0100 Subject: [PATCH 10/28] Make variable local to its function --- installation/includes/02_helpers.sh | 12 ++++++------ installation/routines/setup_jukebox_core.sh | 6 ++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index 2da629468..1294d5bc6 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -35,18 +35,18 @@ run_with_log_frame() { } get_architecture() { - ARCH="" + local arch="" if [ "$(uname -m)" = "armv7l" ]; then - ARCH="armv7" + arch="armv7" elif [ "$(uname -m)" = "armv6l" ]; then - ARCH="armv6" + arch="armv6" elif [ "$(uname -m)" = "aarch64" ]; then - ARCH="arm64" + arch="arm64" else - ARCH="$(uname -m)" + arch="$(uname -m)" fi - echo $ARCH + echo $arch } _download_file_from_google_drive() { diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index 0568feb64..353607c12 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -68,6 +68,7 @@ _jukebox_core_build_libzmq_with_drafts() { } _jukebox_core_download_prebuilt_libzmq_with_drafts() { + echo " Download pre-compiled libzmq" local ZMQ_TAR_FILENAME="libzmq.tar.gz" ARCH=$(get_architecture) @@ -85,12 +86,9 @@ _jukebox_core_build_and_install_pyzmq() { # Sources: # https://pyzmq.readthedocs.io/en/latest/howto/draft.html # https://github.com/MonsieurV/ZeroMQ-RPi/blob/master/README.md - echo " Install pyzmq with WebSockets Support" | tee /dev/fd/3 + echo " Install pyzmq with libzmq-drafts to support WebSockets" | tee /dev/fd/3 if ! pip list | grep -F pyzmq >> /dev/null; then - # Download pre-compiled libzmq from Google Drive because RPi has trouble compiling it - echo " Download pre-compiled libzmq from Google Drive because RPi has trouble compiling it" - { cd "${HOME_PATH}" && mkdir "${ZMQ_TMP_DIR}" && cd "${ZMQ_TMP_DIR}"; } || exit_on_error if [[ $(uname -m) == "armv6l" ]]; then From ade28940c9da12e187ec5f58bf9762ebf5e05bd9 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:23:49 +0100 Subject: [PATCH 11/28] Install webapp from release build if Node.JS download is aborted --- installation/routines/customize_options.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/installation/routines/customize_options.sh b/installation/routines/customize_options.sh index 50df075fe..1590383d1 100644 --- a/installation/routines/customize_options.sh +++ b/installation/routines/customize_options.sh @@ -303,6 +303,7 @@ Do you want to install Node? [Y/n]" 1>&3 case "$response" in [nN][oO]|[nN]) ENABLE_INSTALL_NODE=false + ENABLE_WEBAPP_PROD_DOWNLOAD=true ;; *) ;; From c3d08977b93c99733d86fda9c9e839e8231105d4 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Thu, 7 Dec 2023 22:32:30 +0100 Subject: [PATCH 12/28] Use GH release downloads for webapp --- installation/includes/02_helpers.sh | 22 ++++++++++++++----- installation/routines/setup_jukebox_core.sh | 4 ++-- installation/routines/setup_jukebox_webapp.sh | 5 +++-- installation/routines/setup_samba.sh | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index 1294d5bc6..92d6754e0 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -49,14 +49,24 @@ get_architecture() { echo $arch } -_download_file_from_google_drive() { - GD_SHARING_ID=${1} - TAR_FILENAME=${2} - wget --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$(wget --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate 'https://docs.google.com/uc?export=download&id=${GD_SHARING_ID}' -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=${GD_SHARING_ID}" -O ${TAR_FILENAME} && rm -rf /tmp/cookies.txt - echo "Downloaded from Google Drive ID ${GD_SHARING_ID} into ${TAR_FILENAME}" +get_version_string() { + local python_file="$1" + local version_major + local version_minor + local version_patch + + version_major=$(grep 'VERSION_MAJOR\s*=\s*[0-9]*' "$python_file" | awk -F= '{print $2}' | tr -d ' ') + version_minor=$(grep 'VERSION_MINOR\s*=\s*[0-9]*' "$python_file" | awk -F= '{print $2}' | tr -d ' ') + version_patch=$(grep 'VERSION_PATCH\s*=\s*[0-9]*' "$python_file" | awk -F= '{print $2}' | tr -d ' ') + + if [ -n "$version_major" ] && [ -n "$version_minor" ] && [ -n "$version_patch" ]; then + local version_string="${version_major}.${version_minor}.${version_patch}" + echo "$version_string" + else + echo "Unable to extract version information from $python_file" + fi } - ### Verify helpers print_verify_installation() { diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index 353607c12..efdb6c168 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -61,7 +61,7 @@ _jukebox_core_build_libzmq_with_drafts() { echo " Building libzmq v${ZMQ_VERSION}" | tee /dev/fd/3 cd "${HOME}/${ZMQ_TMP_DIR}" || exit_on_error - wget https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz + wget --quiet https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz tar -xzf libzmq.tar.gz zeromq-${ZMQ_VERSION}/configure --prefix=${ZMQ_PREFIX} --enable-drafts make && make install @@ -72,7 +72,7 @@ _jukebox_core_download_prebuilt_libzmq_with_drafts() { local ZMQ_TAR_FILENAME="libzmq.tar.gz" ARCH=$(get_architecture) - wget https://github.com/pabera/libzmq/releases/download/v${ZMQ_VERSION}/libzmq5-${ARCH}-${ZMQ_VERSION}.tar.gz -O ${ZMQ_TAR_FILENAME} + wget --quiet https://github.com/pabera/libzmq/releases/download/v${ZMQ_VERSION}/libzmq5-${ARCH}-${ZMQ_VERSION}.tar.gz -O ${ZMQ_TAR_FILENAME} tar -xzf ${ZMQ_TAR_FILENAME} rm -f ${ZMQ_TAR_FILENAME} sudo rsync -a ./* ${ZMQ_PREFIX}/ diff --git a/installation/routines/setup_jukebox_webapp.sh b/installation/routines/setup_jukebox_webapp.sh index 54c573654..b7837c29a 100644 --- a/installation/routines/setup_jukebox_webapp.sh +++ b/installation/routines/setup_jukebox_webapp.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash # Constants -GD_ID_COMPILED_WEBAPP="1um-smyfsVPzVZn18hhwuFt97XR3PjAbB" # https://drive.google.com/file/d/1um-smyfsVPzVZn18hhwuFt97XR3PjAbB/view?usp=sharing WEBAPP_NGINX_SITE_DEFAULT_CONF="/etc/nginx/sites-available/default" # For ARMv7+ @@ -56,9 +55,11 @@ _jukebox_webapp_build() { _jukebox_webapp_download() { echo " Downloading web application" | tee /dev/fd/3 + local JUKEBOX_VERSION==$(get_version_string "${INSTALLATION_PATH}/src/jukebox/jukebox/version.py") local TAR_FILENAME="webapp-build.tar.gz" + cd "${INSTALLATION_PATH}/src/webapp" || exit_on_error - _download_file_from_google_drive ${GD_ID_COMPILED_WEBAPP} ${TAR_FILENAME} + wget --quiet ${GIT_URL}/releases/download/v${JUKEBOX_VERSION}/webapp-v${JUKEBOX_VERSION}.tar.gz -O ${TAR_FILENAME} tar -xzf ${TAR_FILENAME} rm -f ${TAR_FILENAME} cd "${INSTALLATION_PATH}" || exit_on_error diff --git a/installation/routines/setup_samba.sh b/installation/routines/setup_samba.sh index 4b45b54e1..100d7370d 100644 --- a/installation/routines/setup_samba.sh +++ b/installation/routines/setup_samba.sh @@ -31,7 +31,7 @@ _samba_set_user() { sudo cat << EOF >> $SMB_CONF ${SMB_CONF_HEADER} [phoniebox] - comment= Pi Jukebox + comment=Pi Jukebox path=${SHARED_PATH} browseable=Yes writeable=Yes From 3ffe8a3598b3f328152aff2bb492d4ca0b12d274 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Thu, 7 Dec 2023 22:55:57 +0100 Subject: [PATCH 13/28] Bugfix: wrong variable assignment --- installation/includes/02_helpers.sh | 11 +++++------ installation/routines/setup_jukebox_webapp.sh | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index 92d6754e0..c0a9aa0d1 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -55,20 +55,19 @@ get_version_string() { local version_minor local version_patch - version_major=$(grep 'VERSION_MAJOR\s*=\s*[0-9]*' "$python_file" | awk -F= '{print $2}' | tr -d ' ') - version_minor=$(grep 'VERSION_MINOR\s*=\s*[0-9]*' "$python_file" | awk -F= '{print $2}' | tr -d ' ') - version_patch=$(grep 'VERSION_PATCH\s*=\s*[0-9]*' "$python_file" | awk -F= '{print $2}' | tr -d ' ') + version_major=$(grep 'VERSION_MAJOR\s*=\s*[0-9]*' "${python_file}" | awk -F= '{print $2}' | tr -d ' ') + version_minor=$(grep 'VERSION_MINOR\s*=\s*[0-9]*' "${python_file}" | awk -F= '{print $2}' | tr -d ' ') + version_patch=$(grep 'VERSION_PATCH\s*=\s*[0-9]*' "${python_file}" | awk -F= '{print $2}' | tr -d ' ') if [ -n "$version_major" ] && [ -n "$version_minor" ] && [ -n "$version_patch" ]; then local version_string="${version_major}.${version_minor}.${version_patch}" - echo "$version_string" + echo "Jukebox Version: ${version_string}" else - echo "Unable to extract version information from $python_file" + echo "Unable to extract version information from ${python_file}" fi } ### Verify helpers - print_verify_installation() { echo "" echo " -------------------------------------------------------" diff --git a/installation/routines/setup_jukebox_webapp.sh b/installation/routines/setup_jukebox_webapp.sh index b7837c29a..881b27468 100644 --- a/installation/routines/setup_jukebox_webapp.sh +++ b/installation/routines/setup_jukebox_webapp.sh @@ -55,7 +55,7 @@ _jukebox_webapp_build() { _jukebox_webapp_download() { echo " Downloading web application" | tee /dev/fd/3 - local JUKEBOX_VERSION==$(get_version_string "${INSTALLATION_PATH}/src/jukebox/jukebox/version.py") + local JUKEBOX_VERSION=$(get_version_string "${INSTALLATION_PATH}/src/jukebox/jukebox/version.py") local TAR_FILENAME="webapp-build.tar.gz" cd "${INSTALLATION_PATH}/src/webapp" || exit_on_error From bdb1dd1b7c30260b681508c112b38755c7644002 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Fri, 8 Dec 2023 09:07:00 +0100 Subject: [PATCH 14/28] Static release download url --- installation/routines/setup_jukebox_webapp.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/installation/routines/setup_jukebox_webapp.sh b/installation/routines/setup_jukebox_webapp.sh index 881b27468..9dc74bf12 100644 --- a/installation/routines/setup_jukebox_webapp.sh +++ b/installation/routines/setup_jukebox_webapp.sh @@ -57,9 +57,12 @@ _jukebox_webapp_download() { echo " Downloading web application" | tee /dev/fd/3 local JUKEBOX_VERSION=$(get_version_string "${INSTALLATION_PATH}/src/jukebox/jukebox/version.py") local TAR_FILENAME="webapp-build.tar.gz" + local DOWNLOAD_URL="https://github.com/MiczFlor/RPi-Jukebox-RFID/releases/download/v${JUKEBOX_VERSION}/webapp-v${JUKEBOX_VERSION}.tar.gz" + echo " DOWNLOAD_URL: ${DOWNLOAD_URL}" cd "${INSTALLATION_PATH}/src/webapp" || exit_on_error - wget --quiet ${GIT_URL}/releases/download/v${JUKEBOX_VERSION}/webapp-v${JUKEBOX_VERSION}.tar.gz -O ${TAR_FILENAME} + # URL must be set to default repo as installation can be run from different repos as well where releases may not exist + wget --quiet ${DOWNLOAD_URL} -O ${TAR_FILENAME} tar -xzf ${TAR_FILENAME} rm -f ${TAR_FILENAME} cd "${INSTALLATION_PATH}" || exit_on_error From caf4a5525fa3f4d50a0ecff1870abb9d5b9f21d3 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Fri, 8 Dec 2023 09:33:09 +0100 Subject: [PATCH 15/28] Fix version funtion return value --- installation/includes/02_helpers.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index c0a9aa0d1..a8deca9c3 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -61,9 +61,9 @@ get_version_string() { if [ -n "$version_major" ] && [ -n "$version_minor" ] && [ -n "$version_patch" ]; then local version_string="${version_major}.${version_minor}.${version_patch}" - echo "Jukebox Version: ${version_string}" + echo ${version_string} else - echo "Unable to extract version information from ${python_file}" + exit_on_error "ERROR: Unable to extract version information from ${python_file}" fi } From 554c0ed0b87717dc90e76794dd63f871ae83e1f6 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Fri, 8 Dec 2023 08:26:19 +0100 Subject: [PATCH 16/28] fix local libzmq build fix folder handling ZMQ_TMP_DIR. remove libsodium (use internal encryption lib tweetnacl). add cpu_count. add --disable-Werror. add sudo to make install. update log messaages. --- installation/routines/setup_jukebox_core.sh | 38 +++++++++------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index efdb6c168..b02b8418b 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Constants -ZMQ_TMP_DIR="libzmq" +ZMQ_TMP_DIR="${HOME_PATH}/libzmq" ZMQ_PREFIX="/usr/local" ZMQ_VERSION="4.3.5" @@ -48,30 +48,26 @@ _jukebox_core_configure_pulseaudio() { } _jukebox_core_build_libzmq_with_drafts() { - echo " Building libzmq with drafts support" | tee /dev/fd/3 - - LIBSODIUM_VERSION="1.0.18" - echo " Building libsodium v${LIBSODIUM_VERSION}" | tee /dev/fd/3 - { cd "${HOME_PATH}" && mkdir "${ZMQ_TMP_DIR}" && cd "${ZMQ_TMP_DIR}"; } || exit_on_error - wget --quiet https://github.com/jedisct1/libsodium/releases/download/${LIBSODIUM_VERSION}-RELEASE/libsodium-${LIBSODIUM_VERSION}.tar.gz - tar -zxvf libsodium-${LIBSODIUM_VERSION}.tar.gz - cd libsodium-${LIBSODIUM_VERSION} || exit_on_error - ./configure - make && make install - - echo " Building libzmq v${ZMQ_VERSION}" | tee /dev/fd/3 - cd "${HOME}/${ZMQ_TMP_DIR}" || exit_on_error - wget --quiet https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/zeromq-${ZMQ_VERSION}.tar.gz -O libzmq.tar.gz - tar -xzf libzmq.tar.gz - zeromq-${ZMQ_VERSION}/configure --prefix=${ZMQ_PREFIX} --enable-drafts - make && make install + echo " Building libzmq v${ZMQ_VERSION} with drafts support" | tee /dev/fd/3 + local zmq_filename="zeromq-${ZMQ_VERSION}" + local zmq_tar_filename="${zmq_filename}.tar.gz" + local cpu_count=${CPU_COUNT:-$(python3 -c "import os; print(os.cpu_count())")} + + cd "${ZMQ_TMP_DIR}" || exit_on_error + wget --quiet https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/${zmq_tar_filename} + tar -xzf ${zmq_tar_filename} + rm -f ${zmq_tar_filename} + cd ${zmq_filename} || exit_on_error + ./configure --prefix=${ZMQ_PREFIX} --enable-drafts --disable-Werror + make -j${cpu_count} && sudo make install } _jukebox_core_download_prebuilt_libzmq_with_drafts() { - echo " Download pre-compiled libzmq" + echo " Download pre-compiled libzmq with drafts support" local ZMQ_TAR_FILENAME="libzmq.tar.gz" ARCH=$(get_architecture) + cd "${ZMQ_TMP_DIR}" || exit_on_error wget --quiet https://github.com/pabera/libzmq/releases/download/v${ZMQ_VERSION}/libzmq5-${ARCH}-${ZMQ_VERSION}.tar.gz -O ${ZMQ_TAR_FILENAME} tar -xzf ${ZMQ_TAR_FILENAME} rm -f ${ZMQ_TAR_FILENAME} @@ -89,12 +85,12 @@ _jukebox_core_build_and_install_pyzmq() { echo " Install pyzmq with libzmq-drafts to support WebSockets" | tee /dev/fd/3 if ! pip list | grep -F pyzmq >> /dev/null; then - { cd "${HOME_PATH}" && mkdir "${ZMQ_TMP_DIR}" && cd "${ZMQ_TMP_DIR}"; } || exit_on_error if [[ $(uname -m) == "armv6l" ]]; then _show_slow_hardware_message fi + mkdir -p "${ZMQ_TMP_DIR}" || exit_on_error if [ "$BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE" = true ] ; then _jukebox_core_build_libzmq_with_drafts else @@ -151,8 +147,8 @@ _jukebox_core_check() { _run_setup_jukebox_core() { _jukebox_core_install_os_dependencies _jukebox_core_install_python_requirements - _jukebox_core_configure_pulseaudio _jukebox_core_build_and_install_pyzmq + _jukebox_core_configure_pulseaudio _jukebox_core_install_settings _jukebox_core_register_as_service _jukebox_core_check From 435bd6fdf0dcc8c074c901c7afad4a777e23d016 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Fri, 8 Dec 2023 08:26:19 +0100 Subject: [PATCH 17/28] add CI test for local libzmq build --- .../test_docker_debian_codename_sub_v3.yml | 2 +- ci/installation/run_install_libzmq_local.sh | 40 +++++++++++++++++++ installation/includes/01_default_config.sh | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 ci/installation/run_install_libzmq_local.sh diff --git a/.github/workflows/test_docker_debian_codename_sub_v3.yml b/.github/workflows/test_docker_debian_codename_sub_v3.yml index 97924c4bf..b4df11b3c 100644 --- a/.github/workflows/test_docker_debian_codename_sub_v3.yml +++ b/.github/workflows/test_docker_debian_codename_sub_v3.yml @@ -143,7 +143,7 @@ jobs: strategy: fail-fast: false matrix: - test_script: ['run_install_common.sh', 'run_install_faststartup.sh', 'run_install_webapp_local.sh', 'run_install_webapp_download.sh'] + test_script: ['run_install_common.sh', 'run_install_faststartup.sh', 'run_install_webapp_local.sh', 'run_install_webapp_download.sh', 'run_install_libzmq_local.sh'] steps: - name: Set up QEMU diff --git a/ci/installation/run_install_libzmq_local.sh b/ci/installation/run_install_libzmq_local.sh new file mode 100644 index 000000000..20f246ff8 --- /dev/null +++ b/ci/installation/run_install_libzmq_local.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Install Phoniebox and test it +# Used e.g. for tests on Docker + +# Objective: +# Test for the libzmq local build (no precompiled download) + +SOURCE="${BASH_SOURCE[0]}" +SCRIPT_DIR="$(dirname "$SOURCE")" +LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" +LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + +export BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE=true +# Run installation (in interactive mode) +# y - start setup +# n - use static ip +# n - deactivate ipv6 +# n - setup autohotspot +# n - deactivate bluetooth +# n - disable on-chip audio +# - - mpd overwrite config (only with existing installation) +# n - setup rfid reader +# n - setup samba +# n - setup webapp +# - - setup kiosk mode (only with webapp = y) +# - - install node (only with webapp = y) +# n - reboot + +"${LOCAL_INSTALL_SCRIPT_PATH}/install-jukebox.sh" <<< 'y +n +n +n +n +n +n +n +n +n +' diff --git a/installation/includes/01_default_config.sh b/installation/includes/01_default_config.sh index b2f37a1de..fa1bafb61 100644 --- a/installation/includes/01_default_config.sh +++ b/installation/includes/01_default_config.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE=false +BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE=${BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE:-"false"} ENABLE_STATIC_IP=true DISABLE_IPv6=true ENABLE_AUTOHOTSPOT=false From 23cf06cb90cb7fe23ee6347fdd86c5741540f8cc Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Fri, 8 Dec 2023 08:26:19 +0100 Subject: [PATCH 18/28] update var names and docs --- installation/routines/setup_jukebox_core.sh | 33 +++++++++++---------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index b02b8418b..6b070ff6c 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash # Constants -ZMQ_TMP_DIR="${HOME_PATH}/libzmq" -ZMQ_PREFIX="/usr/local" -ZMQ_VERSION="4.3.5" +JUKEBOX_ZMQ_TMP_DIR="${HOME_PATH}/libzmq" +JUKEBOX_ZMQ_PREFIX="/usr/local" +JUKEBOX_ZMQ_VERSION="4.3.5" JUKEBOX_PULSE_CONFIG="${HOME_PATH}"/.config/pulse/default.pa JUKEBOX_SERVICE_NAME="${SYSTEMD_USR_PATH}/jukebox-daemon.service" @@ -48,30 +48,30 @@ _jukebox_core_configure_pulseaudio() { } _jukebox_core_build_libzmq_with_drafts() { - echo " Building libzmq v${ZMQ_VERSION} with drafts support" | tee /dev/fd/3 - local zmq_filename="zeromq-${ZMQ_VERSION}" + echo " Building libzmq v${JUKEBOX_ZMQ_VERSION} with drafts support" | tee /dev/fd/3 + local zmq_filename="zeromq-${JUKEBOX_ZMQ_VERSION}" local zmq_tar_filename="${zmq_filename}.tar.gz" local cpu_count=${CPU_COUNT:-$(python3 -c "import os; print(os.cpu_count())")} - cd "${ZMQ_TMP_DIR}" || exit_on_error - wget --quiet https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}/${zmq_tar_filename} + cd "${JUKEBOX_ZMQ_TMP_DIR}" || exit_on_error + wget --quiet https://github.com/zeromq/libzmq/releases/download/v${JUKEBOX_ZMQ_VERSION}/${zmq_tar_filename} tar -xzf ${zmq_tar_filename} rm -f ${zmq_tar_filename} cd ${zmq_filename} || exit_on_error - ./configure --prefix=${ZMQ_PREFIX} --enable-drafts --disable-Werror + ./configure --prefix=${JUKEBOX_ZMQ_PREFIX} --enable-drafts --disable-Werror make -j${cpu_count} && sudo make install } _jukebox_core_download_prebuilt_libzmq_with_drafts() { echo " Download pre-compiled libzmq with drafts support" - local ZMQ_TAR_FILENAME="libzmq.tar.gz" + local zmq_tar_filename="libzmq.tar.gz" ARCH=$(get_architecture) - cd "${ZMQ_TMP_DIR}" || exit_on_error - wget --quiet https://github.com/pabera/libzmq/releases/download/v${ZMQ_VERSION}/libzmq5-${ARCH}-${ZMQ_VERSION}.tar.gz -O ${ZMQ_TAR_FILENAME} - tar -xzf ${ZMQ_TAR_FILENAME} - rm -f ${ZMQ_TAR_FILENAME} - sudo rsync -a ./* ${ZMQ_PREFIX}/ + cd "${JUKEBOX_ZMQ_TMP_DIR}" || exit_on_error + wget --quiet https://github.com/pabera/libzmq/releases/download/v${JUKEBOX_ZMQ_VERSION}/libzmq5-${ARCH}-${JUKEBOX_ZMQ_VERSION}.tar.gz -O ${zmq_tar_filename} + tar -xzf ${zmq_tar_filename} + rm -f ${zmq_tar_filename} + sudo rsync -a ./* ${JUKEBOX_ZMQ_PREFIX}/ } _jukebox_core_build_and_install_pyzmq() { @@ -82,6 +82,7 @@ _jukebox_core_build_and_install_pyzmq() { # Sources: # https://pyzmq.readthedocs.io/en/latest/howto/draft.html # https://github.com/MonsieurV/ZeroMQ-RPi/blob/master/README.md + # https://github.com/zeromq/pyzmq/issues/1523#issuecomment-1593120264 echo " Install pyzmq with libzmq-drafts to support WebSockets" | tee /dev/fd/3 if ! pip list | grep -F pyzmq >> /dev/null; then @@ -90,14 +91,14 @@ _jukebox_core_build_and_install_pyzmq() { _show_slow_hardware_message fi - mkdir -p "${ZMQ_TMP_DIR}" || exit_on_error + mkdir -p "${JUKEBOX_ZMQ_TMP_DIR}" || exit_on_error if [ "$BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE" = true ] ; then _jukebox_core_build_libzmq_with_drafts else _jukebox_core_download_prebuilt_libzmq_with_drafts fi - ZMQ_PREFIX="${ZMQ_PREFIX}" ZMQ_DRAFT_API=1 \ + ZMQ_PREFIX="${JUKEBOX_ZMQ_PREFIX}" ZMQ_DRAFT_API=1 \ pip install -v --no-binary pyzmq --pre pyzmq else echo " Skipping. pyzmq already installed" | tee /dev/fd/3 From 55b1c9e59ae1a556a9953826db002499492df8dd Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:02:04 +0100 Subject: [PATCH 19/28] add platform in scope and description --- .../test_docker_debian_codename_sub_v3.yml | 17 +++++++++-------- .github/workflows/test_docker_debian_v3.yml | 10 ++++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test_docker_debian_codename_sub_v3.yml b/.github/workflows/test_docker_debian_codename_sub_v3.yml index b4df11b3c..dde60cb2a 100644 --- a/.github/workflows/test_docker_debian_codename_sub_v3.yml +++ b/.github/workflows/test_docker_debian_codename_sub_v3.yml @@ -6,14 +6,13 @@ on: debian_codename: required: true type: string + platform: + required: true + type: string docker_image_name: required: false type: string default: rpi-jukebox-rfid-v3 - platform: - required: false - type: string - default: linux/arm/v7 cache_scope: required: false type: string @@ -34,7 +33,7 @@ env: # let only one instance run the test so cache is not corrupted. # cancel already running instances as only the last run will be relevant concurrency: - group: ${{ inputs.cache_scope }}-${{ inputs.debian_codename }} + group: ${{ inputs.cache_scope }}-${{ inputs.debian_codename }}-${{ inputs.platform }} cancel-in-progress: true jobs: @@ -73,10 +72,12 @@ jobs: DEBIAN_CODENAME: ${{ inputs.debian_codename }} DOCKER_IMAGE_NAME: ${{ inputs.docker_image_name }} CACHE_SCOPE: ${{ inputs.cache_scope }} + PLATFORM: ${{ inputs.platform }} run: | - echo "image_tag_name=${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEBIAN_CODENAME }}-test" >> $GITHUB_OUTPUT - echo "image_file_name=${{ env.DOCKER_IMAGE_NAME }}-${{ env.DEBIAN_CODENAME }}.tar" >> $GITHUB_OUTPUT - echo "cache_scope=${{ env.CACHE_SCOPE }}-${{ env.DEBIAN_CODENAME }}" >> $GITHUB_OUTPUT + PLATFORM=${PLATFORM////_} + echo "image_tag_name=${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEBIAN_CODENAME }}-${PLATFORM}-test" >> $GITHUB_OUTPUT + echo "image_file_name=${{ env.DOCKER_IMAGE_NAME }}-${{ env.DEBIAN_CODENAME }}-${PLATFORM}.tar" >> $GITHUB_OUTPUT + echo "cache_scope=${{ env.CACHE_SCOPE }}-${{ env.DEBIAN_CODENAME }}-${PLATFORM}" >> $GITHUB_OUTPUT - name: Set Output vars id: vars diff --git a/.github/workflows/test_docker_debian_v3.yml b/.github/workflows/test_docker_debian_v3.yml index 6cf1648aa..6f90048ec 100644 --- a/.github/workflows/test_docker_debian_v3.yml +++ b/.github/workflows/test_docker_debian_v3.yml @@ -18,14 +18,16 @@ concurrency: jobs: # Build container and run tests. Duplication of job intended for better visualization. - run_bookworm: - name: 'bookworm' + run_bookworm_armv7: + name: 'bookworm armv7' uses: ./.github/workflows/test_docker_debian_codename_sub_v3.yml with: debian_codename: 'bookworm' + platform: linux/arm/v7 - run_bullseye: - name: 'bullseye' + run_bullseye_armv7: + name: 'bullseye armv7' uses: ./.github/workflows/test_docker_debian_codename_sub_v3.yml with: debian_codename: 'bullseye' + platform: linux/arm/v7 From c00cde685104746fc3e1cee495b36d0a7464d713 Mon Sep 17 00:00:00 2001 From: s-martin Date: Fri, 8 Dec 2023 20:53:13 +0100 Subject: [PATCH 20/28] Add file upload via WebUI --- documentation/developers/status.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/developers/status.md b/documentation/developers/status.md index 50968293c..eac874608 100644 --- a/documentation/developers/status.md +++ b/documentation/developers/status.md @@ -227,6 +227,7 @@ Topics marked _in progress_ are already in the process of implementation by comm - [x] Enable/Disable Auto-Hotspot - [x] `run_npm_build` script - [x] Must consider `export NODE_OPTIONS=--max-old-space-size=512` +- [ ] Upload audio files via WebUI https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/2138 ## Installation Procedure From 18857d7336af4dca68cfd72f7ca92e1341fe68f1 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Sun, 10 Dec 2023 18:29:47 +0100 Subject: [PATCH 21/28] [Bugfix] Webapp allows to assign single song to card (#2143) * [Bugfix][Dockerfile] Mount jukebox code as volume to support restart without build * Fix typo * [get_song_by_url] Search for relative paths in MPD database only --- docker/docker-compose.yml | 1 + src/jukebox/components/playermpd/__init__.py | 6 ++++++ src/webapp/src/components/Library/lists/index.js | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b2216894e..1679bbeb5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -40,6 +40,7 @@ services: restart: unless-stopped tty: true volumes: + - ../src/jukebox:/root/RPi-Jukebox-RFID/src/jukebox - ../shared:/root/RPi-Jukebox-RFID/shared - ./config/docker.pulse.mpd.conf:/root/.config/mpd/mpd.conf command: python run_jukebox.py diff --git a/src/jukebox/components/playermpd/__init__.py b/src/jukebox/components/playermpd/__init__.py index ecac65ab8..3975fdb67 100644 --- a/src/jukebox/components/playermpd/__init__.py +++ b/src/jukebox/components/playermpd/__init__.py @@ -80,6 +80,7 @@ # Toggle (und 2nd Swipe generell) ist immer vom Status des Zielsystems abhängig und kann damit nur vom Zielsystem geändert # werden. Bei Wifi also braucht man 3 Funktionen: on / off / toggle. Toggle ist dann first swipe / second swipe +import os import mpd import threading import logging @@ -574,6 +575,11 @@ def list_song_by_artist_and_album(self, albumartist, album): @plugs.tag def get_song_by_url(self, song_url): + # MPD can play absolute paths but can find songs in its database only by relative path + # In certain situations, `song_url` can be an absolute path. Then, it will be trimed to be relative + _music_library_path_absolute = os.path.expanduser(components.player.get_music_library_path()) + song_url = song_url.replace(f'{_music_library_path_absolute}/', '') + with self.mpd_lock: song = self.mpd_retry_with_mutex(self.mpd_client.find, 'file', song_url) diff --git a/src/webapp/src/components/Library/lists/index.js b/src/webapp/src/components/Library/lists/index.js index a153619e6..22970d9a9 100644 --- a/src/webapp/src/components/Library/lists/index.js +++ b/src/webapp/src/components/Library/lists/index.js @@ -28,7 +28,7 @@ const LibraryLists = () => { const [cardId] = useState(searchParams.get('cardId')); const [musicFilter, setMusicFilter] = useState(''); - const handleMusicFilder = (event) => { + const handleMusicFolder = (event) => { setMusicFilter(event.target.value); }; @@ -49,7 +49,7 @@ const LibraryLists = () => { {isSelecting && } Date: Sun, 10 Dec 2023 22:28:55 +0100 Subject: [PATCH 22/28] [Docs] Inform about Python venv (#2147) --- documentation/developers/README.md | 2 +- .../developers/development-environment.md | 59 +++++++------------ documentation/developers/pyhton.md | 18 ++++++ 3 files changed, 41 insertions(+), 38 deletions(-) create mode 100644 documentation/developers/pyhton.md diff --git a/documentation/developers/README.md b/documentation/developers/README.md index 9136c5f31..6c973d6ba 100644 --- a/documentation/developers/README.md +++ b/documentation/developers/README.md @@ -3,7 +3,7 @@ ## Getting started * [Development Environment](./development-environment.md) -* [Setting up Docker](./docker.md) +* [Python Development Notes](pyhton.md) ## Reference diff --git a/documentation/developers/development-environment.md b/documentation/developers/development-environment.md index d79a6101e..9abefbee0 100644 --- a/documentation/developers/development-environment.md +++ b/documentation/developers/development-environment.md @@ -1,30 +1,30 @@ # Development Environment -You have 3 development options: -## Directly on Raspberry Pi -The full setup is running on the RPi and you access files via SSH. -Pretty easy to set up as you simply do a normal install and switch to -the `future3/develop` branch. +You have 3 development options. Each option has its pros and cons. To interact with GPIO or other hardware, it's required to develop directly on a Raspberry Pi. For general development of Python code (Jukebox) or JavaScript (Webapp), we recommend Docker. Developing on your local machine (Linux, Mac, Windows) works as well and requires all dependencies to be installed locally. + +* [Develop in Docker](#develop-in-docker) +* [Develop on Raspberry Pi](#develop-on-raspberry-pi) +* [Develop on local machine](#develop-on-local-machine) + +## Develop in Docker + +There is a complete [Docker setup](./docker.md). + +## Develop on Raspberry Pi + +The full setup is running on the RPi and you access files via SSH. Pretty easy to set up as you simply do a normal install and switch to the `future3/develop` branch. ### Steps to install -We recommend to use at least a Pi 3 or Pi Zero 2 for development. This -hardware won\'t be needed in production, but it can be slow while -developing. +We recommend to use at least a Pi 3 or Pi Zero 2 for development. This hardware won\'t be needed in production, but it can be slow while developing. 1. Install the latest Pi OS on a SD card. 2. Boot up your Raspberry Pi. -3. [Install](../builders/installation.md) the Jukebox software as if you were building a - Phoniebox. You can install from your own fork and feature branch if - you wish which can be changed later as well. The original repository - will be set as `upstream`. +3. [Install](../builders/installation.md) the Jukebox software as if you were building a Phoniebox. You can install from your own fork and feature branch you wish which can be changed later as well. The original repository will be set as `upstream`. 4. Once the installation has successfully ran, reboot your Pi. -5. Due to some resource constraints, the Webapp does not build the - latest changes and instead consumes the latest official release. To - change that, you need to install NodeJS and build the Webapp - locally. +5. Due to some resource constraints, the Webapp does not build the latest changes and instead consumes the latest official release. To change that, you need to install NodeJS and build the Webapp locally. 6. Install NodeJS using the existing installer ``` bash @@ -34,8 +34,7 @@ developing. ``` 7. To free up RAM, reboot your Pi. -8. Build the Webapp using the existing build command. If the build - fails, you might have forgotten to reboot. +8. Build the Webapp using the existing build command. If the build fails, you might have forgotten to reboot. ``` bash cd ~/RPi-Jukebox-RFID/src/webapp; \ @@ -43,30 +42,16 @@ developing. ``` 9. The Webapp should now be updated. -10. To continuously update Webapp, pull the latest changes from your - repository and rerun the command above. +10. To continuously update Webapp, pull the latest changes from your repository and rerun the command above. -## Locally on any Linux machine +## Develop on local machine -The jukebox also runs on any Linux machine. The Raspberry Pi specific -stuff will not work of course. That is no issue depending our your -development area. USB RFID Readers, however, will work. You will have -to install and configure [MPD (Music Player -Daemon)](https://www.musicpd.org/). +The jukebox also runs on any Linux machine. The Raspberry Pi specific stuff will not work of course. That is no issue depending our your development area. USB RFID Readers, however, will work. You will have to install and configure [MPD (Music Player Daemon)](https://www.musicpd.org/). -In addition to the `requirements.txt`, you will this -dependency. On the Raspberry PI, the latest stable release of ZMQ does -not support WebSockets. We need to compile the latest version from -Github, which is taken care of by the installation script. For regular -machines, the normal package can be installed: +In addition to the `requirements.txt`, you will this dependency. On the Raspberry PI, the latest stable release of ZMQ does not support WebSockets. We need to compile the latest version from Github, which is taken care of by the installation script. For regular machines, the normal package can be installed: ``` bash pip install pyzmq ``` -You will have to start Jukebox core application and the WebUI -separately. The MPD usually runs as a service. - -## Using Docker container - -There is a complete [Docker setup](./docker.md). +You will have to start Jukebox core application and the WebUI separately. The MPD usually runs as a service. diff --git a/documentation/developers/pyhton.md b/documentation/developers/pyhton.md new file mode 100644 index 000000000..e9a071e34 --- /dev/null +++ b/documentation/developers/pyhton.md @@ -0,0 +1,18 @@ +# Python Development Notes + +## Prerequisites + +> [!NOTE] +> All Python scripts must be run within a [virtual environment](https://docs.python.org/3/library/venv.html) (`.venv`). All Python plugins are installed encapsulated within this environment. + +Before you can run Python code, you need to enable the virtual environment. On the Raspberry Pi, it's located in the project root `~/RPi-Jukebox-RFID/.venv`. Depending on your setup, the absolute path can vary. + +``` +$ ~/RPi-Jukebox-RFID/.venv/bin/activate +``` + +If the virtual environment has been activated correctly, your terminal will now show a prefix (`.venv`). If you want to leave the venv again execute deactivate. + +``` +$ ~/RPi-Jukebox-RFID/.venv/bin/deactivate +``` From dd7f6e943903162b816336eaf0c7496240a13273 Mon Sep 17 00:00:00 2001 From: s-martin Date: Mon, 11 Dec 2023 00:10:13 +0100 Subject: [PATCH 23/28] Add running pytest to GitHub action (#2146) * Add running pytest * Trigger running the action * Remove Python 3.7 to check * support only bullseye and bookworm python versions * Add coverage check with coveralls * use coverage for ci * add coverage package * consider review comments --- .flake8 | 2 +- .github/workflows/pythonpackage_future3.yml | 23 ++++++++++++++++++--- requirements.txt | 1 + run_pytest.sh | 2 +- src/jukebox/misc/loggingext.py | 1 + 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.flake8 b/.flake8 index d11edbe8a..0c2cd276e 100644 --- a/.flake8 +++ b/.flake8 @@ -15,7 +15,7 @@ per-file-ignores = count = True max-complexity = 12 statistics = True -filename = *.py,*.py.* +filename = *.py extend-exclude = # Ignore all scratch development directories scratch*, diff --git a/.github/workflows/pythonpackage_future3.yml b/.github/workflows/pythonpackage_future3.yml index 48e27b15d..3834d83db 100644 --- a/.github/workflows/pythonpackage_future3.yml +++ b/.github/workflows/pythonpackage_future3.yml @@ -6,13 +6,11 @@ on: - 'future3/**' paths: - '**.py' - - '**.py.*' pull_request: branches: - 'future3/**' paths: - '**.py' - - '**.py.*' jobs: build: @@ -21,7 +19,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11'] steps: - uses: actions/checkout@v3 @@ -41,8 +39,27 @@ jobs: pip3 install -r src/jukebox/components/rfid/hardware/pn532_i2c_py532/requirements.txt pip3 install -r src/jukebox/components/rfid/hardware/rdm6300_serial/requirements.txt pip3 install -r src/jukebox/components/rfid/hardware/rc522_spi/requirements.txt + - name: Run pytest + run: | + ./run_pytest.sh --cov --cov-report xml + - name: Report to Coveralls (parallel) + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + file: coverage.xml + format: cobertura + parallel: true - name: Lint with flake8 run: | pip3 install flake8 # Stop the build if linting fails ./run_flake8.sh + + finish: + needs: build + runs-on: ubuntu-latest + steps: + - name: Close parallel build + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true diff --git a/requirements.txt b/requirements.txt index 0f8c8c86d..bd2ea6651 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,4 +31,5 @@ gpiozero # Code quality flake8>=4.0.0 pytest +pytest-cov mock diff --git a/run_pytest.sh b/run_pytest.sh index a3cbd8df6..766f05182 100755 --- a/run_pytest.sh +++ b/run_pytest.sh @@ -10,4 +10,4 @@ SCRIPT_DIR="$(dirname "$SOURCE")" cd "$SCRIPT_DIR" || (echo "Could not change to top-level project directory" && exit 1) # Run pytest -pytest -c pytest.ini +pytest -c pytest.ini $@ diff --git a/src/jukebox/misc/loggingext.py b/src/jukebox/misc/loggingext.py index 9328cfea8..771248d8f 100644 --- a/src/jukebox/misc/loggingext.py +++ b/src/jukebox/misc/loggingext.py @@ -1,6 +1,7 @@ """ ############## Logger + ############## We use a hierarchical Logger structure based on pythons logging module. It can be finely configured with a yaml file. From afc30671f509aa333393ef3161845bbaa56ad35b Mon Sep 17 00:00:00 2001 From: ben0r33 <72662304+ben0r33@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:52:57 +0100 Subject: [PATCH 24/28] [Bugfix] setup_autohotspot.sh for multiple wifi country codes, use first (#2150) --- installation/routines/setup_autohotspot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installation/routines/setup_autohotspot.sh b/installation/routines/setup_autohotspot.sh index cc40b7794..a083b3fcf 100644 --- a/installation/routines/setup_autohotspot.sh +++ b/installation/routines/setup_autohotspot.sh @@ -14,7 +14,7 @@ AUTOHOTSPOT_TARGET_PATH="/usr/bin/autohotspot" _get_interface() { # interfaces may vary WIFI_INTERFACE=$(iw dev | grep "Interface"| awk '{ print $2 }') - WIFI_REGION=$(iw reg get | grep country | awk '{ print $2}' | cut -d: -f1) + WIFI_REGION=$(iw reg get | grep country | head -n 1 | awk '{ print $2}' | cut -d: -f1) # fix for CI runs on docker if [ "${CI_RUNNING}" == "true" ]; then From bd345213496bd2288b3feb86d71e7c4d215464f7 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:07:55 +0100 Subject: [PATCH 25/28] some documentation updates (#2151) harmonize paths updated doc for coreapps and references fix execution docs for run_jukebox.py --- documentation/builders/audio.md | 14 +++--- documentation/builders/concepts.md | 4 +- documentation/builders/configuration.md | 10 +++-- documentation/builders/rpc-commands.md | 2 +- documentation/builders/system.md | 4 +- documentation/builders/troubleshooting.md | 18 ++++---- documentation/builders/update.md | 6 +++ documentation/developers/coreapps.md | 43 ++++++++----------- documentation/developers/developer-issues.md | 1 + documentation/developers/docker.md | 2 +- documentation/developers/rfid/basics.md | 5 +-- documentation/developers/rfid/genericusb.md | 2 +- documentation/developers/rfid/mfrc522_spi.md | 2 +- .../developers/rfid/template_reader.md | 4 +- .../default-settings/jukebox.default.yaml | 2 +- .../hardware/fake_reader_gui/requirements.txt | 1 + .../hardware/pn532_i2c_py532/requirements.txt | 1 + .../hardware/rdm6300_serial/requirements.txt | 3 ++ 18 files changed, 65 insertions(+), 59 deletions(-) diff --git a/documentation/builders/audio.md b/documentation/builders/audio.md index 07d24e40f..0bb5a7163 100644 --- a/documentation/builders/audio.md +++ b/documentation/builders/audio.md @@ -10,14 +10,14 @@ Stream transfer happens on user input or automatically on the connection of an a This is mainly targeted at Bluetooth Headsets/Speakers. Audio outputs run via PulseAudio and the basic configuration should be easy. -There is a [configuration tool](../developers/coreapps.md#run_configure_audio.py), +There is a [configuration tool](../developers/coreapps.md#Audio), to setup the configuration for the Jukebox Core App. To set up the audio 1. Follow the setup steps according to your sound card 2. Check that the sound output works [as described below](audio.md#checking-system-sound-output) -3. Run the the tool [run_configure_audio](../developers/coreapps.md#run_configure_audio.py) +3. Run the [audio configuration tool](../developers/coreapps.md#Audio) 4. [Fine-tune audio parameters](audio.md#additional-options) ## Checking system sound output @@ -31,7 +31,7 @@ $ pactl list sinks short 1 bluez_sink.C4_FB_20_63_CO_FE.a2dp_sink module-bluez5-device.c s16le 2ch 44100Hz # Set the default sink (this will be reset at reboot) -$ pactl set-default-sink sink_name +$ pactl set-default-sink # Check default sink is correctly set $ pactl info @@ -50,7 +50,7 @@ You can also try different PulseAudio sinks without setting the default sink. In volume level for this sink: ```bash -$ paplay -d sink_name /usr/share/sounds/alsa/Front_Center.wav +$ paplay -d /usr/share/sounds/alsa/Front_Center.wav ``` # Bluetooth @@ -134,8 +134,4 @@ You are, of course, free to modify the PulseAudio configuration to your needs. R 1. [PulseAudio Documentation](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User) 2. [PulseAudio Examples](https://wiki.archlinux.org/title/PulseAudio/Examples) -In this case, run the configuration tool with below parameter to avoid touching the PulseAudio configuration file. - -```bash -$ ./run_configure_audio.py --ro_pulse -``` +In this case, run the [audio configuration tool](../developers/coreapps.md#Audio) with the parameter `--ro_pulse` to avoid touching the PulseAudio configuration file. diff --git a/documentation/builders/concepts.md b/documentation/builders/concepts.md index c08a33caa..37c13db89 100644 --- a/documentation/builders/concepts.md +++ b/documentation/builders/concepts.md @@ -16,10 +16,10 @@ The Remote Procedure Call (RPC) server allows remotely triggering actions (e.g., Why should you care? Because we use the same protocol when triggering actions from other inputs like a card swipe, a GPIO button press, etc. How that works is described in [RPC Commands](rpc-commands.md). -We also have a tool to send RPC commands to the running Jukebox application: [run_rpc_tool.py](../developers/coreapps.md#run_rpc_toolpy) +We also have a [tool to send RPC commands](../developers/coreapps.md#RPC) to the running Jukebox application. ## Publishing Message Queue The Publishing Message Queue is the complementary part to the RPC where the core application publishes its status and status updates. As a user, you need not worry about it. -If you want to interact with the Jukebox from your own application, this is where you get the current state from. Details about the protocol can be found here (TBD). A sniffer tool exists which listens and prints the incoming status messages: [run_publicity_sniffer.py](../developers/coreapps.md#run_publicity_snifferpy). +If you want to interact with the Jukebox from your own application, this is where you get the current state from. Details about the protocol can be found here (TBD). A [sniffer tool](../developers/coreapps.md#Publicity-Sniffer) exists which listens and prints the incoming status messages. diff --git a/documentation/builders/configuration.md b/documentation/builders/configuration.md index e0240ddbe..f09e8098d 100644 --- a/documentation/builders/configuration.md +++ b/documentation/builders/configuration.md @@ -1,13 +1,13 @@ # Jukebox Configuration -The Jukebox configuration is managed by set of files located in `../shared/settings`. +The Jukebox configuration is managed by a set of files located in `shared/settings`. Some configuration changes can be made through the WebUI and take immediate effect. The majority of configuration options is only available by editing the config files - *when the service is not running!* Don't fear (overly), they contain commentaries. -For several aspects we have :ref:`developer/coreapps:Configuration Tools` and detailed guides: +For several aspects we have [configuration tools](../developers/coreapps.md#configuration-tools) and detailed guides: * [Audio Configuration](./audio.md#audio-configuration) * [RFID Reader Configuration](../developers/rfid/basics.md#reader-configuration) @@ -24,7 +24,8 @@ $ systemctl --user stop jukebox-daemon $ nano ./shared/settings/jukebox.yaml # Start Jukebox in console and check the log output (optional) -$ ./src/jukebox/run_jukebox.py +$ cd src/jukebox +$ ./run_jukebox.py # and if OK, press Ctrl-C and restart the service # Restart the service @@ -36,5 +37,6 @@ This could be useful if you want your Jukebox to only allow a lower volume when at night time when there is time to go to bed :-) ```bash -$./run_jukebox.py --conf ../path/to/custom/config.yaml +$ cd src/jukebox +$ ./run_jukebox.py --conf path/to/custom/config.yaml ``` diff --git a/documentation/builders/rpc-commands.md b/documentation/builders/rpc-commands.md index f578ccd99..f98da8cb4 100644 --- a/documentation/builders/rpc-commands.md +++ b/documentation/builders/rpc-commands.md @@ -107,6 +107,6 @@ You will find some more examples the configuration of the [Card Database](card-d ## For developers -To send RPC commands for testing and debugging purpose you can use the CLI Tool [`run_rpc_tool.py`](../developers/coreapps.md#run_rpc_toolpy) +To send RPC commands for testing and debugging purpose you can use the [CLI Tool](../developers/coreapps.md#RPC). Also here is a ready-to-use decoding functions which decodes an RPC command (with or without alias) from a YAML entry:func:`jukebox.utils.decode_rpc_command`. diff --git a/documentation/builders/system.md b/documentation/builders/system.md index 873d489f6..0e2c19485 100644 --- a/documentation/builders/system.md +++ b/documentation/builders/system.md @@ -70,7 +70,7 @@ Service control and service configuration file location is identical to MPD. ## Jukebox Core Service -The :ref:`developer/coreapps:Jukebox Core` runs as a *user-local* service with the name `jukebox-daemon`. +The [Jukebox Core Service](../developers/coreapps.md#Jukebox-Core) runs as a *user-local* service with the name `jukebox-daemon`. Similar to MPD, it's important that it does run as system-wide service to be able to interact with PulseAudio. The service can be controlled with the `systemctl`-command by adding the parameter `--user` @@ -101,7 +101,7 @@ Starting and stopping the service can be useful for debugging or configuration c The Web UI is served using nginx. Nginx runs as a system service. The home directory is localed at ``` -~/RPi-Jukebox-RFID/src/webapp/build +./src/webapp/build ``` The Nginx configuration is located at diff --git a/documentation/builders/troubleshooting.md b/documentation/builders/troubleshooting.md index a0618ab5d..a83384ec5 100644 --- a/documentation/builders/troubleshooting.md +++ b/documentation/builders/troubleshooting.md @@ -15,8 +15,8 @@ Debugging your setup runs in several steps ## The short answer ```bash -../shared/logs/app.log : Complete Debug Messages -../shared/logs/errors.log: Only Errors and Warnings +shared/logs/app.log : Complete Debug Messages +shared/logs/errors.log: Only Errors and Warnings ``` These files always contain the messages of the current run only. @@ -33,9 +33,9 @@ http://ip.of.your.box/logs ## The long answer: A few more details -If started without parameters, the Jukebox checks for the existence of `../shared/settings/logger.yaml` +If started without parameters, the Jukebox checks for the existence of `shared/settings/logger.yaml` and if present, uses that configuration for logging. This file is created by the installation process. -The default configuration file is also provided in `../resources/default-settings/logger.default.yaml`. +The default configuration file is also provided in `resources/default-settings/logger.default.yaml`. We use Python's logging module to provide the debug messages which is configured through this file. **We are still in the Pre-Release phase which means full debug logging is enabled by default.** @@ -47,8 +47,8 @@ The default logging config does 2 things: 1. It writes 2 log files: ```bash -../shared/logs/app.log : Complete Debug Messages -../shared/logs/errors.log : Only Errors and Warnings +shared/logs/app.log : Complete Debug Messages +shared/logs/errors.log : Only Errors and Warnings ``` 2. Prints logging messages to the console. If run as a service, only error messages are emitted to console to avoid spamming the system log files. @@ -63,11 +63,12 @@ on the console log. $ systemctl --user stop jukebox-daemon # Start the Jukebox in debug mode: +$ cd src/jukebox + # with default logger: $ ./run_jukebox.py - # or with custom logger configuration: -$ ./run_jukebox.py --logger ../path/to/logger.yaml +$ ./run_jukebox.py --logger path/to/custom/logger.yaml ``` ### Fallback configuration @@ -77,6 +78,7 @@ Attention: This only emits messages to the console and does not write to the log This is more a fallback features: ``` bash +$ cd src/jukebox $ ./run_jukebox.py -vv ``` diff --git a/documentation/builders/update.md b/documentation/builders/update.md index e09137ca3..f6dab2c91 100644 --- a/documentation/builders/update.md +++ b/documentation/builders/update.md @@ -2,6 +2,12 @@ ## Updating your Jukebox Version 3 +### Update from v3.2.1 and prior + +As there are some significant changes in the installation, a new setup on a fresh image is required. + +### General + Things on Version 3 are moving fast and you may want to keep up with recent changes. Since we are in Alpha Release stage, a fair number of fixes are expected to be committed in the near future. diff --git a/documentation/developers/coreapps.md b/documentation/developers/coreapps.md index 2fa8b84e9..3e4fc7b1f 100644 --- a/documentation/developers/coreapps.md +++ b/documentation/developers/coreapps.md @@ -4,14 +4,14 @@ The Jukebox\'s core apps are located in `src/jukebox`. Run the following command to learn more about each app and its parameters: ``` bash -$ ./run_app_name.py -h +$ cd src/jukebox +$ ./ -h ``` -## Jukebox Core -### `run_jukebox.py` +## Jukebox Core -[run_jukebox.py](../../src/jukebox/run_jukebox.py) +**Scriptname:** [run_jukebox.py](../../src/jukebox/run_jukebox.py) This is the main app and starts the Jukebox Core. @@ -19,49 +19,44 @@ Usually this runs as a service, which is started automatically after boot-up. At For debugging, it is usually desirable to run the Jukebox directly from the console rather than as service. This gives direct logging info in the console and allows changing command line parameters. See [Troubleshooting](../builders/troubleshooting.md). + ## Configuration Tools Before running the configuration tools, stop the Jukebox Core service. See [Best practice procedure](../builders/configuration.md#best-practice-procedure). -### `run_configure_audio.py` - -[run_configure_audio.py](../../src/jukebox/run_configure_audio.py) +### Audio -Setup tool to register the PulseAudio sinks as primary and secondary audio outputs. +**Scriptname:** [run_configure_audio.py](../../src/jukebox/run_configure_audio.py) -Will also setup equalizer and mono down mixer in the pulseaudio config file. +Setup tool to register the PulseAudio sinks as primary and secondary audio outputs. -Run this once after installation. Can be re-run at any time to change the settings. For more information see [Audio Configuration](../builders/audio.md). +Will also setup equalizer and mono down mixer in the pulseaudio config file. Run this once after installation. Can be re-run at any time to change the settings. For more information see [Audio Configuration](../builders/audio.md). -### `run_register_rfid_reader.py` +### RFID Reader -[run_register_rfid_reader.py](../../src/jukebox/run_register_rfid_reader.py) +**Scriptname:** [run_register_rfid_reader.py](../../src/jukebox/run_register_rfid_reader.py) -Setup tool to configure the RFID Readers. +Setup tool to configure the RFID Readers. Run this once to register and configure the RFID readers with the Jukebox. Can be re-run at any time to change the settings. For more information see [RFID Readers](./rfid/README.md). > [!NOTE] > This tool will always write a new configurations file. Thus, overwrite the old one (after checking with the user). Any manual modifications to the settings will have to be re-applied -## Developer Tools - -### `run_rpc_tool.py` -[run_rpc_tool.py](../../src/jukebox/run_rpc_tool.py) - -Command Line Interface to the Jukebox RPC Server. +## Developer Tools -A command line tool for sending RPC commands to the running jukebox app. This uses the same interface as the WebUI. Can be used for additional control or for debugging. +### RPC -The tool features auto-completion and command history. +**Scriptname:** [run_rpc_tool.py](../../src/jukebox/run_rpc_tool.py) -The list of available commands is fetched from the running Jukebox service. +Command Line Interface to the Jukebox RPC Server. +A command line tool for sending RPC commands to the running jukebox app. This uses the same interface as the WebUI. Can be used for additional control or for debugging.The tool features auto-completion and command history. The list of available commands is fetched from the running Jukebox service. -### `run_publicity_sniffer.py` +### Publicity Sniffer - [run_publicity_sniffer.py](../../src/jukebox/run_publicity_sniffer.py) +**Scriptname:** [run_publicity_sniffer.py](../../src/jukebox/run_publicity_sniffer.py) A command line tool that monitors all messages being sent out from the Jukebox via the publishing interface. Received messages are printed in the console. Mainly used for debugging. diff --git a/documentation/developers/developer-issues.md b/documentation/developers/developer-issues.md index 1ed531738..c8dd3b6c3 100644 --- a/documentation/developers/developer-issues.md +++ b/documentation/developers/developer-issues.md @@ -46,6 +46,7 @@ Alternatively, use the provided script, which sets the variable for you (provided your swap size is large enough): ``` bash +$ cd src/webapp $ ./run_rebuild.sh ``` diff --git a/documentation/developers/docker.md b/documentation/developers/docker.md index 96b5a64b6..39518e248 100644 --- a/documentation/developers/docker.md +++ b/documentation/developers/docker.md @@ -33,7 +33,7 @@ need to adapt some of those commands to your needs. * Override/Merge the values from the following [Override file](https://github.com/MiczFlor/RPi-Jukebox-RFID/blob/future3/develop/docker/config/jukebox.overrides.yaml) in your `jukebox.yaml`. * **\[Currently required\]** Update all relative paths (`../..`) in to `/home/pi/RPi-Jukebox-RFID`. -4. Change directory into the `./RPi-Jukebox-RFID/shared/audiofolders` +4. Change directory into the `./shared/audiofolders` and copy a set of MP3 files into this folder (for more fun when testing). diff --git a/documentation/developers/rfid/basics.md b/documentation/developers/rfid/basics.md index 7a5aa37d9..7d557ed06 100644 --- a/documentation/developers/rfid/basics.md +++ b/documentation/developers/rfid/basics.md @@ -35,8 +35,7 @@ Readers operate on one of two different frequencies: 125kHz or 13.56 MHz. Make s ## Reader Configuration During the installation process, you can already configure a RFID -reader. To manually configure RFID reader(s), -[please run the tool](../coreapps.md#run_register_rfid_reader.py), (`src/jukebox/run_register_rfid_reader.py`). +reader. To manually configure RFID reader(s) run the [RFID reader configuration tool](../coreapps.md#RFID-Reader). It will generate a reader configuration file at `shared/settings/rfid.yaml`. You can re-run the tool to change the @@ -67,7 +66,7 @@ Indicates the Python package used for this reader. Filled by the RFID configurat #### config: -Filled by the [RFID configuration tool](../coreapps.md#run_register_rfid_reader.py) (`src/jukebox/run_register_rfid_reader.py`) based on default values and user input. After running the tool, you may manually change some settings here, as not everything can be configured through the tool. Note that re-running the tool will completely rewrite the configuration file. +Filled by the [RFID reader configuration tool](../coreapps.md#RFID-Reader) based on default values and user input. After running the tool, you may manually change some settings here, as not everything can be configured through the tool. Note that re-running the tool will completely rewrite the configuration file. #### same_id_delay: float \| integer diff --git a/documentation/developers/rfid/genericusb.md b/documentation/developers/rfid/genericusb.md index 23975cf14..544f0245c 100644 --- a/documentation/developers/rfid/genericusb.md +++ b/documentation/developers/rfid/genericusb.md @@ -4,7 +4,7 @@ This module covers all types of USB-based RFID input readers. If you plan to connect multiple USB-based RFID readers to the Jukebox, make -sure to connect all of them before running the registration tool [run_register_rfid_reader.py](../coreapps.md#run_register_rfid_readerpy). +sure to connect all of them before running the [RFID reader configuration tool](../coreapps.md#RFID-Reader). > [!NOTE] > The user needs to be part of the group \'input\' for evdev to work. This should usually be the case. However, a user can be added with: diff --git a/documentation/developers/rfid/mfrc522_spi.md b/documentation/developers/rfid/mfrc522_spi.md index f7710b2b1..5dc46aab6 100644 --- a/documentation/developers/rfid/mfrc522_spi.md +++ b/documentation/developers/rfid/mfrc522_spi.md @@ -6,7 +6,7 @@ RC522 RFID reader via SPI connection. ## Installation -Run the [run_register_rfid_reader.py](../coreapps.md#run_register_rfid_reader.py) tool for guided +Run the [RFID reader configuration tool](../coreapps.md#RFID-Reader) for guided installation. ## Options diff --git a/documentation/developers/rfid/template_reader.md b/documentation/developers/rfid/template_reader.md index 0f4c3e939..6a7a8b0c3 100644 --- a/documentation/developers/rfid/template_reader.md +++ b/documentation/developers/rfid/template_reader.md @@ -9,9 +9,9 @@ This template provides the skeleton API for a new Reader. If you follow the conventions outlined below, your new reader will be picked up automatically There is no extra need to register the reader module with -the Phoniebox. Just re-run `the reader config tool `. +the Phoniebox. Just re-run [RFID reader configuration tool](../coreapps.md#RFID-Reader). -Follow the instructions in [template_new_reader.py] +Follow the instructions in [template_new_reader.py](../../../src/jukebox/components/rfid/hardware/template_new_reader/template_new_reader.py) Also have a look at the other reader subpackages to see how stuff works with an example diff --git a/resources/default-settings/jukebox.default.yaml b/resources/default-settings/jukebox.default.yaml index 91ada74c6..36661c992 100644 --- a/resources/default-settings/jukebox.default.yaml +++ b/resources/default-settings/jukebox.default.yaml @@ -30,7 +30,7 @@ pulse: toggle_on_connect: true # Limit maximum volume range to XX % - can be changed through the UI (for temporary use) soft_max_volume: 70 - # Run the tool run_configure_audio.py to configure the pulseaudio sinks + # Run the audio configuration tool to configure the pulseaudio sinks # # After startup, the audio output defaults to primary # Any Bluetooth device should be the secondary (as it may not always be available directly after boot) diff --git a/src/jukebox/components/rfid/hardware/fake_reader_gui/requirements.txt b/src/jukebox/components/rfid/hardware/fake_reader_gui/requirements.txt index 931c9db0f..937256e86 100644 --- a/src/jukebox/components/rfid/hardware/fake_reader_gui/requirements.txt +++ b/src/jukebox/components/rfid/hardware/fake_reader_gui/requirements.txt @@ -1,5 +1,6 @@ # This GUI-based mock reader also requires: tkinter # tkinter is a standard Python package and needs not be installed separately # It is available on most Unix systems (but not on headless Raspbian RPi where running a GUI is difficult anyway) +# You need to install these with `python -m pip install --upgrade --force-reinstall -q -r requirements.txt` ttkthemes diff --git a/src/jukebox/components/rfid/hardware/pn532_i2c_py532/requirements.txt b/src/jukebox/components/rfid/hardware/pn532_i2c_py532/requirements.txt index 9b156854b..f7fe9563f 100644 --- a/src/jukebox/components/rfid/hardware/pn532_i2c_py532/requirements.txt +++ b/src/jukebox/components/rfid/hardware/pn532_i2c_py532/requirements.txt @@ -1,3 +1,4 @@ # PN532 related requirements # You need to install these with `python -m pip install --upgrade --force-reinstall -q -r requirements.txt` + py532lib diff --git a/src/jukebox/components/rfid/hardware/rdm6300_serial/requirements.txt b/src/jukebox/components/rfid/hardware/rdm6300_serial/requirements.txt index f6c1a1f57..df92852d9 100644 --- a/src/jukebox/components/rfid/hardware/rdm6300_serial/requirements.txt +++ b/src/jukebox/components/rfid/hardware/rdm6300_serial/requirements.txt @@ -1 +1,4 @@ +# RDM6300 related requirements +# You need to install these with `python -m pip install --upgrade --force-reinstall -q -r requirements.txt` + pyserial From 50e8446bdff37ab87faadf3938eef0413df89946 Mon Sep 17 00:00:00 2001 From: pabera <1260686+pabera@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:03:28 +0100 Subject: [PATCH 26/28] Better logging functions for Installation script (#2152) * Introduce proper logging functions * Fix a few minor things * Introduce clear_c * A few minor bugfixes * Introduce run_and_log() function * Rename function to run_and_print_lc * Log IP address if static is chosen * Revert "Log IP address if static is chosen" This reverts commit 8852d97b4b11b3eb34781db5b8da32d405a4183a. * Update commit for run_and_print_lc --- installation/README.md | 9 +- installation/includes/02_helpers.sh | 68 +++++------ installation/includes/03_welcome.sh | 10 +- installation/includes/05_finish.sh | 14 +-- installation/install-jukebox.sh | 114 ++++++++++-------- installation/routines/customize_options.sh | 113 ++++++++--------- installation/routines/install.sh | 4 +- installation/routines/optimize_boot_time.sh | 30 ++--- installation/routines/set_raspi_config.sh | 12 +- installation/routines/set_ssh_qos.sh | 2 +- installation/routines/setup_git.sh | 76 ++++++------ installation/routines/setup_jukebox_core.sh | 22 ++-- installation/routines/setup_jukebox_webapp.sh | 12 +- installation/routines/setup_kiosk_mode.sh | 4 +- installation/routines/setup_mpd.sh | 8 +- installation/routines/setup_rfid_reader.sh | 2 +- installation/routines/setup_samba.sh | 6 +- 17 files changed, 261 insertions(+), 245 deletions(-) diff --git a/installation/README.md b/installation/README.md index b2a496348..178f1b7be 100644 --- a/installation/README.md +++ b/installation/README.md @@ -3,10 +3,11 @@ ## Logging - Bash Script output rules ```bash -Output to both console and logfile: "$ command | tee /dev/fd/3" -Output to console only "$ command 1>&3" -Output to logfile only: "$ command" -No output to both console and logfile: "$ command > /dev/null" +run_and_print_lc "Run a command and log its output to both console and logfile" +print_lc "This message will be logged to both console and logfile" +print_c "This message will only be logged to the console" +log "This message will only be logged to the logfile" +clear_c "Clears the console screen" ``` [Learn more about bash script outputs](https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console) diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index a8deca9c3..7520241c6 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -17,21 +17,21 @@ run_with_timer() { $1; # Executes the function passed as an argument - calc_runtime_and_print time_start $(date +%s) | tee /dev/fd/3 + run_and_print_lc calc_runtime_and_print time_start $(date +%s) } run_with_log_frame() { local time_start=$(date +%s); local description="$2" - echo -e "\n\n" - echo "#########################################################" - echo "${description}" | tee /dev/fd/3 + log "\n\n" + log "#########################################################" + print_lc "${description}" $1; # Executes the function passed as an argument local done_in=$(calc_runtime_and_print time_start $(date +%s)) - echo -e "\n${done_in} - ${description}" - echo "#########################################################" + log "\n${done_in} - ${description}" + log "#########################################################" } get_architecture() { @@ -69,16 +69,16 @@ get_version_string() { ### Verify helpers print_verify_installation() { - echo "" - echo " -------------------------------------------------------" - echo " Check installation" - echo "" + log "\n + ------------------------------------------------------- + Check installation +" } # Check if the file(s) exists verify_files_exists() { local files="$@" - echo " Verify '${files}' exists" + log " Verify '${files}' exists" if [[ -z "${files}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -88,13 +88,13 @@ verify_files_exists() { do test ! -f ${file} && exit_on_error "ERROR: '${file}' does not exists or is not a file!" done - echo " CHECK" + log " CHECK" } # Check if the dir(s) exists verify_dirs_exists() { local dirs="$@" - echo " Verify '${dirs}' exists" + log " Verify '${dirs}' exists" if [[ -z "${dirs}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -104,7 +104,7 @@ verify_dirs_exists() { do test ! -d ${dir} && exit_on_error "ERROR: '${dir}' does not exists or is not a dir!" done - echo " CHECK" + log " CHECK" } # Check if the file(s) has/have the expected owner and modifications @@ -113,7 +113,7 @@ verify_files_chmod_chown() { local user_expected=$2 local group_expected=$3 local files="${@:4}" - echo " Verify '${mod_expected}' '${user_expected}:${group_expected}' is set for '${files}'" + log " Verify '${mod_expected}' '${user_expected}:${group_expected}' is set for '${files}'" if [[ -z "${mod_expected}" || -z "${user_expected}" || -z "${group_expected}" || -z "${files}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -130,7 +130,7 @@ verify_files_chmod_chown() { test ! "${user_expected}" == "${user_actual}" && exit_on_error "ERROR: '${file}' actual owner '${user_actual}' differs from expected '${user_expected}'!" test ! "${group_expected}" == "${group_actual}" && exit_on_error "ERROR: '${file}' actual group '${group_actual}' differs from expected '${group_expected}'!" done - echo " CHECK" + log " CHECK" } # Check if the dir(s) has/have the expected owner and modifications @@ -139,7 +139,7 @@ verify_dirs_chmod_chown() { local user_expected=$2 local group_expected=$3 local dirs="${@:4}" - echo " Verify '${mod_expected}' '${user_expected}:${group_expected}' is set for '${dirs}'" + log " Verify '${mod_expected}' '${user_expected}:${group_expected}' is set for '${dirs}'" if [[ -z "${mod_expected}" || -z "${user_expected}" || -z "${group_expected}" || -z "${dirs}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -156,13 +156,13 @@ verify_dirs_chmod_chown() { test ! "${user_expected}" == "${user_actual}" && exit_on_error "ERROR: '${dir}' actual owner '${user_actual}' differs from expected '${user_expected}'!" test ! "${group_expected}" == "${group_actual}" && exit_on_error "ERROR: '${dir}' actual group '${group_actual}' differs from expected '${group_expected}'!" done - echo " CHECK" + log " CHECK" } verify_file_contains_string() { local string="$1" local file="$2" - echo " Verify '${string}' found in '${file}'" + log " Verify '${string}' found in '${file}'" if [[ -z "${string}" || -z "${file}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -171,13 +171,13 @@ verify_file_contains_string() { if [[ ! $(grep -iw "${string}" "${file}") ]]; then exit_on_error "ERROR: '${string}' not found in '${file}'" fi - echo " CHECK" + log " CHECK" } verify_file_contains_string_once() { local string="$1" local file="$2" - echo " Verify '${string}' found in '${file}'" + log " Verify '${string}' found in '${file}'" if [[ -z "${string}" || -z "${file}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -189,14 +189,14 @@ verify_file_contains_string_once() { elif [ "$file_contains_string_count" -gt 1 ]; then exit_on_error "ERROR: '${string}' found more than once in '${file}'" fi - echo " CHECK" + log " CHECK" } verify_service_state() { local service="$1" local desired_state="$2" local option="${3:+$3 }" # optional, dont't quote in next call! - echo " Verify service '${option}${service}' is '${desired_state}'" + log " Verify service '${option}${service}' is '${desired_state}'" if [[ -z "${service}" || -z "${desired_state}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -206,14 +206,14 @@ verify_service_state() { if [[ ! "${actual_state}" == "${desired_state}" ]]; then exit_on_error "ERROR: service '${option}${service}' is not '${desired_state}' (state: '${actual_state}')." fi - echo " CHECK" + log " CHECK" } verify_service_enablement() { local service="$1" local desired_enablement="$2" local option="${3:+$3 }" # optional, dont't quote in next call! - echo " Verify service ${option}${service} is ${desired_enablement}" + log " Verify service ${option}${service} is ${desired_enablement}" if [[ -z "${service}" || -z "${desired_enablement}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -223,14 +223,14 @@ verify_service_enablement() { if [[ ! "${actual_enablement}" == "${desired_enablement}" ]]; then exit_on_error "ERROR: service ${option}${service} is not ${desired_enablement} (state: ${actual_enablement})." fi - echo " CHECK" + log " CHECK" } verify_optional_service_enablement() { local service="$1" local desired_enablement="$2" local option="${3:+$3 }" # optional, dont't quote in next call! - echo " Verify service ${option}${service} is ${desired_enablement}" + log " Verify service ${option}${service} is ${desired_enablement}" if [[ -z "${service}" || -z "${desired_enablement}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -238,13 +238,13 @@ verify_optional_service_enablement() { local actual_enablement=$(systemctl is-enabled ${option}${service}) 2>/dev/null if [[ -z "${actual_enablement}" ]]; then - echo " INFO: optional service ${option}${service} is not installed." + log " INFO: optional service ${option}${service} is not installed." elif [[ "${actual_enablement}" == "static" ]]; then - echo " INFO: optional service ${option}${service} is set static." + log " INFO: optional service ${option}${service} is set static." elif [[ ! "${actual_enablement}" == "${desired_enablement}" ]]; then exit_on_error "ERROR: service ${option}${service} is not ${desired_enablement} (state: ${actual_enablement})." fi - echo " CHECK" + log " CHECK" } # Reads a textfile and returns all lines as args. @@ -259,7 +259,7 @@ get_args_from_file() { # Check if all passed packages are installed. Fail on first missing. verify_apt_packages() { local packages="$@" - echo " Verify packages are installed: '${packages}'" + log " Verify packages are installed: '${packages}'" if [[ -z "${packages}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -272,13 +272,13 @@ verify_apt_packages() { exit_on_error "ERROR: ${package} is not installed" fi done - echo " CHECK" + log " CHECK" } # Check if all passed modules are installed. Fail on first missing. verify_pip_modules() { local modules="$@" - echo " Verify modules are installed: '${modules}'" + log " Verify modules are installed: '${modules}'" if [[ -z "${modules}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" @@ -291,5 +291,5 @@ verify_pip_modules() { exit_on_error "ERROR: ${module} is not installed" fi done - echo " CHECK" + log " CHECK" } diff --git a/installation/includes/03_welcome.sh b/installation/includes/03_welcome.sh index 7aeaa56ab..5b3ee84be 100644 --- a/installation/includes/03_welcome.sh +++ b/installation/includes/03_welcome.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash welcome() { - clear 1>&3 - echo "######################################################### + clear_c + print_c "######################################################### # # # ___ __ ______ _ __________ ____ __ _ _ # # / _ \/ // / __ \/ |/ / _/ __/( _ \ / \( \/ ) # @@ -29,16 +29,16 @@ in a separate SSH session: cd; tail -f ${INSTALLATION_LOGFILE} Let's set up your Phoniebox. -Do you want to start the installation? [Y/n]" 1>&3 +Do you want to start the installation? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) exit ;; *) - echo "Starting installation + print_c "Starting installation --------------------- -" 1>&3 +" ;; esac } diff --git a/installation/includes/05_finish.sh b/installation/includes/05_finish.sh index 55489ff46..22ba6ae80 100644 --- a/installation/includes/05_finish.sh +++ b/installation/includes/05_finish.sh @@ -2,7 +2,7 @@ finish() { local local_hostname=$(hostname) - echo -e "####################### FINISHED ######################## + print_lc "####################### FINISHED ######################## Installation complete! @@ -14,19 +14,19 @@ Your SSH connection will disconnect. After the reboot, you can access the WebApp in your browser at http://${local_hostname}.local or http://${CURRENT_IP_ADDRESS} Don't forget to upload files. -" | tee /dev/fd/3 -echo "Do you want to reboot now? [Y/n]" 1>&3 +" +print_c "Do you want to reboot now? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) - echo "Reboot aborted" | tee /dev/fd/3 - echo "DONE: finish" + print_lc "Reboot aborted" + log "DONE: finish" exit ;; *) - echo "Rebooting ..." | tee /dev/fd/3 - echo "DONE: finish" + print_lc "Rebooting ..." + log "DONE: finish" sudo reboot ;; esac diff --git a/installation/install-jukebox.sh b/installation/install-jukebox.sh index 90f78800f..84827f99d 100755 --- a/installation/install-jukebox.sh +++ b/installation/install-jukebox.sh @@ -23,42 +23,12 @@ echo GIT_URL $GIT_URL CURRENT_USER="${SUDO_USER:-$(whoami)}" CURRENT_USER_GROUP=$(id -gn "$CURRENT_USER") HOME_PATH=$(getent passwd "$CURRENT_USER" | cut -d: -f6) -echo "Current User: $CURRENT_USER" -echo "User home dir: $HOME_PATH" INSTALLATION_PATH="${HOME_PATH}/${GIT_REPO_NAME}" INSTALL_ID=$(date +%s) INSTALLATION_LOGFILE="${HOME_PATH}/INSTALL-${INSTALL_ID}.log" -# Check if current distro is a 32 bit version -# Support for 64 bit Distros has not been checked (or precisely: is known not to work) -# All RaspianOS versions report as machine "armv6l" or "armv7l", if 32 bit (even the ARMv8 cores!) -_check_os_type() { - local os_type=$(uname -m) - - echo -e "\nChecking OS type '$os_type'" - - if [[ $os_type == "armv7l" || $os_type == "armv6l" ]]; then - echo -e " ... OK!\n" - else - echo "ERROR: Only 32 bit operating systems supported. Please use a 32bit version of RaspianOS!" - echo "You can fix this problem for 64bit kernels: https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/2041" - exit 1 - fi -} - # Manipulate file descriptor for logging -# Behavior: -# Write To logfile: -# default stdout will only write to logfile -# default stderr will only write to logfile -# e.g echo "write only to logfile" -# Write To console (user window): -# redirect to fd 3 will only write to the console -# e.g. echo "write only to console" 1>&3 -# Write To both: -# use tee to write output to logfile and console -# e.g. echo "write to both" | tee /dev/fd/3 _setup_logging(){ if [ "$CI_RUNNING" == "true" ]; then exec 3>&1 2>&1 @@ -68,40 +38,84 @@ _setup_logging(){ echo "Log start: ${INSTALL_ID}" } +# Function to log to both console and logfile +print_lc() { + local message="$1" + echo -e "$message" | tee /dev/fd/3 +} + +# Function to log to logfile only +log() { + local message="$1" + echo -e "$message" +} + +# Function to run a command where the output will be logged to both console and logfile +run_and_print_lc() { + "$@" | tee /dev/fd/3 +} + +# Function to log to console only +print_c() { + local message="$1" + echo -e "$message" 1>&3 +} + +# Function to clear console screen +clear_c() { + clear 1>&3 +} + # Generic emergency error handler that exits the script immediately # Print additional custom message if passed as first argument # Examples: # a command || exit_on_error # a command || exit_on_error "Execution of command failed" exit_on_error () { - echo -e "\n****************************************" | tee /dev/fd/3 - echo "ERROR OCCURRED! + print_lc "\n****************************************" + print_lc "ERROR OCCURRED! A non-recoverable error occurred. -Check install log for details:" | tee /dev/fd/3 - echo "$INSTALLATION_LOGFILE" | tee /dev/fd/3 - echo "****************************************" | tee /dev/fd/3 +Check install log for details:" + print_lc "$INSTALLATION_LOGFILE" + print_lc "****************************************" if [[ -n $1 ]]; then - echo "$1" | tee /dev/fd/3 - echo "****************************************" | tee /dev/fd/3 + print_lc "$1" + print_lc "****************************************" fi - echo "Abort!" + log "Abort!" exit 1 } +# Check if current distro is a 32 bit version +# Support for 64 bit Distros has not been checked (or precisely: is known not to work) +# All RaspianOS versions report as machine "armv6l" or "armv7l", if 32 bit (even the ARMv8 cores!) +_check_os_type() { + local os_type=$(uname -m) + + print_lc "\nChecking OS type '$os_type'" + + if [[ $os_type == "armv7l" || $os_type == "armv6l" ]]; then + print_lc " ... OK!\n" + else + print_lc "ERROR: Only 32 bit operating systems supported. Please use a 32bit version of RaspianOS!" + print_lc "You can fix this problem for 64bit kernels: https://github.com/MiczFlor/RPi-Jukebox-RFID/issues/2041" + exit 1 + fi +} + _download_jukebox_source() { - echo -e "\n\n" - echo "#########################################################" - echo "Downloading Phoniebox software from Github ..." 1>&3 - echo "Download Source: ${GIT_URL}/${GIT_BRANCH}" | tee /dev/fd/3 + log "#########################################################" + print_c "Downloading Phoniebox software from Github ..." + print_lc "Download Source: ${GIT_URL}/${GIT_BRANCH}" cd "${HOME_PATH}" || exit_on_error "ERROR: Changing to home dir failed." wget -qO- "${GIT_URL}/tarball/${GIT_BRANCH}" | tar xz # Use case insensitive search/sed because user names in Git Hub are case insensitive local git_repo_download=$(find . -maxdepth 1 -type d -iname "${GIT_USER}-${GIT_REPO_NAME}-*") - echo "GIT REPO DOWNLOAD = $git_repo_download" + log "GIT REPO DOWNLOAD = $git_repo_download" GIT_HASH=$(echo "$git_repo_download" | sed -rn "s/.*${GIT_USER}-${GIT_REPO_NAME}-([0-9a-fA-F]+)/\1/ip") # Save the git hash for this particular download for later git repo initialization - echo "GIT HASH = $GIT_HASH" + log "GIT HASH = $GIT_HASH" if [[ -z "${git_repo_download}" ]]; then exit_on_error "ERROR: Couldn't find git download." fi @@ -109,8 +123,8 @@ _download_jukebox_source() { exit_on_error "ERROR: Couldn't determine git hash from download." fi mv "$git_repo_download" "$GIT_REPO_NAME" - echo -e "\nDONE: Downloading Phoniebox software from Github" - echo "#########################################################" + log "\nDONE: Downloading Phoniebox software from Github" + log "#########################################################" } _load_sources() { @@ -124,14 +138,16 @@ _load_sources() { done } +### SETUP LOGGING +_setup_logging ### CHECK PREREQUISITE _check_os_type -### SETUP LOGGING -_setup_logging - ### RUN INSTALLATION +log "Current User: $CURRENT_USER" +log "User home dir: $HOME_PATH" + _download_jukebox_source cd "${INSTALLATION_PATH}" || exit_on_error "ERROR: Changing to install dir failed." _load_sources diff --git a/installation/routines/customize_options.sh b/installation/routines/customize_options.sh index 1590383d1..4007b88f5 100644 --- a/installation/routines/customize_options.sh +++ b/installation/routines/customize_options.sh @@ -8,15 +8,15 @@ _option_static_ip() { CURRENT_GATEWAY=$(echo "${CURRENT_ROUTE}" | awk '{ print $3; exit }') CURRENT_INTERFACE=$(echo "${CURRENT_ROUTE}" | awk '{ print $5; exit }') CURRENT_IP_ADDRESS=$(echo "${CURRENT_ROUTE}" | awk '{ print $7; exit }') - clear 1>&3 - echo "----------------------- STATIC IP ----------------------- + clear_c + print_c "----------------------- STATIC IP ----------------------- Setting a static IP will save a lot of start up time. The static adress will be '${CURRENT_IP_ADDRESS}' from interface '${CURRENT_INTERFACE}' with the gateway '${CURRENT_GATEWAY}'. -Set a static IP? [Y/n]" 1>&3 +Set a static IP? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -25,18 +25,18 @@ Set a static IP? [Y/n]" 1>&3 *) ;; esac - echo "ENABLE_STATIC_IP=${ENABLE_STATIC_IP}" + log "ENABLE_STATIC_IP=${ENABLE_STATIC_IP}" } _option_ipv6() { # DISABLE_IPv6 - clear 1>&3 - echo "------------------------- IP V6 ------------------------- + clear_c + print_c "------------------------- IP V6 ------------------------- IPv6 is only needed if you intend to use it. Otherwise it can be disabled. -Do you want to disable IPv6? [Y/n]" 1>&3 +Do you want to disable IPv6? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -45,19 +45,19 @@ Do you want to disable IPv6? [Y/n]" 1>&3 *) ;; esac - echo "DISABLE_IPv6=${DISABLE_IPv6}" + log "DISABLE_IPv6=${DISABLE_IPv6}" } _option_autohotspot() { # ENABLE_AUTOHOTSPOT - clear 1>&3 - echo "---------------------- AUTOHOTSPOT ---------------------- + clear_c + print_c "---------------------- AUTOHOTSPOT ---------------------- When enabled, this service spins up a WiFi hotspot when the Phoniebox is unable to connect to a known WiFi. This way you can still access it. -Do you want to enable an Autohotpot? [y/N]" 1>&3 +Do you want to enable an Autohotpot? [y/N]" read -r response case "$response" in [yY][eE][sS]|[yY]) @@ -68,13 +68,13 @@ Do you want to enable an Autohotpot? [y/N]" 1>&3 esac if [ "$ENABLE_AUTOHOTSPOT" = true ]; then - echo "Do you want to set a custom Password? (default: ${AUTOHOTSPOT_PASSWORD}) [y/N] " 1>&3 + print_c "Do you want to set a custom Password? (default: ${AUTOHOTSPOT_PASSWORD}) [y/N] " read -r response_pw_q case "$response_pw_q" in [yY][eE][sS]|[yY]) while [ $(echo ${response_pw}|wc -m) -lt 8 ] do - echo "Please type the new password (at least 8 character)." 1>&3 + print_c "Please type the new password (at least 8 character)." read -r response_pw done AUTOHOTSPOT_PASSWORD="${response_pw}" @@ -84,29 +84,27 @@ Do you want to enable an Autohotpot? [y/N]" 1>&3 esac if [ "$ENABLE_STATIC_IP" = true ]; then - echo "Wifi hotspot cannot be enabled with static IP. Disabling static IP configuration." 1>&3 - echo "--------------------- - " 1>&3 + print_c "Wifi hotspot cannot be enabled with static IP. Disabling static IP configuration." ENABLE_STATIC_IP=false - echo "ENABLE_STATIC_IP=${ENABLE_STATIC_IP}" + log "ENABLE_STATIC_IP=${ENABLE_STATIC_IP}" fi fi - echo "ENABLE_AUTOHOTSPOT=${ENABLE_AUTOHOTSPOT}" + log "ENABLE_AUTOHOTSPOT=${ENABLE_AUTOHOTSPOT}" if [ "$ENABLE_AUTOHOTSPOT" = true ]; then - echo "AUTOHOTSPOT_PASSWORD=${AUTOHOTSPOT_PASSWORD}" + log "AUTOHOTSPOT_PASSWORD=${AUTOHOTSPOT_PASSWORD}" fi } _option_bluetooth() { # DISABLE_BLUETOOTH - clear 1>&3 - echo "----------------------- BLUETOOTH ----------------------- + clear_c + print_c "----------------------- BLUETOOTH ----------------------- Turning off Bluetooth will save energy and start up time, if you do not plan to use it. -Do you want to disable Bluetooth? [Y/n]" 1>&3 +Do you want to disable Bluetooth? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -115,18 +113,18 @@ Do you want to disable Bluetooth? [Y/n]" 1>&3 *) ;; esac - echo "DISABLE_BLUETOOTH=${DISABLE_BLUETOOTH}" + log "DISABLE_BLUETOOTH=${DISABLE_BLUETOOTH}" } _option_mpd() { - clear 1>&3 + clear_c if [[ "$SETUP_MPD" == true ]]; then if [[ -f "${MPD_CONF_PATH}" || -f "${SYSTEMD_USR_PATH}/mpd.service" ]]; then - echo "-------------------------- MPD -------------------------- + print_c "-------------------------- MPD -------------------------- It seems there is a MPD already installed. Note: It is important that MPD runs as a user service! -Would you like to overwrite your configuration? [Y/n]" 1>&3 +Would you like to overwrite your configuration? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -138,23 +136,23 @@ Would you like to overwrite your configuration? [Y/n]" 1>&3 fi fi - echo "SETUP_MPD=${SETUP_MPD}" + log "SETUP_MPD=${SETUP_MPD}" if [ "$SETUP_MPD" == true ]; then - echo "ENABLE_MPD_OVERWRITE_INSTALL=${ENABLE_MPD_OVERWRITE_INSTALL}" + log "ENABLE_MPD_OVERWRITE_INSTALL=${ENABLE_MPD_OVERWRITE_INSTALL}" fi } _option_rfid_reader() { # ENABLE_RFID_READER - clear 1>&3 - echo "---------------------- RFID READER ---------------------- + clear_c + print_c "---------------------- RFID READER ---------------------- Phoniebox can be controlled with rfid cards/tags, if you have a rfid reader connected. Choose yes to setup a reader. You get prompted for the type selection and configuration later on. -Do you want to setup a rfid reader? [Y/n]" 1>&3 +Do you want to setup a rfid reader? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -163,20 +161,20 @@ Do you want to setup a rfid reader? [Y/n]" 1>&3 *) ;; esac - echo "ENABLE_RFID_READER=${ENABLE_RFID_READER}" + log "ENABLE_RFID_READER=${ENABLE_RFID_READER}" } _option_samba() { # ENABLE_SAMBA - clear 1>&3 - echo "------------------------- SAMBA ------------------------- + clear_c + print_c "------------------------- SAMBA ------------------------- Samba is required to conveniently copy files to your Phoniebox via a network share. If you don't need it, feel free to skip the installation. If you are unsure, stick to YES! -Do you want to install Samba? [Y/n]" 1>&3 +Do you want to install Samba? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -185,18 +183,18 @@ Do you want to install Samba? [Y/n]" 1>&3 *) ;; esac - echo "ENABLE_SAMBA=${ENABLE_SAMBA}" + log "ENABLE_SAMBA=${ENABLE_SAMBA}" } _option_webapp() { # ENABLE_WEBAPP - clear 1>&3 - echo "------------------------ WEBAPP ------------------------- + clear_c + print_c "------------------------ WEBAPP ------------------------- This is only required if you want to use a graphical interface to manage your Phoniebox! -Would you like to install the web application? [Y/n]" 1>&3 +Would you like to install the web application? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -206,20 +204,20 @@ Would you like to install the web application? [Y/n]" 1>&3 *) ;; esac - echo "ENABLE_WEBAPP=${ENABLE_WEBAPP}" + log "ENABLE_WEBAPP=${ENABLE_WEBAPP}" } _option_kiosk_mode() { # ENABLE_KIOSK_MODE - clear 1>&3 - echo "----------------------- KIOSK MODE ---------------------- + clear_c + print_c "----------------------- KIOSK MODE ---------------------- If you have a screen attached to your RPi, this will launch the web application right after boot. It will only install the necessary xserver dependencies and not the entire RPi desktop environment. -Would you like to enable the Kiosk Mode? [y/N]" 1>&3 +Would you like to enable the Kiosk Mode? [y/N]" read -r response case "$response" in [yY][eE][sS]|[yY]) @@ -228,18 +226,18 @@ Would you like to enable the Kiosk Mode? [y/N]" 1>&3 *) ;; esac - echo "ENABLE_KIOSK_MODE=${ENABLE_KIOSK_MODE}" + log "ENABLE_KIOSK_MODE=${ENABLE_KIOSK_MODE}" } _options_update_raspi_os() { # UPDATE_RASPI_OS - clear 1>&3 - echo "----------------------- UPDATE OS ----------------------- + clear_c + print_c "----------------------- UPDATE OS ----------------------- This shall be done eventually, but increases the installation time a lot. -Would you like to update the operating system? [Y/n]" 1>&3 +Would you like to update the operating system? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -248,14 +246,14 @@ Would you like to update the operating system? [Y/n]" 1>&3 *) ;; esac - echo "UPDATE_RASPI_OS=${UPDATE_RASPI_OS}" + log "UPDATE_RASPI_OS=${UPDATE_RASPI_OS}" } _option_disable_onboard_audio() { # Disable BCM on-chip audio (typically Headphones) # not needed when external sound card is sued - clear 1>&3 - echo "--------------------- ON-CHIP AUDIO --------------------- + clear_c + print_c "--------------------- ON-CHIP AUDIO --------------------- If you are using an external sound card (e.g. USB, HifiBerry, PirateAudio, etc), we recommend to disable @@ -269,7 +267,7 @@ We will do our best not to mess anything up. However, a backup copy will be written to ${DISABLE_ONBOARD_AUDIO_BACKUP} ) -Disable Pi's on-chip audio (headphone / jack output)? [y/N]" 1>&3 +Disable Pi's on-chip audio (headphone / jack output)? [y/N]" read -r response case "$response" in [yY][eE][sS]|[yY]) @@ -278,7 +276,7 @@ Disable Pi's on-chip audio (headphone / jack output)? [y/N]" 1>&3 *) ;; esac - echo "DISABLE_ONBOARD_AUDIO=${DISABLE_ONBOARD_AUDIO}" + log "DISABLE_ONBOARD_AUDIO=${DISABLE_ONBOARD_AUDIO}" } @@ -291,14 +289,14 @@ _option_webapp_devel_build() { ENABLE_WEBAPP_PROD_DOWNLOAD=false fi if [[ "$ENABLE_WEBAPP_PROD_DOWNLOAD" == false ]]; then - clear 1>&3 - echo "--------------------- WEBAPP NODE --------------------- + clear_c + print_c "--------------------- WEBAPP NODE --------------------- You are installing from a non-release branch. This means, you will need to build the web app locally. For that you'll need Node. -Do you want to install Node? [Y/n]" 1>&3 +Do you want to install Node? [Y/n]" read -r response case "$response" in [nN][oO]|[nN]) @@ -316,6 +314,11 @@ Do you want to install Node? [Y/n]" 1>&3 FIN_MESSAGE="${FIN_MESSAGE:+$FIN_MESSAGE\n}${tmp_fin_message}" fi fi + + log "ENABLE_INSTALL_NODE=${ENABLE_INSTALL_NODE}" + if [ "$ENABLE_INSTALL_NODE" != true ]; then + log "ENABLE_WEBAPP_PROD_DOWNLOAD=${ENABLE_WEBAPP_PROD_DOWNLOAD}" + fi } _run_customize_options() { diff --git a/installation/routines/install.sh b/installation/routines/install.sh index d241658b6..62d602f17 100644 --- a/installation/routines/install.sh +++ b/installation/routines/install.sh @@ -1,7 +1,7 @@ install() { - clear 1>&3 + clear_c customize_options - clear 1>&3 + clear_c set_raspi_config set_ssh_qos update_raspi_os diff --git a/installation/routines/optimize_boot_time.sh b/installation/routines/optimize_boot_time.sh index 383f790c0..bb6f71902 100644 --- a/installation/routines/optimize_boot_time.sh +++ b/installation/routines/optimize_boot_time.sh @@ -9,17 +9,17 @@ OPTIMIZE_IPV6_CONF_HEADER="## Jukebox IPV6 Config" OPTIMIZE_BOOT_CONF_HEADER="## Jukebox Boot Config" _optimize_disable_irrelevant_services() { - echo " Disable keyboard-setup.service" + log " Disable keyboard-setup.service" sudo systemctl disable keyboard-setup.service - echo " Disable triggerhappy.service" + log " Disable triggerhappy.service" sudo systemctl disable triggerhappy.service sudo systemctl disable triggerhappy.socket - echo " Disable raspi-config.service" + log " Disable raspi-config.service" sudo systemctl disable raspi-config.service - echo " Disable apt-daily.service & apt-daily-upgrade.service" + log " Disable apt-daily.service & apt-daily-upgrade.service" sudo systemctl disable apt-daily.service sudo systemctl disable apt-daily-upgrade.service sudo systemctl disable apt-daily.timer @@ -29,7 +29,7 @@ _optimize_disable_irrelevant_services() { # TODO: If false, actually make sure bluetooth is enabled _optimize_handle_bluetooth() { if [ "$DISABLE_BLUETOOTH" = true ] ; then - echo " Disable bluetooth" | tee /dev/fd/3 + print_lc " Disable bluetooth" sudo systemctl disable hciuart.service sudo systemctl disable bluetooth.service fi @@ -39,14 +39,14 @@ _optimize_handle_bluetooth() { _optimize_static_ip() { # Static IP Address and DHCP optimizations if [ "$ENABLE_STATIC_IP" = true ] ; then - echo " Set static IP address" | tee /dev/fd/3 + print_lc " Set static IP address" if grep -q "${OPTIMIZE_DHCP_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then - echo " Skipping. Already set up!" + log " Skipping. Already set up!" else # DHCP has not been configured - echo " ${CURRENT_INTERFACE} is the default network interface" - echo " ${CURRENT_GATEWAY} is the Router Gateway address" - echo " Using ${CURRENT_IP_ADDRESS} as the static IP for now" + log " ${CURRENT_INTERFACE} is the default network interface" + log " ${CURRENT_GATEWAY} is the Router Gateway address" + log " Using ${CURRENT_IP_ADDRESS} as the static IP for now" sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF @@ -65,9 +65,9 @@ EOF # TODO: Allow both Enable and Disable _optimize_ipv6_arp() { if [ "$DISABLE_IPv6" = true ] ; then - echo " Disabling IPV6" | tee /dev/fd/3 + print_lc " Disabling IPV6" if grep -q "${OPTIMIZE_IPV6_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then - echo " Skipping. Already set up!" + log " Skipping. Already set up!" else sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF @@ -84,9 +84,9 @@ EOF # TODO: Allow both Enable and Disable _optimize_handle_boot_screen() { if [ "$DISABLE_BOOT_SCREEN" = true ] ; then - echo " Disable RPi rainbow screen" + log " Disable RPi rainbow screen" if grep -q "${OPTIMIZE_BOOT_CONF_HEADER}" "$RPI_BOOT_CONFIG_FILE"; then - echo " Skipping. Already set up!" + log " Skipping. Already set up!" else sudo tee -a $RPI_BOOT_CONFIG_FILE <<-EOF @@ -101,7 +101,7 @@ EOF # TODO: Allow both Enable and Disable _optimize_handle_boot_logs() { if [ "$DISABLE_BOOT_LOGS_PRINT" = true ] ; then - echo " Disable boot logs" + log " Disable boot logs" if [ ! -s "${RPI_BOOT_CMDLINE_FILE}" ];then sudo tee "${RPI_BOOT_CMDLINE_FILE}" <<-EOF diff --git a/installation/routines/set_raspi_config.sh b/installation/routines/set_raspi_config.sh index a9cb7b6f1..7f39a0ba5 100644 --- a/installation/routines/set_raspi_config.sh +++ b/installation/routines/set_raspi_config.sh @@ -4,26 +4,26 @@ _run_set_raspi_config() { # Source: https://raspberrypi.stackexchange.com/a/66939 # Autologin - echo " Enable Autologin for user" + log " Enable Autologin for user" sudo raspi-config nonint do_boot_behaviour B2 # Wait for network at boot - # echo " Enable 'Wait for network at boot'" + # log " Enable 'Wait for network at boot'" # sudo raspi-config nonint do_boot_wait 1 # power management of wifi: switch off to avoid disconnecting - echo " Disable Wifi power management to avoid disconnecting" + log " Disable Wifi power management to avoid disconnecting" sudo iwconfig wlan0 power off # On-board audio if [ "$DISABLE_ONBOARD_AUDIO" == true ]; then - echo " Disable on-chip BCM audio" + log " Disable on-chip BCM audio" if grep -q -E "^dtparam=([^,]*,)*audio=(on|true|yes|1).*" "${RPI_BOOT_CONFIG_FILE}" ; then - echo " Backup ${RPI_BOOT_CONFIG_FILE} --> ${DISABLE_ONBOARD_AUDIO_BACKUP}" + log " Backup ${RPI_BOOT_CONFIG_FILE} --> ${DISABLE_ONBOARD_AUDIO_BACKUP}" sudo cp "${RPI_BOOT_CONFIG_FILE}" "${DISABLE_ONBOARD_AUDIO_BACKUP}" sudo sed -i "s/^\(dtparam=\([^,]*,\)*\)audio=\(on\|true\|yes\|1\)\(.*\)/\1audio=off\4/g" "${RPI_BOOT_CONFIG_FILE}" else - echo " On board audio seems to be off already. Not touching ${RPI_BOOT_CONFIG_FILE}" + log " On board audio seems to be off already. Not touching ${RPI_BOOT_CONFIG_FILE}" fi fi } diff --git a/installation/routines/set_ssh_qos.sh b/installation/routines/set_ssh_qos.sh index eaca62fed..76242f712 100644 --- a/installation/routines/set_ssh_qos.sh +++ b/installation/routines/set_ssh_qos.sh @@ -4,7 +4,7 @@ set_ssh_qos() { if [ "$DISABLE_SSH_QOS" == true ] ; then # The latest version of SSH installed on the Raspberry Pi 3 uses QoS headers, which disagrees with some # routers and other hardware. This causes immense delays when remotely accessing the RPi over ssh. - echo " Set SSH QoS to best effort" + log " Set SSH QoS to best effort" echo -e "IPQoS 0x00 0x00\n" | sudo tee -a /etc/ssh/sshd_config echo -e "IPQoS 0x00 0x00\n" | sudo tee -a /etc/ssh/ssh_config fi diff --git a/installation/routines/setup_git.sh b/installation/routines/setup_git.sh index 613062f43..c04ff7acf 100644 --- a/installation/routines/setup_git.sh +++ b/installation/routines/setup_git.sh @@ -2,7 +2,7 @@ GIT_ABORT_MSG="Aborting dir to git repo conversion. Your directory content is untouched, you simply cannot use git for updating / developing" _git_install_os_dependencies() { - echo " Install Git dependencies" + log " Install Git dependencies" sudo apt-get -y update; sudo apt-get -y install \ git \ --no-install-recommends \ @@ -12,9 +12,9 @@ _git_install_os_dependencies() { } _git_convert_tardir_git_repo() { - echo "****************************************************" - echo "*** Converting tar-ball download into git repository" - echo "****************************************************" + log "**************************************************** +*** Converting tar-ball download into git repository +****************************************************" # Just in case, the git version is not new enough, we split up git init -b "${GIT_BRANCH}" into: git -c init.defaultBranch=main init @@ -30,21 +30,19 @@ _git_convert_tardir_git_repo() { # We simply get everything from the beginning of future 3 development but excluding Version 2.X if [[ $GIT_USE_SSH == true ]]; then git remote add origin "git@github.com:${GIT_USER}/${GIT_REPO_NAME}.git" - echo "" - echo "*** Git fetch (SSH) *******************************" + log "\n*** Git fetch (SSH) *******************************" # Prevent: The authenticity of host 'github.com (140.82.121.4)' can't be established. # Do only for this one command, so we do not disable the checks forever if ! git -c core.sshCommand='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' fetch origin "${GIT_BRANCH}" --set-upstream --shallow-since=2021-04-21 --tags; then - echo "" - echo "*** NOTICE *****************************************" - echo "* Error in getting Git Repository using SSH! USING FALLBACK HTTPS." - echo "* Note: This is only relevant for developers!" - echo "* Did you forget to upload the ssh key for this machine to GitHub?" - echo "* Defaulting to HTTPS protocol. You can change back to SSH later with" - echo "* git remote set-url origin git@github.com:${GIT_USER}/${GIT_REPO_NAME}.git" - echo "* git remote set-url upstream git@github.com:${GIT_UPSTREAM_USER}/${GIT_REPO_NAME}.git" - echo "" + log "\n*** NOTICE ***************************************** +* Error in getting Git Repository using SSH! USING FALLBACK HTTPS. +* Note: This is only relevant for developers! +* Did you forget to upload the ssh key for this machine to GitHub? +* Defaulting to HTTPS protocol. You can change back to SSH later with +* git remote set-url origin git@github.com:${GIT_USER}/${GIT_REPO_NAME}.git +* git remote set-url upstream git@github.com:${GIT_UPSTREAM_USER}/${GIT_REPO_NAME}.git\n" + git remote remove origin GIT_USE_SSH=false else @@ -60,32 +58,31 @@ _git_convert_tardir_git_repo() { if [[ "$GIT_USER" != "$GIT_UPSTREAM_USER" ]]; then git remote add upstream "https://github.com/${GIT_UPSTREAM_USER}/${GIT_REPO_NAME}.git" fi - echo "" - echo "*** Git fetch (HTTPS) *****************************" + log "\n*** Git fetch (HTTPS) *****************************" if ! git fetch origin --set-upstream --shallow-since=2021-04-21 --tags "${GIT_BRANCH}"; then - echo "Error: Could not fetch repository!" - echo -e "$GIT_ABORT_MSG" + log "Error: Could not fetch repository!" + log "$GIT_ABORT_MSG" return fi fi HASH_BRANCH=$(git rev-parse FETCH_HEAD) || { echo -e "$GIT_ABORT_MSG"; return; } - echo "" - echo "*** FETCH_HEAD ($GIT_BRANCH) = $HASH_BRANCH" + + log "\n*** FETCH_HEAD ($GIT_BRANCH) = $HASH_BRANCH" git add . # Checkout the exact hash that we have downloaded as tarball - echo "*** Git checkout commit" + log "*** Git checkout commit" git -c advice.detachedHead=false checkout "$GIT_HASH" || { echo -e "$GIT_ABORT_MSG"; return; } HASH_HEAD=$(git rev-parse HEAD) || { echo -e "$GIT_ABORT_MSG"; return; } - echo "*** REQUESTED COMMIT = $HASH_HEAD" + log "*** REQUESTED COMMIT = $HASH_HEAD" # Let's move onto the relevant branch, WITHOUT touching the current checked-out commit # Since we have fetched with --set-upstream above this initializes the tracking branch - echo "*** Git initialize branch" + log "*** Git initialize branch" git checkout -b "$GIT_BRANCH" if [[ "$GIT_USER" != "$GIT_UPSTREAM_USER" ]]; then - echo "*** Get upstream release tags" + log "*** Get upstream release tags" # Always get the upstream release branch to get all release tags # in case they have not been copied to user repository git fetch upstream --shallow-since=2021-04-21 --tags "${GIT_BRANCH_RELEASE}" @@ -101,7 +98,7 @@ _git_convert_tardir_git_repo() { if [[ $GIT_BRANCH != "${GIT_BRANCH_RELEASE}" ]]; then OUTPUT=$(git fetch origin --shallow-since=2021-04-21 --tags "${GIT_BRANCH_RELEASE}" 2>&1) if [[ $? -ne 128 ]]; then - echo "*** Preparing ${GIT_BRANCH_RELEASE} in background" + log "*** Preparing ${GIT_BRANCH_RELEASE} in background" echo -e "$OUTPUT" fi unset OUTPUT @@ -109,7 +106,7 @@ _git_convert_tardir_git_repo() { if [[ $GIT_BRANCH != "${GIT_BRANCH_DEVELOP}" ]]; then OUTPUT=$(git fetch origin --shallow-since=2021-04-21 --tags "${GIT_BRANCH_DEVELOP}" 2>&1) if [[ $? -ne 128 ]]; then - echo "*** Preparing ${GIT_BRANCH_DEVELOP} in background" + log "*** Preparing ${GIT_BRANCH_DEVELOP} in background" echo -e "$OUTPUT" fi unset OUTPUT @@ -117,25 +114,24 @@ _git_convert_tardir_git_repo() { # Provide some status outputs to the user if [[ "${HASH_BRANCH}" != "${HASH_HEAD}" ]]; then - echo "" - echo "*** IMPORTANT NOTICE *******************************" - echo "* Your requested branch has moved on while you were installing." - echo "* Don't worry! We will stay within the exact download version!" - echo "* But we set up the git repo to be ready for updating." - echo "* To start updating (observe updating guidelines!), do:" - echo "* $ git pull origin $GIT_BRANCH" - echo "" + log "\n*** IMPORTANT NOTICE ******************************* +* Your requested branch has moved on while you were installing. +* Don't worry! We will stay within the exact download version! +* But we set up the git repo to be ready for updating. +* To start updating (observe updating guidelines!), do: +* $ git pull origin $GIT_BRANCH\n" + fi - echo "*** Git remotes ************************************" + log "*** Git remotes ************************************" git remote -v - echo "*** Git status *************************************" + log "*** Git status *************************************" git status -sb - echo "*** Git log ****************************************" + log "*** Git log ****************************************" git log --oneline "HEAD^..origin/$GIT_BRANCH" - echo "*** Git describe ***********************************" + log "*** Git describe ***********************************" git describe --tag --dirty='-dirty' - echo "****************************************************" + log "****************************************************" cp -f .githooks/* .git/hooks diff --git a/installation/routines/setup_jukebox_core.sh b/installation/routines/setup_jukebox_core.sh index 6b070ff6c..a7d0f29b6 100644 --- a/installation/routines/setup_jukebox_core.sh +++ b/installation/routines/setup_jukebox_core.sh @@ -9,16 +9,16 @@ JUKEBOX_PULSE_CONFIG="${HOME_PATH}"/.config/pulse/default.pa JUKEBOX_SERVICE_NAME="${SYSTEMD_USR_PATH}/jukebox-daemon.service" _show_slow_hardware_message() { -echo " -------------------------------------------------------------------- + print_c " -------------------------------------------------------------------- | Your hardware is a little slower so this step will take a while. | | Go watch a movie but don't let your computer go to sleep for the | | SSH connection to remain intact. | - --------------------------------------------------------------------" 1>&3 + --------------------------------------------------------------------" } # Functions _jukebox_core_install_os_dependencies() { - echo " Install Jukebox OS dependencies" | tee /dev/fd/3 + print_lc " Install Jukebox OS dependencies" local apt_packages=$(get_args_from_file "${INSTALLATION_PATH}/packages-core.txt") sudo apt-get -y update && sudo apt-get -y install \ @@ -30,7 +30,7 @@ _jukebox_core_install_os_dependencies() { } _jukebox_core_install_python_requirements() { - echo " Install Python requirements" | tee /dev/fd/3 + print_lc " Install Python requirements" cd "${INSTALLATION_PATH}" || exit_on_error @@ -42,13 +42,13 @@ _jukebox_core_install_python_requirements() { } _jukebox_core_configure_pulseaudio() { - echo " Copy PulseAudio configuration" | tee /dev/fd/3 + print_lc " Copy PulseAudio configuration" mkdir -p $(dirname "$JUKEBOX_PULSE_CONFIG") cp -f "${INSTALLATION_PATH}/resources/default-settings/pulseaudio.default.pa" "${JUKEBOX_PULSE_CONFIG}" } _jukebox_core_build_libzmq_with_drafts() { - echo " Building libzmq v${JUKEBOX_ZMQ_VERSION} with drafts support" | tee /dev/fd/3 + print_lc " Building libzmq v${JUKEBOX_ZMQ_VERSION} with drafts support" local zmq_filename="zeromq-${JUKEBOX_ZMQ_VERSION}" local zmq_tar_filename="${zmq_filename}.tar.gz" local cpu_count=${CPU_COUNT:-$(python3 -c "import os; print(os.cpu_count())")} @@ -63,7 +63,7 @@ _jukebox_core_build_libzmq_with_drafts() { } _jukebox_core_download_prebuilt_libzmq_with_drafts() { - echo " Download pre-compiled libzmq with drafts support" + log " Download pre-compiled libzmq with drafts support" local zmq_tar_filename="libzmq.tar.gz" ARCH=$(get_architecture) @@ -83,7 +83,7 @@ _jukebox_core_build_and_install_pyzmq() { # https://pyzmq.readthedocs.io/en/latest/howto/draft.html # https://github.com/MonsieurV/ZeroMQ-RPi/blob/master/README.md # https://github.com/zeromq/pyzmq/issues/1523#issuecomment-1593120264 - echo " Install pyzmq with libzmq-drafts to support WebSockets" | tee /dev/fd/3 + print_lc " Install pyzmq with libzmq-drafts to support WebSockets" if ! pip list | grep -F pyzmq >> /dev/null; then @@ -101,18 +101,18 @@ _jukebox_core_build_and_install_pyzmq() { ZMQ_PREFIX="${JUKEBOX_ZMQ_PREFIX}" ZMQ_DRAFT_API=1 \ pip install -v --no-binary pyzmq --pre pyzmq else - echo " Skipping. pyzmq already installed" | tee /dev/fd/3 + print_lc " Skipping. pyzmq already installed" fi } _jukebox_core_install_settings() { - echo " Register Jukebox settings" | tee /dev/fd/3 + print_lc " Register Jukebox settings" cp -f "${INSTALLATION_PATH}/resources/default-settings/jukebox.default.yaml" "${SETTINGS_PATH}/jukebox.yaml" cp -f "${INSTALLATION_PATH}/resources/default-settings/logger.default.yaml" "${SETTINGS_PATH}/logger.yaml" } _jukebox_core_register_as_service() { - echo " Register Jukebox Core user service" | tee /dev/fd/3 + print_lc " Register Jukebox Core user service" sudo cp -f "${INSTALLATION_PATH}/resources/default-services/jukebox-daemon.service" "${JUKEBOX_SERVICE_NAME}" sudo sed -i "s|%%INSTALLATION_PATH%%|${INSTALLATION_PATH}|g" "${JUKEBOX_SERVICE_NAME}" diff --git a/installation/routines/setup_jukebox_webapp.sh b/installation/routines/setup_jukebox_webapp.sh index 9dc74bf12..f7407f96c 100644 --- a/installation/routines/setup_jukebox_webapp.sh +++ b/installation/routines/setup_jukebox_webapp.sh @@ -15,13 +15,13 @@ _jukebox_webapp_install_node() { sudo apt-get -y update if which node > /dev/null; then - echo " Found existing NodeJS. Hence, updating NodeJS" | tee /dev/fd/3 + print_lc " Found existing NodeJS. Hence, updating NodeJS" sudo npm cache clean -f sudo npm install --silent -g n sudo n --quiet latest sudo npm update --silent -g else - echo " Install NodeJS" | tee /dev/fd/3 + print_lc " Install NodeJS" # Zero and older versions of Pi with ARMv6 only # support experimental NodeJS @@ -45,7 +45,7 @@ _jukebox_webapp_install_node() { # TODO: Avoid building the app locally # Instead implement a Github Action that prebuilds on commititung a git tag _jukebox_webapp_build() { - echo " Building web application" | tee /dev/fd/3 + print_lc " Building web application" cd "${INSTALLATION_PATH}/src/webapp" || exit_on_error npm ci --prefer-offline --no-audit --production rm -rf build @@ -54,11 +54,11 @@ _jukebox_webapp_build() { } _jukebox_webapp_download() { - echo " Downloading web application" | tee /dev/fd/3 + print_lc " Downloading web application" local JUKEBOX_VERSION=$(get_version_string "${INSTALLATION_PATH}/src/jukebox/jukebox/version.py") local TAR_FILENAME="webapp-build.tar.gz" local DOWNLOAD_URL="https://github.com/MiczFlor/RPi-Jukebox-RFID/releases/download/v${JUKEBOX_VERSION}/webapp-v${JUKEBOX_VERSION}.tar.gz" - echo " DOWNLOAD_URL: ${DOWNLOAD_URL}" + log " DOWNLOAD_URL: ${DOWNLOAD_URL}" cd "${INSTALLATION_PATH}/src/webapp" || exit_on_error # URL must be set to default repo as installation can be run from different repos as well where releases may not exist @@ -69,7 +69,7 @@ _jukebox_webapp_download() { } _jukebox_webapp_register_as_system_service_with_nginx() { - echo " Install and configure nginx" | tee /dev/fd/3 + print_lc " Install and configure nginx" sudo apt-get -qq -y update sudo apt-get -y purge apache2 sudo apt-get -y install nginx diff --git a/installation/routines/setup_kiosk_mode.sh b/installation/routines/setup_kiosk_mode.sh index f8d07971c..b6e543768 100644 --- a/installation/routines/setup_kiosk_mode.sh +++ b/installation/routines/setup_kiosk_mode.sh @@ -7,7 +7,7 @@ KIOSK_MODE_CHROMIUM_CUSTOM_DISABLE_UPDATE_CHECK='/etc/chromium-browser/customiza KIOSK_MODE_CHROMIUM_FLAG_UPDATE_INTERVAL='--check-for-update-interval=31536000' _kiosk_mode_install_os_dependencies() { - echo " Install Kiosk Mode dependencies" | tee /dev/fd/3 + print_lc " Install Kiosk Mode dependencies" # Resource: # https://blog.r0b.io/post/minimal-rpi-kiosk/ sudo apt-get -qq -y install --no-install-recommends \ @@ -19,7 +19,7 @@ _kiosk_mode_install_os_dependencies() { } _kiosk_mode_set_autostart() { - echo " Configure Kiosk Mode" | tee /dev/fd/3 + print_lc " Configure Kiosk Mode" local _DISPLAY='$DISPLAY' local _XDG_VTNR='$XDG_VTNR' diff --git a/installation/routines/setup_mpd.sh b/installation/routines/setup_mpd.sh index 40ffe8aac..6a95a95e5 100644 --- a/installation/routines/setup_mpd.sh +++ b/installation/routines/setup_mpd.sh @@ -4,11 +4,11 @@ AUDIOFOLDERS_PATH="${SHARED_PATH}/audiofolders" PLAYLISTS_PATH="${SHARED_PATH}/playlists" _mpd_install_os_dependencies() { - echo " Install MPD OS dependencies" + log " Install MPD OS dependencies" sudo apt-get -y update - echo "Note: Installing MPD might cause a message: 'Job failed. See journalctl -xe for details'" - echo "It can be ignored! It's an artefact of the MPD installation - nothing we can do about it." + log "Note: Installing MPD might cause a message: 'Job failed. See journalctl -xe for details' +It can be ignored! It's an artefact of the MPD installation - nothing we can do about it." sudo apt-get -y install \ mpd mpc \ --no-install-recommends \ @@ -18,7 +18,7 @@ _mpd_install_os_dependencies() { } _mpd_configure() { - echo " Configure MPD as user local service" | tee /dev/fd/3 + print_lc " Configure MPD as user local service" # Make sure system-wide mpd is disabled sudo systemctl stop mpd.socket diff --git a/installation/routines/setup_rfid_reader.sh b/installation/routines/setup_rfid_reader.sh index b5e8b4bbc..3003d79a4 100644 --- a/installation/routines/setup_rfid_reader.sh +++ b/installation/routines/setup_rfid_reader.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash _run_setup_rfid_reader() { - python "${INSTALLATION_PATH}/src/jukebox/run_register_rfid_reader.py" | tee /dev/fd/3 + run_and_print_lc python "${INSTALLATION_PATH}/src/jukebox/run_register_rfid_reader.py" } setup_rfid_reader() { diff --git a/installation/routines/setup_samba.sh b/installation/routines/setup_samba.sh index 100d7370d..c1875113e 100644 --- a/installation/routines/setup_samba.sh +++ b/installation/routines/setup_samba.sh @@ -4,7 +4,7 @@ SMB_CONF="/etc/samba/smb.conf" SMB_CONF_HEADER="## Jukebox Samba Config" _samba_install_os_dependencies() { - echo " Install Samba Core dependencies" + log " Install Samba Core dependencies" sudo apt-get -qq -y update; sudo apt-get -qq -y install \ samba samba-common-bin \ --no-install-recommends \ @@ -14,12 +14,12 @@ _samba_install_os_dependencies() { } _samba_set_user() { - echo " Configure Samba" | tee /dev/fd/3 + print_lc " Configure Samba" local SMB_PASSWD="raspberry" # Samba has not been configured if grep -q "$SMB_CONF_HEADER" "$SMB_CONF"; then - echo " Skipping. Already set up!" | tee /dev/fd/3 + print_lc " Skipping. Already set up!" else # Create Samba user (echo "${SMB_PASSWD}"; echo "${SMB_PASSWD}") | sudo smbpasswd -s -a "${CURRENT_USER}" From 7250211502ef8bb5b5f8c4c289c0c2e519844fe8 Mon Sep 17 00:00:00 2001 From: s-martin Date: Mon, 11 Dec 2023 21:18:13 +0100 Subject: [PATCH 27/28] Minor doc improvements (#2149) * some improvements in the docs * improve docs * Revert change * Fix whitespace * Fix deactivate command vor venv --------- Co-authored-by: pabera <1260686+pabera@users.noreply.github.com> --- documentation/builders/audio.md | 6 +++--- documentation/builders/installation.md | 8 +++++--- documentation/developers/pyhton.md | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/documentation/builders/audio.md b/documentation/builders/audio.md index 0bb5a7163..4fd82e457 100644 --- a/documentation/builders/audio.md +++ b/documentation/builders/audio.md @@ -13,14 +13,14 @@ Audio outputs run via PulseAudio and the basic configuration should be easy. There is a [configuration tool](../developers/coreapps.md#Audio), to setup the configuration for the Jukebox Core App. -To set up the audio +### To set up the audio 1. Follow the setup steps according to your sound card 2. Check that the sound output works [as described below](audio.md#checking-system-sound-output) 3. Run the [audio configuration tool](../developers/coreapps.md#Audio) 4. [Fine-tune audio parameters](audio.md#additional-options) -## Checking system sound output +#### Checking system sound output Run the following steps in a console: @@ -53,7 +53,7 @@ volume level for this sink: $ paplay -d /usr/share/sounds/alsa/Front_Center.wav ``` -# Bluetooth +## Bluetooth Bluetooth setup consists of three steps diff --git a/documentation/builders/installation.md b/documentation/builders/installation.md index fadc77aac..756e2a03c 100644 --- a/documentation/builders/installation.md +++ b/documentation/builders/installation.md @@ -85,22 +85,24 @@ Run the following command in your SSH terminal and follow the instructions cd; bash <(wget -qO- https://raw.githubusercontent.com/MiczFlor/RPi-Jukebox-RFID/future3/main/installation/install-jukebox.sh) ``` -This will get the latest stable release from the branch future3/main. +This will get the latest **stable release** from the branch *future3/main*. + To install directly from a specific branch and/or a different repository specify the variables like this: ```bash - cd; GIT_USER='MiczFlor' GIT_BRANCH='future3/develop' bash <(wget -qO- https://raw.githubusercontent.com/MiczFlor/RPi-Jukebox-RFID/future3/develop/installation/install-jukebox.sh) ``` This will switch directly to the specified feature branch during installation. > [!NOTE] -> For all branches *except* the current Release, you will need to build the Web App locally on the Pi. This is not part of the installation process due to memory limitation issues. See [Steps to install](../developers/development-environment.md#steps-to-install) +> For all branches *except* the current Release future3/main, you will need to build the Web App locally on the Pi. This is not part of the installation process due to memory limitation issues. See [Developer steps to install](../developers/development-environment.md#steps-to-install) If you suspect an error you can monitor the installation-process with ```bash cd; tail -f INSTALL-.log ``` + +After successful installation, continue with [configuring your Phoniebox](configuration.md). diff --git a/documentation/developers/pyhton.md b/documentation/developers/pyhton.md index e9a071e34..31659ef3c 100644 --- a/documentation/developers/pyhton.md +++ b/documentation/developers/pyhton.md @@ -8,11 +8,11 @@ Before you can run Python code, you need to enable the virtual environment. On the Raspberry Pi, it's located in the project root `~/RPi-Jukebox-RFID/.venv`. Depending on your setup, the absolute path can vary. ``` -$ ~/RPi-Jukebox-RFID/.venv/bin/activate +$ source ~/RPi-Jukebox-RFID/.venv/bin/activate ``` If the virtual environment has been activated correctly, your terminal will now show a prefix (`.venv`). If you want to leave the venv again execute deactivate. ``` -$ ~/RPi-Jukebox-RFID/.venv/bin/deactivate +$ deactivate ``` From b8b68c8f565001af7f06127caaff98d46e4adffc Mon Sep 17 00:00:00 2001 From: s-martin Date: Mon, 11 Dec 2023 21:22:04 +0100 Subject: [PATCH 28/28] Add coverage badge (#2153) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ada3e8b3..5824bebbb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/MiczFlor/RPi-Jukebox-RFID/future3/develop) -[![Test Install Scripts Debian v3](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian_v3.yml/badge.svg?branch=future3%2Fdevelop)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian_v3.yml) [![Python + Docs Checks and Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage_future3.yml/badge.svg?branch=future3%2Fdevelop)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage_future3.yml) +[![Test Install Scripts Debian v3](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian_v3.yml/badge.svg?branch=future3%2Fdevelop)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/test_docker_debian_v3.yml) [![Python + Docs Checks and Tests](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage_future3.yml/badge.svg?branch=future3%2Fdevelop)](https://github.com/MiczFlor/RPi-Jukebox-RFID/actions/workflows/pythonpackage_future3.yml) [![Coverage Status](https://coveralls.io/repos/github/MiczFlor/RPi-Jukebox-RFID/badge.svg?branch=future3/develop)](https://coveralls.io/github/MiczFlor/RPi-Jukebox-RFID?branch=future3/develop) [![Matrix chat](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#phoniebox_community:gitter.im)