From 7ab5a410d3ce8c75a48d29d25df30626c4bab482 Mon Sep 17 00:00:00 2001 From: Thilo Graf Date: Tue, 11 Feb 2025 18:20:58 +0100 Subject: [PATCH] refactor: major overhaul and cleanup of the build environment - Removed `.env.sample` and improved `.env` handling - Deleted `translate.py` and replaced it with `translate-md.py` - Refactored `readme.yml` to enhance translation and tagging workflow - Updated `.gitignore` with new exclusions - Major restructuring of `Dockerfile`, including improved ENV variables and layout - Extended `create-env.sh` with interactive prompts and validation - Improved error handling and structure in `docker-compose-wrapper` - Expanded `docker-compose.yml` with new environment variables and network settings - Moved and updated `init.sh`, `.bashrc`, and other files to `files/` directory - Added new scripts: `show-env.sh` for better diagnostics and `terminal-splash.txt` for enhanced display These changes optimize the build environment for improved stability and flexibility. --- .env.sample | 33 -- .github/scripts/translate.py | 25 -- .github/workflows/readme.yml | 63 ++- .gitignore | 3 +- Dockerfile | 274 ++++++------ create-env.sh | 390 ++++++++++++++---- docker-compose-wrapper | 20 +- docker-compose.yml | 156 ++++--- .bashrc => files/.bashrc | 61 ++- files/init.sh | 120 ++++++ files/show-env.sh | 44 ++ .../terminal-splash.txt | 0 12 files changed, 818 insertions(+), 371 deletions(-) delete mode 100644 .env.sample delete mode 100644 .github/scripts/translate.py rename .bashrc => files/.bashrc (61%) create mode 100755 files/init.sh create mode 100755 files/show-env.sh rename terminal-splash.txt => files/terminal-splash.txt (100%) diff --git a/.env.sample b/.env.sample deleted file mode 100644 index 1d91c21..0000000 --- a/.env.sample +++ /dev/null @@ -1,33 +0,0 @@ -BUILDENV_GIT_URL=https://github.com/tuxbox-neutrino/buildenv.git -BUILDENV_VERSION=3.2.4 -BUILDENV_PREFIX=buildenv -TB_BUILD_TIME= -DISPLAY=:0 -ENABLE_UI_TOOLS=false -GIT_EMAIL=${USER}@localhost -GIT_USER=${USER} -HISTFILE=/home/${USER}/tuxbox/.data/.bash_history -HISTFILE_NAME=.bash_history -HOST_PREFIX=tuxbox -LANGUAGE=de_DE.UTF-8 -LC_ALL=de_DE.UTF-8 -LOCALE_LANG=de_DE.UTF-8 -LOCAL_HOSTNAME=localhost -NVIDIA_VISIBLE_DEVICES=all -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -QT_QUICK_BACKEND=software -QT_XCB_GL_INTEGRATION=xcb_egl -START_PATH=/home/${USER}/tuxbox/buildenv -TERM=xterm-256color -TZ=Europe/Berlin -USER=${USER} -USER_DIR=/home/${USER} -USER_GROUP=${USER} -USER_GROUP_ID=1000 -USER_ID=1000 -USER_PASSWORD=${USER} -USER_VOLUME_WORKDIR=/home/${USER}/tuxbox -USER_VOLUME_DATADIR=/home/${USER}/tuxbox/.data -TB_VERSION= -XDG_CONFIG_HOME=/home -XDG_RUNTIME_DIR=/tmp/runtime-root diff --git a/.github/scripts/translate.py b/.github/scripts/translate.py deleted file mode 100644 index 473a910..0000000 --- a/.github/scripts/translate.py +++ /dev/null @@ -1,25 +0,0 @@ -from googletrans import Translator - -def translate_readme(input_text, target_lang): - translator = Translator() - translated = translator.translate(input_text, dest=target_lang) - translated_text = translated.text - - # add hint for automatically translation - translated_text = f"Note: This is an automatically translated file. Original content from [here](https://github.com/tuxbox-neutrino/docker-buildenv/blob/master/README-de.md):\n\n{translated_text}" - - # Use this workaround, because translater breaks some links and anchors - translated_text = translated_text.replace("[Build Image](#Build Image)", "[Build Image](#build-image)") - translated_text = translated_text.replace("devtool -reference.html", "devtool-reference.html") - translated_text = translated_text.replace("dev-manual -common-tasks.html", "dev-manual-common-tasks.html") - translated_text = translated_text.replace("Clone #1-Init-Script", "#1-clone-init-script") - - return translated_text - -if __name__ == "__main__": - input_text = open("README-de.md", "r").read() - target_lang = "en" # target language is english - translated_text = translate_readme(input_text, target_lang) - - with open("README-en.md", "w") as outfile: - outfile.write(translated_text) diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index 4b617a8..b9afbd3 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -1,11 +1,17 @@ -name: Translate README +name: Translate README and tag repository on: push: branches: - master paths: - - 'README-de.md' + - 'README_de.md' + - 'create-env.sh' + - 'docker-compose-wrapper' + - 'docker-compose.yml' + - 'Dockerfile' + paths-ignore: + - '.github/**' permissions: contents: write @@ -16,27 +22,66 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.x - - name: Install dependencies + - name: Install translate dependencies run: | python -m pip install --upgrade pip pip install --upgrade googletrans==3.1.0a0 + curl -o translate-md.py https://raw.githubusercontent.com/dbt1/translate-md/refs/heads/master/translate-md.py + chmod 755 translate-md.py + curl -o translate-md-config.json https://raw.githubusercontent.com/dbt1/translate-md/refs/heads/master/translate-md-config.json.sample + + - name: Verify translate-md.py download + run: | + if [ ! -f translate-md.py ]; then + echo "translate-md.py was not downloaded!" + exit 1 + fi - name: Translate README run: | - python .github/scripts/translate.py + cp README_de.md template.md + python translate-md.py --template-md template.md --output-dir . --prefix README_ --main-doc README.md -c translate-md-config.json -s de + rm template.md + + - name: Prepare Git user data + run: | + git config --global user.email "dbt@novatux.de" + git config --global user.name "Thilo Graf" - name: Commit and push translated README run: | - git config --global user.email "actions@github.com" - git config --global user.name "GitHub Actions" - git add README-en.md + git add README*.md git commit -m "readme: Automatically translated README" git push + - name: Install tagit dependencies + run: | + pip install GitPython + curl -o tagit.py https://raw.githubusercontent.com/dbt1/tagit/master/tagit.py + curl -o tagit-config.json https://raw.githubusercontent.com/dbt1/tagit/master/tagit-config.json + chmod +x tagit.py + + - name: Verify tagit.py download + run: | + if [ ! -f tagit.py ]; then + echo "tagit.py was not downloaded!" + exit 1 + fi + + - name: Tagging + run: | + python tagit.py -f Makefile + + - name: Commit and push version and tag changes + run: | + git add Makefile + git commit -m "tagging: Automatically updated tags [skip ci]" || echo "No changes to commit" + git push + git push --tags \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5fa5a29..a691572 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ .gitconfig .directory -init.sh + *-swp +env_backups diff --git a/Dockerfile b/Dockerfile index 3e86c69..e805294 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,196 +1,174 @@ -## Use the official Debian 11 image based up debian:bullseye-slim as a base +# Dockerfile for Debian-based Tuxbox build environment FROM dbt1/debian-tuxbox-base:v1.6 -### Args -ARG PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +## Build arguments from docker-compose ## + +# Internal information +ARG DOCKER_BUILDENV_VERSION=${DOCKER_BUILDENV_VERSION} +ARG DOCKER_BUILDENV_GIT_URL=$DOCKER_BUILDENV_GIT_URL + +# URL to buildenv sources and where to install ARG BUILDENV_GIT_URL=${BUILDENV_GIT_URL} -ARG BUILDENV_VERSION=${BUILDENV_VERSION} ARG BUILDENV_PREFIX=${BUILDENV_PREFIX} -ARG TB_BUILD_TIME=${TB_BUILD_TIME} + +# User and group +ARG USER_NAME=${USER_NAME} +ARG USER_ID=${USER_ID} +ARG USER_GROUP=${USER_GROUP} +ARG USER_GROUP_ID=${USER_GROUP_ID} +ARG USER_PASSWORD=${USER_PASSWORD} +ARG USER_DIR=${USER_DIR} + +# More build args ARG DISPLAY=${DISPLAY} -ARG ENABLE_UI_TOOLS=false +ARG ENABLE_UI_TOOLS=${ENABLE_UI_TOOLS} ARG GIT_EMAIL=${GIT_EMAIL} ARG GIT_USER=${GIT_USER} -ARG USER_GROUP_ID=${USER_GROUP_ID} +ARG HISTFILE_NAME=${HISTFILE_NAME} ARG HISTFILE=${HISTFILE} -ARG HOST_PREFIX=${HOST_PREFIX} -ARG LOCALE_LANG=${LOCALE_LANG} +ARG BUILDENV_INSTALL_PREFIX=${BUILDENV_INSTALL_PREFIX} ARG LOCAL_HOSTNAME=${LOCAL_HOSTNAME} +ARG LOCALE_LANG=${LOCALE_LANG} +ARG TZ=${TZ} +ARG TERM=${TERM} ARG NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES} ARG QT_QUICK_BACKEND=${QT_QUICK_BACKEND} ARG QT_XCB_GL_INTEGRATION=${QT_XCB_GL_INTEGRATION} +ARG USER_VOLUME_WORKDIR=${USER_VOLUME_WORKDIR} +ARG USER_VOLUME_DATADIR=${USER_VOLUME_DATADIR} ARG START_PATH=${START_PATH} -ARG TERM=${TERM} -ARG TZ=${TZ} -ARG USER=${USER} -ARG USER_DIR=${USER_DIR} -ARG USER_GROUP=${USER_GROUP} -ARG USER_ID=${USER_ID} -ARG USER_PASSWORD=${USER_PASSWORD} -ARG USER_VOLUME_WORKDIR=${USER_DIR}/${HOST_PREFIX} -ARG TB_VERSION=${TB_VERSION} +ARG WWW_DOCDIR=${WWW_DOCDIR} +ARG EXPLORER_ENABLE=${EXPLORER_ENABLE} +ARG EXPLORER_GIT_URL=${EXPLORER_GIT_URL} ARG XDG_CONFIG_HOME=${XDG_CONFIG_HOME} ARG XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR} -## Add the user with default password +# Convert ARG to ENV for runtime usage +ENV DOCKER_BUILDENV_VERSION=${DOCKER_BUILDENV_VERSION} +ENV DISPLAY=${DISPLAY} +ENV DOCKER_BUILDENV_GIT_URL=$DOCKER_BUILDENV_GIT_URL +ENV BUILDENV_GIT_URL=$BUILDENV_GIT_URL +ENV ENABLE_UI_TOOLS=${ENABLE_UI_TOOLS} +ENV GIT_EMAIL=${GIT_EMAIL} +ENV GIT_USER=${GIT_USER} +ENV HISTFILE_NAME=${HISTFILE_NAME} +ENV HISTFILE=${HISTFILE} +ENV BUILDENV_INSTALL_PREFIX=${BUILDENV_INSTALL_PREFIX} +ENV LOCAL_HOSTNAME=${LOCAL_HOSTNAME} +ENV LOCALE_LANG=${LOCALE_LANG} +ENV TZ=${TZ} +ENV TERM=${TERM} +ENV NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES} +ENV QT_QUICK_BACKEND=${QT_QUICK_BACKEND} +ENV QT_XCB_GL_INTEGRATION=${QT_XCB_GL_INTEGRATION} +ENV USER=${USER_NAME} +ENV USER_ID=${USER_ID} +ENV USER_GROUP=${USER_GROUP} +ENV USER_GROUP_ID=${USER_GROUP_ID} +ENV USER_PASSWORD=${USER_PASSWORD} +ENV USER_DIR=${USER_DIR} +ENV USER_VOLUME_WORKDIR=${USER_VOLUME_WORKDIR} +ENV USER_VOLUME_DATADIR=${USER_VOLUME_DATADIR} +ENV START_PATH=${START_PATH} +ENV WWW_DOCDIR=${WWW_DOCDIR} +ENV EXPLORER_ENABLE=${EXPLORER_ENABLE} +ENV EXPLORER_GIT_URL=${EXPLORER_GIT_URL} +ENV XDG_CONFIG_HOME=${XDG_CONFIG_HOME} +ENV XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR} + +# Create user and group RUN groupadd -g "${USER_GROUP_ID}" "${USER_GROUP}" && \ useradd -m -u "${USER_ID}" -g "${USER_GROUP_ID}" -s /bin/bash "${USER}" && \ echo "${USER}:${USER_PASSWORD}" | chpasswd -## Set the desired Locale -RUN locale-gen ${LOCALE_LANG} && \ - dpkg-reconfigure --frontend=noninteractive locales && \ - update-locale LANG=${LOCALE_LANG} +# Set Locale +RUN sed -i "/${LOCALE_LANG}/s/^# //g" /etc/locale.gen && \ + locale-gen ${LOCALE_LANG} && \ + update-locale LANG="${LOCALE_LANG}" -### Some labels -LABEL maintainer="Thilo Graf " \ - maintainer.org="tuxbox-neutrino" \ - maintainer.org.uri="https://tuxbox-neutrino.org" \ - com.tuxbox-neutrino.project.repo.type="git" \ - com.tuxbox-neutrino.project.repo.uri="https://github.com/dbt1/docker-tuxbox-build" \ - com.tuxbox-neutrino.project.repo.issues="https://github.com/dbt1/docker-tuxbox-build/issues" \ - com.tuxbox-neutrino.app.docker-tuxbox-build.version="${TB_VERSION}" \ - # Open container labels - org.opencontainers.image.created="${TB_BUILD_TIME}" \ - org.opencontainers.image.description="Debian based" \ - org.opencontainers.image.vendor="tuxbox-neutrino" \ - org.opencontainers.image.source="https://github.com/dbt1/docker-tuxbox-build" \ - # Artifact hub annotations - io.artifacthub.package.readme-url="https://github.com/dbt1/docker-tuxbox-build/blob/master/README.md" \ - io.artifacthub.package.logo-url="https://avatars.githubusercontent.com/u/22789022?s=200&v=4" - -### ui package experimental atm -RUN if [ "$ENABLE_UI_TOOLS" = "true" ]; then \ - apt-get update && apt-get install -y --no-install-recommends \ - breeze-icon-theme \ - meld \ - dbus \ - kdevelop; \ +# Install UI tools (if enabled) +RUN if [ "${ENABLE_UI_TOOLS}" = "true" ]; then \ + apt-get update && apt-get install -y --no-install-recommends \ + breeze-icon-theme \ + meld \ + dbus \ + kdevelop; \ fi + ## avoid dbus warn messages ENV NO_AT_BRIDGE=1 ## Create some basic directories and permissions for X-Server -RUN mkdir -p $XDG_RUNTIME_DIR && chown -R root:root $XDG_RUNTIME_DIR && chmod 0700 $XDG_RUNTIME_DIR +RUN mkdir -p "${XDG_RUNTIME_DIR}" && chown -R root:root "${XDG_RUNTIME_DIR}" && chmod 0700 "${XDG_RUNTIME_DIR}" ## Copy welcome message ENV BANNER_FILE=/etc/welcome.txt -COPY terminal-splash.txt /etc/terminal-splash.txt +COPY files/terminal-splash.txt /etc/terminal-splash.txt RUN cat /etc/terminal-splash.txt > ${BANNER_FILE} && \ echo "--------------------------------------------------------------" >> ${BANNER_FILE} && \ - echo "Tuxbox-Builder Version: ${TB_VERSION}" >> ${BANNER_FILE} && \ + echo "Tuxbox docker-buildenv: v${DOCKER_BUILDENV_VERSION}" >> ${BANNER_FILE} && \ echo "--------------------------------------------------------------" >> ${BANNER_FILE} -### ssh stuff +# ssh service setup ENV SSHD_RUN_SERVICE_DIR="/etc/service/sshd" ENV SSHD_RUN="${SSHD_RUN_SERVICE_DIR}/run" -RUN mkdir /var/run/sshd && \ +RUN mkdir -p /var/run/sshd && \ ssh-keygen -A && \ - mkdir -p ${SSHD_RUN_SERVICE_DIR} && \ - echo '#!/bin/sh' > ${SSHD_RUN} && \ - echo 'exec /usr/sbin/sshd -D' >> ${SSHD_RUN} && \ - chmod 755 ${SSHD_RUN} + mkdir -p "${SSHD_RUN_SERVICE_DIR}" && \ + echo '#!/bin/sh' > "${SSHD_RUN}" && \ + echo 'exec /usr/sbin/sshd -D' >> "${SSHD_RUN}" && \ + chmod 755 "${SSHD_RUN}" -### Set timzone -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +# Set timezone +RUN ln -snf /usr/share/zoneinfo/"${TZ}" /etc/localtime && echo "${TZ}" > /etc/timezone -## Lighttpd setup and create the runit service for lighttpd -ENV LIGHTTPD_RUN="/etc/service/lighttpd/run" +# Lighttpd setup +RUN apt update && apt install -y php-cgi php-cli php-common php-fpm php-mbstring && \ + lighty-enable-mod fastcgi && \ + lighty-enable-mod fastcgi-php && \ + mkdir -p /run/lighttpd && \ + chown -R www-data:www-data /run/lighttpd && \ + chmod -R 755 /run/lighttpd +ENV LIGHTTPD_SERVICE_RUN="/etc/service/lighttpd/run" ENV LIGHTTPD_CONFIG_PATH="/config/lighttpd" ENV LIGHTTPD_STD_CONFIG_FILE="${LIGHTTPD_CONFIG_PATH}/lighttpd.conf" +ENV LIGHTTPD_ERROR_DOC="404.html" RUN mkdir -p /etc/service/lighttpd && \ - echo '#!/bin/sh' > ${LIGHTTPD_RUN} && \ - echo "if [ ! -d ${LIGHTTPD_CONFIG_PATH} ]; then" >> ${LIGHTTPD_RUN} && \ - echo " mkdir -p ${LIGHTTPD_CONFIG_PATH}" >> ${LIGHTTPD_RUN} && \ - echo "fi" >> ${LIGHTTPD_RUN} && \ - echo "" >> ${LIGHTTPD_RUN} && \ - echo "if [ ! -f ${LIGHTTPD_STD_CONFIG_FILE} ]; then" >> ${LIGHTTPD_RUN} && \ - echo " cp /etc/lighttpd/lighttpd.conf ${LIGHTTPD_STD_CONFIG_FILE}" >> ${LIGHTTPD_RUN} && \ - echo " echo 'dir-listing.activate = \"enable\"' >> ${LIGHTTPD_STD_CONFIG_FILE}" >> ${LIGHTTPD_RUN} && \ - echo " sed -i 's|/var/www/html|${USER_VOLUME_WORKDIR}/${BUILDENV_PREFIX}/dist|' ${LIGHTTPD_STD_CONFIG_FILE}" >> ${LIGHTTPD_RUN} && \ - echo "fi" >> ${LIGHTTPD_RUN} && \ - echo "" >> ${LIGHTTPD_RUN} && \ - echo "exec lighttpd -D -f ${LIGHTTPD_STD_CONFIG_FILE}" >> ${LIGHTTPD_RUN} && \ - chmod 755 ${LIGHTTPD_RUN} + echo '#!/bin/sh' > "${LIGHTTPD_SERVICE_RUN}" && \ + echo "if [ ! -d ${LIGHTTPD_CONFIG_PATH} ]; then" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo " mkdir -p ${LIGHTTPD_CONFIG_PATH}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo "fi" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo "" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo "if [ ! -f ${LIGHTTPD_STD_CONFIG_FILE} ]; then" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo " cp /etc/lighttpd/lighttpd.conf ${LIGHTTPD_STD_CONFIG_FILE}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo " echo 'dir-listing.activate = \"enable\"' >> ${LIGHTTPD_STD_CONFIG_FILE}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo " echo 'server.follow-symlink = \"enable\"' >> ${LIGHTTPD_STD_CONFIG_FILE}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo " echo 'server.error-handler-404 = \"/${LIGHTTPD_ERROR_DOC}\"' >> ${LIGHTTPD_STD_CONFIG_FILE}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo " sed -i 's|/var/www/html|${WWW_DOCDIR}|g' ${LIGHTTPD_STD_CONFIG_FILE}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo "fi" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo "" >> "${LIGHTTPD_SERVICE_RUN}" && \ + echo "exec lighttpd -D -f ${LIGHTTPD_STD_CONFIG_FILE}" >> "${LIGHTTPD_SERVICE_RUN}" && \ + usermod -aG www-data "${USER}" && \ + chmod 755 "${LIGHTTPD_SERVICE_RUN}" -### Start generate content of start script ### +# Copy helper scripts +COPY files/show-env.sh /usr/local/bin/show-env.sh + +# Set the location of the init script and copy the init script from your project into the image ENV CONTAINER_INIT_SCRIPT="/usr/local/bin/init.sh" -RUN echo "#!/bin/bash" > ${CONTAINER_INIT_SCRIPT} && \ - echo "echo 'Initialize tuxbox-builder container...'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "chown -R ${USER}:${USER_GROUP} ${USER_DIR} ${USER_VOLUME_DATADIR}" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "usermod -aG sudo $USER" >> ${CONTAINER_INIT_SCRIPT} +COPY files/init.sh ${CONTAINER_INIT_SCRIPT} +RUN chmod +x ${CONTAINER_INIT_SCRIPT} +COPY files/.bashrc ${USER_DIR}/.bashrc -## prepare git config -RUN mkdir -p ${XDG_CONFIG_HOME}/git && \ - echo "echo -e '[user]\\n\\temail = ${GIT_EMAIL}\\n\\tname = ${GIT_USER}' > ${XDG_CONFIG_HOME}/git/config" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "chown -R ${USER}:${USER_GROUP} ${XDG_CONFIG_HOME}/git" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo " >> ${CONTAINER_INIT_SCRIPT} - -## Prepare buildenv script -RUN echo "if [ ! -d ${START_PATH}/.git ]; then" >> ${CONTAINER_INIT_SCRIPT} && \ - echo " echo Cloning buildenv Repository from ${BUILDENV_GIT_URL}" >> ${CONTAINER_INIT_SCRIPT} && \ - echo " git clone ${BUILDENV_GIT_URL} /tmp/${BUILDENV_PREFIX}" >> ${CONTAINER_INIT_SCRIPT} && \ - echo " rsync -a /tmp/${BUILDENV_PREFIX} ${USER_VOLUME_WORKDIR}/" >> ${CONTAINER_INIT_SCRIPT} && \ - echo " rm -rf ${USER_DIR}/${BUILDENV_PREFIX}/tmp" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "else" >> ${CONTAINER_INIT_SCRIPT} && \ - echo " echo 'Repository [${START_PATH}] already exists. Not touched!'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "fi" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "chown -R ${USER}:${USER_GROUP} ${USER_VOLUME_WORKDIR}" >> ${CONTAINER_INIT_SCRIPT} - -## prepare profile -ENV BASH_RC_FILE=${USER_DIR}/.bashrc -COPY .bashrc ${BASH_RC_FILE} -RUN echo "sed -i 's|@START_PATH@|'"${START_PATH}"'|' ${BASH_RC_FILE}" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "sed -i 's|@VERSION@|'"${TB_VERSION}"'|' ${BASH_RC_FILE}" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "sed -i 's|@HISTFILE@|'"${HISTFILE}"'|' ${BASH_RC_FILE}" >> ${CONTAINER_INIT_SCRIPT} - -## prepare ssh config -RUN echo "mkdir -p ${USER_DIR}/.ssh" >> ${CONTAINER_INIT_SCRIPT} - -## show env info -RUN echo "echo " >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo Environment:" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo BUILDENV_VERSION='${BUILDENV_VERSION}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo HOST_PREFIX='${HOST_PREFIX}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo BUILDENV_PREFIX='${BUILDENV_PREFIX}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo BUILDENV_GIT_URL='${BUILDENV_GIT_URL}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo TZ='${TZ}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo USER='${USER}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo USER_GROUP='${USER_GROUP}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo USER_ID='${USER_ID}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo USER_GROUP_ID='${USER_GROUP_ID}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo USER_DIR='${HOME}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo USER_PASSWORD=******" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo HISTFILE='${HISTFILE}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo GIT_USER='${GIT_USER}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo GIT_EMAIL='${GIT_EMAIL}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo PATH='${PATH}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo LOCALE_LANG='${LOCALE_LANG}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo START_PATH='${START_PATH}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo TB_VERSION='${TB_VERSION}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo TB_BUILD_TIME='${TB_BUILD_TIME}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo DISPLAY='${DISPLAY}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo ENABLE_UI_TOOLS='${ENABLE_UI_TOOLS} NOTE: Experimental only!'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo LOCAL_HOSTNAME='${LOCAL_HOSTNAME}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo HOSTNAME='$HOSTNAME'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo XDG_RUNTIME_DIR='${XDG_RUNTIME_DIR}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo XDG_CONFIG_HOME='${XDG_CONFIG_HOME}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo QT_QUICK_BACKEND='${QT_QUICK_BACKEND}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo QT_XCB_GL_INTEGRATION='${QT_XCB_GL_INTEGRATION}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo NVIDIA_VISIBLE_DEVICES='${NVIDIA_VISIBLE_DEVICES}'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "echo " >> ${CONTAINER_INIT_SCRIPT} - -## start services -RUN echo "echo 'Ready...'" >> ${CONTAINER_INIT_SCRIPT} && \ - echo "exec runsvdir -P /etc/service" >> ${CONTAINER_INIT_SCRIPT} -### END generate content of start script ### - -# clean up -RUN apt-get autoremove -y && apt-get autoclean && apt-get clean && \ +# Cleanup +RUN apt-get autoremove -y && apt-get autoclean -y && apt-get clean -y && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -## make start script executable +# Make init script executable RUN chmod 755 "${CONTAINER_INIT_SCRIPT}" # Start container with init script -ENTRYPOINT ["bash", "-c", "${CONTAINER_INIT_SCRIPT}"] -CMD ["D"] +ENTRYPOINT ["bash", "-c", "exec ${CONTAINER_INIT_SCRIPT:-/usr/local/bin/init.sh}"] + +# Add HEALTHCHECK +HEALTHCHECK --interval=5s --timeout=5s --start-period=1s --retries=10 \ + CMD [ -f /tmp/container_ready ] || exit 1 diff --git a/create-env.sh b/create-env.sh index 67c20b8..20ff194 100755 --- a/create-env.sh +++ b/create-env.sh @@ -1,106 +1,330 @@ -#!/bin/bash +#!/usr/bin/env bash +# +# create_env.sh - Automatically create the .env file for Docker Compose +# Creates a .env file with user and system settings. +# If a .env file already exists, the user is asked +# if a backup should be created and the file overwritten. -# Path to.env-Datei +set -e # Stop on error + +# Prints an error message and exits +function error_exit { + echo "$1" >&2 + exit 1 +} + +# ------------------------------------------------------------------------------ +# Global constants +# ------------------------------------------------------------------------------ ENV_FILE=".env" +BACKUP_DIR="env_backups" +EXIT_USER_CANCEL=70 -BUILDENV_VERSION="3.2.4" -TB_VERSION="latest" -TB_BUILD_TIME=$(date '+%Y-%m-%d %H:%M:%S') -USER=$(whoami) -USER_ID=$(id -u) -USER_GROUP_ID=$(id -g) -USER_DIR="${HOME}" -HOST_PREFIX=tuxbox -BUILDENV_PREFIX="buildenv" -LOCAL_HOSTNAME=$(hostname) -ENABLE_UI_TOOLS="false" -USER_VOLUME_BINDIR="${USER_DIR}/bin" -USER_VOLUME_WORKDIR="${USER_DIR}/${HOST_PREFIX}" -USER_VOLUME_WORKBINDIR="${USER_VOLUME_WORKDIR}/bin" +# ------------------------------------------------------------------------------ +# Prompt functions +# ------------------------------------------------------------------------------ + +# Prompt the user with a message and default value +function prompt { + local PROMPT_MESSAGE=$1 + local DEFAULT_VALUE=$2 + local PAD_WIDTH=${3:-20} + + # Build the prompt with color logic + local PROMPT_WITH_COLOR + PROMPT_WITH_COLOR=$(prompt_color "$PROMPT_MESSAGE" "$DEFAULT_VALUE" "$PAD_WIDTH") + + # Read user input and use default if empty + read -p "$(echo -e "$PROMPT_WITH_COLOR")" INPUT + INPUT="${INPUT:-$DEFAULT_VALUE}" + + echo "$INPUT" +} + +# Return a color-coded prompt based on whether the current default deviates from the original default +function prompt_color { + local PROMPT_MESSAGE=$1 + local DEFAULT_VALUE=$2 + local PAD_WIDTH=${3:-20} + + local GREEN="\033[0;32m" + local YELLOW="\033[0;33m" + local RESET="\033[0m" + + # Retrieve the original value from a variable named ORIG_ + local ORIG_VAR="ORIG_${PROMPT_MESSAGE}" + local ORIG_VALUE="${!ORIG_VAR}" + + local COLOR="$GREEN" + if [[ -n "$ORIG_VALUE" && "$DEFAULT_VALUE" != "$ORIG_VALUE" ]]; then + COLOR="$YELLOW" + fi + + local ADJUSTED_WIDTH=$((PAD_WIDTH + 3)) + local PROMPT_WITH_COLOR + PROMPT_WITH_COLOR=$(printf "%-*s %s%s%s: " \ + $ADJUSTED_WIDTH \ + "$PROMPT_MESSAGE" \ + "$COLOR" \ + "$DEFAULT_VALUE" \ + "$RESET") + echo "$PROMPT_WITH_COLOR" +} + +# Prompt for mandatory input (e.g. passwords), input is hidden +function prompt_mandatory { + local PROMPT_MESSAGE=$1 + local PAD_WIDTH=${2:-20} + local INPUT="" + + while [ -z "$INPUT" ]; do + local PROMPT_WITH_COLOR + PROMPT_WITH_COLOR=$(printf "%-*s: " $PAD_WIDTH "$PROMPT_MESSAGE") + read -s -p "$(echo -e "$PROMPT_WITH_COLOR")" INPUT + echo # newline after hidden input + if [ -z "$INPUT" ]; then + echo "The field $PROMPT_MESSAGE may not be empty. Please enter again." + fi + done + echo "$INPUT" +} + +# Prompt the user with specific options and return the response in lowercase +function prompt_user() { + local prompt_message="$1" + local options="$2" + local default_response="$3" + + read -p "$prompt_message ($options): " RESPONSE + RESPONSE=${RESPONSE,,} # Convert to lowercase + echo "${RESPONSE:-$default_response}" +} + +# ------------------------------------------------------------------------------ +# Function to edit an existing .env file (create a backup and load its values) +# ------------------------------------------------------------------------------ +function edit_env_file() { + # Create backup + mkdir -p "$BACKUP_DIR" + local TIMESTAMP + TIMESTAMP=$(date +"%Y%m%d-%H%M%S") + local BACKUP_FILE="${BACKUP_DIR}/.env.backup-${TIMESTAMP}" + cp "$ENV_FILE" "$BACKUP_FILE" || error_exit "Error creating backup copy." + echo "Backup copy created under $BACKUP_FILE." + + # Read existing .env and export variables + echo "Reading existing .env to use its values as defaults..." + while IFS='=' read -r key value || [[ -n "$key" ]]; do + # Skip empty lines and comments + [[ -z "$key" || "$key" =~ ^# ]] && continue + # Remove surrounding quotes if any + value=${value#\"} + value=${value%\"} + value=${value#\'} + value=${value%\'} + export "$key=$value" + done < "$ENV_FILE" +} + +# ------------------------------------------------------------------------------ +# Function to handle user cancellation +# ------------------------------------------------------------------------------ +function cancel_operation() { + echo "Operation cancelled by user." + exit "$EXIT_USER_CANCEL" +} + +# ------------------------------------------------------------------------------ +# Main Logic +# ------------------------------------------------------------------------------ +if [ -f "$ENV_FILE" ]; then + RESPONSE=$(prompt_user "Edit: ${ENV_FILE} type | Hold: type or | Cancel: type " "Edit/Use/Cancel" "use") + case "$RESPONSE" in + edit|e) + edit_env_file + ;; + use|u) + echo "Existing ${ENV_FILE} file will be used (unchanged)." + exit 0 + ;; + cancel|c) + cancel_operation + ;; + *) + echo "Unknown input - existing ${ENV_FILE} will be used (unchanged)." + exit 0 + ;; + esac +else + echo "No ${ENV_FILE} file found." + RESPONSE=$(prompt_user "Create new: ${ENV_FILE} type | Cancel: type " "Edit/Cancel" "edit") + case "$RESPONSE" in + edit|e) + echo "Proceeding to create a new ${ENV_FILE} file..." + ;; + cancel|c) + cancel_operation + ;; + *) + echo "Unknown input - proceeding to create a new ${ENV_FILE} file." + ;; + esac +fi + +# ------------------------------------------------------------------------------ +# Internal use: Retrieve git info +# ------------------------------------------------------------------------------ +DOCKER_BUILDENV_GIT_URL="$(git config --get remote.origin.url)" +DOCKER_BUILDENV_VERSION="$(git -C "$(pwd)" describe --tags --long | sed -e 's/-g[0-9a-f]\{7,\}$//' -e 's/-\([0-9]\+\)$/.\1/')" + +# ------------------------------------------------------------------------------ +# Original defaults used for prompts (for color comparison and fallback) +# ------------------------------------------------------------------------------ +ORIG_USER_NAME="$(whoami)" +ORIG_USER_ID="$(id -u)" +ORIG_USER_GROUP="$(id -gn)" +ORIG_USER_GROUP_ID="$(id -g)" +ORIG_DEFAULT_PASSWORD="tuxpwd" + +if command -v git &>/dev/null; then + ORIG_GIT_EMAIL=$(git config --global user.email || true) + ORIG_GIT_USER=$(git config --global user.name || true) +fi +ORIG_GIT_EMAIL=${ORIG_GIT_EMAIL:-"${USER}@${HOSTNAME}"} +ORIG_GIT_USER=${ORIG_GIT_USER:-$(getent passwd "${USER}" | cut -d: -f5 | cut -d, -f1)} + +ORIG_BUILDENV_GIT_URL="https://github.com/tuxbox-neutrino/buildenv.git" +ORIG_BUILDENV_PREFIX="buildenv" + +# Additional defaults +ORIG_DISPLAY="${DISPLAY:-:0}" +ORIG_ENABLE_UI_TOOLS="false" +ORIG_BUILDENV_INSTALL_PREFIX="tuxbox" +ORIG_LOCAL_HOSTNAME="${HOSTNAME}" +ORIG_LOCALE_LANG="${LANG:-en_US.UTF-8}" +ORIG_TZ="$(cat /etc/timezone 2>/dev/null || echo 'UTC')" +ORIG_TERM="${TERM:-xterm}" +ORIG_NVIDIA_VISIBLE_DEVICES="all" +ORIG_QT_QUICK_BACKEND="software" +ORIG_QT_XCB_GL_INTEGRATION="xcb_egl" + +ORIG_USER_DIR="${HOME}" + +ORIG_EXPLORER_ENABLE="false" +ORIG_EXPLORER_GIT_URL="https://github.com/dbt1/tuxbox-explorer.git" + +ORIG_XDG_CONFIG_HOME="${ORIG_USER_DIR}/.config" +ORIG_XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR}" + +# ------------------------------------------------------------------------------ +# Prompt the user for various settings using defaults (either from existing .env or original) +# ------------------------------------------------------------------------------ +echo -e "Global user data" +USER_NAME=$(prompt "USER_NAME" "${USER_NAME:-$ORIG_USER_NAME}") +USER_DIR=$(prompt "USER_DIR" "${USER_DIR:-$ORIG_USER_DIR}") +USER_ID=$(prompt "USER_ID" "${USER_ID:-$ORIG_USER_ID}") +USER_GROUP=$(prompt "USER_GROUP" "${USER_GROUP:-$ORIG_USER_GROUP}") +USER_GROUP_ID=$(prompt "USER_GROUP_ID" "${USER_GROUP_ID:-$ORIG_USER_GROUP_ID}") +echo -e "" +echo -e "Set or use this default user password, NOTE: Please change it if you run the container at first time!" +USER_PASSWORD=$(prompt "USER_PASSWORD" "${USER_PASSWORD:-$ORIG_DEFAULT_PASSWORD}") +# Alternatively, you could use prompt_mandatory for hidden password input: +# USER_PASSWORD=$(prompt_mandatory "USER_PASSWORD" 20) + +echo -e "" +echo -e "Add some default git user data." +GIT_EMAIL=$(prompt "GIT_EMAIL" "${GIT_EMAIL:-$ORIG_GIT_EMAIL}") +GIT_USER=$(prompt "GIT_USER" "${GIT_USER:-$ORIG_GIT_USER}") + +echo -e "" +echo -e "Clone URL for buildenv sources." +BUILDENV_GIT_URL=$(prompt "BUILDENV_GIT_URL" "${BUILDENV_GIT_URL:-$ORIG_BUILDENV_GIT_URL}") + +echo -e "" +echo -e "htdoc content for file explorer, allows userfriendly navigation through deploed results" +EXPLORER_ENABLE=$(prompt "EXPLORER_ENABLE" "${EXPLORER_ENABLE:-$ORIG_EXPLORER_ENABLE}") +EXPLORER_GIT_URL=$(prompt "EXPLORER_GIT_URL" "${EXPLORER_GIT_URL:-$ORIG_EXPLORER_GIT_URL}") + +echo -e "" +echo -e "Prefix where to install all buildenv stuff within user dir (default: $ORIG_BUILDENV_INSTALL_PREFIX)" +BUILDENV_INSTALL_PREFIX=$(prompt "BUILDENV_INSTALL_PREFIX" "${BUILDENV_INSTALL_PREFIX:-$ORIG_BUILDENV_INSTALL_PREFIX}") + +echo -e "" +echo -e "Prefix for buildenv sources (default: $ORIG_BUILDENV_PREFIX)" +BUILDENV_PREFIX=$(prompt "BUILDENV_PREFIX" "${BUILDENV_PREFIX:-$ORIG_BUILDENV_PREFIX}") + +echo -e "" +echo -e "UI-related settings." +DISPLAY=$(prompt "DISPLAY" "${DISPLAY:-$ORIG_DISPLAY}") +ENABLE_UI_TOOLS=$(prompt "ENABLE_UI_TOOLS" "${ENABLE_UI_TOOLS:-$ORIG_ENABLE_UI_TOOLS}") +NVIDIA_VISIBLE_DEVICES=$(prompt "NVIDIA_VISIBLE_DEVICES" "${NVIDIA_VISIBLE_DEVICES:-$ORIG_NVIDIA_VISIBLE_DEVICES}") +QT_QUICK_BACKEND=$(prompt "QT_QUICK_BACKEND" "${QT_QUICK_BACKEND:-$ORIG_QT_QUICK_BACKEND}") +QT_XCB_GL_INTEGRATION=$(prompt "QT_XCB_GL_INTEGRATION" "${QT_XCB_GL_INTEGRATION:-$ORIG_QT_XCB_GL_INTEGRATION}") + +echo -e "" +echo -e "System variables." +LOCAL_HOSTNAME=$(prompt "LOCAL_HOSTNAME" "${LOCAL_HOSTNAME:-$ORIG_LOCAL_HOSTNAME}") +LOCALE_LANG=$(prompt "LOCALE_LANG" "${LOCALE_LANG:-$ORIG_LOCALE_LANG}") +TZ=$(prompt "TZ" "${TZ:-$ORIG_TZ}") +TERM=$(prompt "TERM" "${TERM:-$ORIG_TERM}") +XDG_CONFIG_HOME=$(prompt "XDG_CONFIG_HOME" "${XDG_CONFIG_HOME:-$ORIG_XDG_CONFIG_HOME}") +XDG_RUNTIME_DIR=$(prompt "XDG_RUNTIME_DIR" "${XDG_RUNTIME_DIR:-$ORIG_XDG_RUNTIME_DIR}") + +# Derived variables based on the above +USER_VOLUME_WORKDIR="${USER_DIR}/${BUILDENV_INSTALL_PREFIX}" USER_VOLUME_DATADIR="${USER_VOLUME_WORKDIR}/.data" +USER_VOLUME_BINDIR="${USER_DIR}/bin" +START_PATH="${USER_VOLUME_WORKDIR}/${BUILDENV_PREFIX}" +WWW_DOCDIR="${USER_VOLUME_WORKDIR}/htdoc" + +# Setup history file location HISTFILE_NAME=".bash_history" HISTFILE="${USER_VOLUME_DATADIR}/${HISTFILE_NAME}" -# Set default values for GIT_EMAIL, GIT_USER -GIT_EMAIL="${USER}@${HOSTNAME}" -GIT_USER="$(grep "${USER}" /etc/passwd | cut -d: -f5 | sed 's/,//g')" +# ------------------------------------------------------------------------------ +# Write the final .env file +# ------------------------------------------------------------------------------ +cat < "$ENV_FILE" +# Auto-generated $ENV_FILE file for docker-buildenv +# Do not change manually! Run $0 to generate $ENV_FILE! -# Check if git is installed -if git --version &>/dev/null; then - # Git is installed, try to get global values - GLOBAL_EMAIL=$(git config --global user.email) - if [ -z "$GLOBAL_EMAIL" ]; then - GLOBAL_EMAIL=$GIT_EMAIL - fi - GLOBAL_USER=$(git config --global user.name) - if [ -z "$GLOBAL_USER" ]; then - GLOBAL_USER=$GIT_USER - fi - - # Check if inside a Git repository - if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - # Try to get local values if globals are not set - [ -z "$GLOBAL_EMAIL" ] && GIT_EMAIL=$(git config --local user.email) || GIT_EMAIL=$GLOBAL_EMAIL - [ -z "$GLOBAL_USER" ] && GIT_USER=$(git config --local user.name) || GIT_USER=$GLOBAL_USER +DOCKER_BUILDENV_GIT_URL=${DOCKER_BUILDENV_GIT_URL} +DOCKER_BUILDENV_VERSION=${DOCKER_BUILDENV_VERSION} - # Get version info - last_tag=$(git describe --tags --abbrev=0 2>/dev/null) - last_commit_id=$(git rev-parse --short HEAD) - current_branch=$(git rev-parse --abbrev-ref HEAD) - if [ -z "$last_tag" ]; then - commit_count=$(git rev-list --count HEAD) - TB_VERSION="git+${commit_count}-${last_commit_id}-${current_branch}" - else - commit_count=$(git rev-list --count ${last_tag}..HEAD) - TB_VERSION="${last_tag}.${commit_count}-${current_branch}" - fi - else - # Not inside a Git repo, use global values if available - GIT_EMAIL=${GLOBAL_EMAIL:-$GIT_EMAIL} - GIT_USER=${GLOBAL_USER:-$GIT_USER} - fi -else - echo "Git is not installed, using default values." -fi - -# Create environment variables and write into .env -cat <$ENV_FILE -BUILDENV_GIT_URL=https://github.com/tuxbox-neutrino/buildenv.git -BUILDENV_VERSION=${BUILDENV_VERSION} +BUILDENV_GIT_URL=${BUILDENV_GIT_URL} BUILDENV_PREFIX=${BUILDENV_PREFIX} -TB_BUILD_TIME=${TB_BUILD_TIME} + +USER_NAME=${USER_NAME} +USER_ID=${USER_ID} +USER_GROUP=${USER_GROUP} +USER_GROUP_ID=${USER_GROUP_ID} +USER_PASSWORD=${USER_PASSWORD} + DISPLAY=${DISPLAY} ENABLE_UI_TOOLS=${ENABLE_UI_TOOLS} GIT_EMAIL=${GIT_EMAIL} GIT_USER=${GIT_USER} -HISTFILE=${HISTFILE} HISTFILE_NAME=${HISTFILE_NAME} -HOST_PREFIX=${HOST_PREFIX} -LANGUAGE=${LANG} -LC_ALL=${LANG} -LOCALE_LANG=${LANG} +HISTFILE=${HISTFILE} +BUILDENV_INSTALL_PREFIX=${BUILDENV_INSTALL_PREFIX} LOCAL_HOSTNAME=${LOCAL_HOSTNAME} -NVIDIA_VISIBLE_DEVICES=all -QT_QUICK_BACKEND=software -QT_XCB_GL_INTEGRATION=xcb_egl -START_PATH=${USER_VOLUME_WORKDIR}/${BUILDENV_PREFIX} +LOCALE_LANG=${LOCALE_LANG} +TZ=${TZ} TERM=${TERM} -TZ=$(cat /etc/timezone) -USER=${USER} +NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES} +QT_QUICK_BACKEND=${QT_QUICK_BACKEND} +QT_XCB_GL_INTEGRATION=${QT_XCB_GL_INTEGRATION} USER_DIR=${USER_DIR} -USER_GROUP=${USER} -USER_GROUP_ID=${USER_GROUP_ID} -USER_ID=${USER_ID} -USER_PASSWORD=${USER} USER_VOLUME_WORKDIR=${USER_VOLUME_WORKDIR} USER_VOLUME_DATADIR=${USER_VOLUME_DATADIR} USER_VOLUME_BINDIR=${USER_VOLUME_BINDIR} -USER_VOLUME_WORKBINDIR=${USER_VOLUME_WORKBINDIR} -TB_VERSION=${TB_VERSION} -XDG_CONFIG_HOME=/home -XDG_RUNTIME_DIR=/tmp/runtime-root +START_PATH=${START_PATH} +WWW_DOCDIR=${WWW_DOCDIR} +EXPLORER_ENABLE=${EXPLORER_ENABLE} +EXPLORER_GIT_URL=${EXPLORER_GIT_URL} +XDG_CONFIG_HOME=${XDG_CONFIG_HOME} +XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR} EOF -# validate -echo ".env-file successfully created with:" -cat $ENV_FILE +echo -e "" +echo -e "$ENV_FILE file was successfully created (or overwritten)." diff --git a/docker-compose-wrapper b/docker-compose-wrapper index 6c60f8d..7481f33 100755 --- a/docker-compose-wrapper +++ b/docker-compose-wrapper @@ -1,16 +1,28 @@ #!/bin/bash -# Path to script that will be executed before starts docker-compose +# Path to script that will be executed before starting docker-compose ENV_SCRIPT="./create-env.sh" +# Define exit codes as constants +EXIT_USER_CANCEL=70 + # Check script if [ -x "$ENV_SCRIPT" ]; then - echo "executing $ENV_SCRIPT..." - $ENV_SCRIPT + echo "Executing $ENV_SCRIPT..." + "$ENV_SCRIPT" + EXIT_CODE=$? + + if [ $EXIT_CODE -eq $EXIT_USER_CANCEL ]; then + echo "create-env.sh was canceled by the user." + exit $EXIT_USER_CANCEL + elif [ $EXIT_CODE -ne 0 ]; then + echo "create-env.sh failed with exit code $EXIT_CODE." + exit $EXIT_CODE + fi else echo "Error: $ENV_SCRIPT not found or not executable." exit 1 fi -# Execute docker-compose with all parameters an sub commannds +# Execute docker-compose with all parameters and subcommands docker-compose "$@" diff --git a/docker-compose.yml b/docker-compose.yml index 69f0d4c..abf7447 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,86 +1,118 @@ - - services: tuxbox-build: container_name: tuxbox-build - image: tuxbox-build - environment: - - PATH=${USER_VOLUME_WORKBINDIR}:${USER_VOLUME_BINDIR}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - env_file: - - .env build: context: . dockerfile: Dockerfile args: - - BUILDENV_GIT_URL=${BUILDENV_GIT_URL} - - BUILDENV_PREFIX=${BUILDENV_PREFIX} - - BUILDENV_VERSION=${BUILDENV_VERSION} - - DISPLAY=${DISPLAY} - - ENABLE_UI_TOOLS=false - - GIT_EMAIL=${GIT_EMAIL} - - GIT_USER=${GIT_USER} - - HISTFILE=${USER_VOLUME_DATADIR}/${HISTFILE_NAME} - - HISTFILE_NAME=${HISTFILE_NAME} - - HOST_PREFIX=${HOST_PREFIX} - - LOCALE_LANG=${LOCALE_LANG} - - LOCAL_HOSTNAME=${LOCAL_HOSTNAME} - - NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES} - - QT_QUICK_BACKEND=${QT_QUICK_BACKEND} - - QT_XCB_GL_INTEGRATION=${QT_XCB_GL_INTEGRATION} - - START_PATH=${START_PATH} - - TB_BUILD_TIME=${TB_BUILD_TIME} - - TB_VERSION=${TB_VERSION} - - TERM=${TERM} - - TZ=${TZ} - - USER=${USER} - - USER_DIR=${USER_DIR} - - USER_GROUP=${USER_GROUP} - - USER_GROUP_ID=${USER_GROUP_ID} - - USER_ID=${USER_ID} - - USER_PASSWORD=${USER_PASSWORD} - - USER_VOLUME_WORKDIR=${USER_DIR}/${HOST_PREFIX} - - USER_VOLUME_DATADIR=${USER_VOLUME_DATADIR} - - XDG_CONFIG_HOME=${XDG_CONFIG_HOME} - - XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR} + DOCKER_BUILDENV_VERSION: ${DOCKER_BUILDENV_VERSION} + DOCKER_BUILDENV_GIT_URL: $DOCKER_BUILDENV_GIT_URL + PATH: "${USER_VOLUME_WORKDIR}/bin:${USER_VOLUME_BINDIR}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + BUILDENV_GIT_URL: ${BUILDENV_GIT_URL} + BUILDENV_PREFIX: ${BUILDENV_PREFIX} + + # Host user and group + USER_NAME: ${USER_NAME} + USER_ID: ${USER_ID} + USER_GROUP: ${USER_GROUP} + USER_GROUP_ID: ${USER_GROUP_ID} + USER_PASSWORD: ${USER_PASSWORD} + USER_DIR: ${USER_DIR} + + # More Build-Args + DISPLAY: ${DISPLAY} + ENABLE_UI_TOOLS: ${ENABLE_UI_TOOLS} + GIT_EMAIL: ${GIT_EMAIL} + GIT_USER: ${GIT_USER} + HISTFILE_NAME: ${HISTFILE_NAME} + HISTFILE: ${HISTFILE} + BUILDENV_INSTALL_PREFIX: ${BUILDENV_INSTALL_PREFIX} + LOCAL_HOSTNAME: ${LOCAL_HOSTNAME} + LOCALE_LANG: ${LOCALE_LANG} + TZ: ${TZ} + TERM: ${TERM} + NVIDIA_VISIBLE_DEVICES: ${NVIDIA_VISIBLE_DEVICES} + QT_QUICK_BACKEND: ${QT_QUICK_BACKEND} + QT_XCB_GL_INTEGRATION: ${QT_XCB_GL_INTEGRATION} + USER_VOLUME_WORKDIR: ${USER_VOLUME_WORKDIR} + USER_VOLUME_DATADIR: ${USER_VOLUME_DATADIR} + START_PATH: ${START_PATH} + WWW_DOCDIR: ${WWW_DOCDIR} + EXPLORER_ENABLE: ${EXPLORER_ENABLE} + EXPLORER_GIT_URL: ${EXPLORER_GIT_URL} + XDG_CONFIG_HOME: ${XDG_CONFIG_HOME} + XDG_RUNTIME_DIR: ${XDG_RUNTIME_DIR} + + image: tuxbox-build + + environment: + DOCKER_BUILDENV_VERSION: ${DOCKER_BUILDENV_VERSION} + DOCKER_BUILDENV_GIT_URL: $DOCKER_BUILDENV_GIT_URL + BUILDENV_GIT_URL: ${BUILDENV_GIT_URL} + BUILDENV_PREFIX: ${BUILDENV_PREFIX} + PATH: "${USER_VOLUME_WORKDIR}/bin:${USER_VOLUME_BINDIR}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + DISPLAY: ${DISPLAY} + ENABLE_UI_TOOLS: ${ENABLE_UI_TOOLS} + GIT_EMAIL: ${GIT_EMAIL} + GIT_USER: ${GIT_USER} + HISTFILE_NAME: ${HISTFILE_NAME} + HISTFILE: ${HISTFILE} + BUILDENV_INSTALL_PREFIX: ${BUILDENV_INSTALL_PREFIX} + LOCAL_HOSTNAME: ${LOCAL_HOSTNAME} + LOCALE_LANG: ${LOCALE_LANG} + TZ: ${TZ} + TERM: ${TERM} + NVIDIA_VISIBLE_DEVICES: ${NVIDIA_VISIBLE_DEVICES} + QT_QUICK_BACKEND: ${QT_QUICK_BACKEND} + QT_XCB_GL_INTEGRATION: ${QT_XCB_GL_INTEGRATION} + USER: ${USER_NAME} + USER_ID: ${USER_ID} + USER_GROUP: ${USER_GROUP} + USER_GROUP_ID: ${USER_GROUP_ID} + USER_PASSWORD: ${USER_PASSWORD} + USER_DIR: ${USER_DIR} + USER_VOLUME_WORKDIR: ${USER_VOLUME_WORKDIR} + USER_VOLUME_DATADIR: ${USER_VOLUME_DATADIR} + START_PATH: ${START_PATH} + WWW_DOCDIR: ${WWW_DOCDIR} + EXPLORER_ENABLE: ${EXPLORER_ENABLE} + EXPLORER_GIT_URL: ${EXPLORER_GIT_URL} + XDG_CONFIG_HOME: ${XDG_CONFIG_HOME} + XDG_RUNTIME_DIR: ${XDG_RUNTIME_DIR} - devices: - - /dev/dri:/dev/dri - ports: - # the host: container ports for web access, used for httpd inside container to get built packages and images via browser, wget, curl, set top boxes etc. - - "8080:80" - # the host: container ports for ssh access of users in its /home - - "222:22" - tty: true - working_dir: / volumes: - ${USER_VOLUME_WORKDIR}:${USER_VOLUME_WORKDIR} + - ${USER_VOLUME_BINDIR}:${USER_DIR}/bin + - ${USER_VOLUME_DATADIR}:/data + - ${USER_VOLUME_WORKDIR}/.config:/config + - ${USER_VOLUME_WORKDIR}/.config/git/config:${XDG_CONFIG_HOME}/git - ${USER_DIR}/sstate-cache:${USER_DIR}/sstate-cache - ${USER_DIR}/Archive:${USER_DIR}/Archive - ${USER_DIR}/.ccache:${USER_DIR}/.ccache - ${USER_DIR}/sources:${USER_DIR}/sources - - ${USER_VOLUME_BINDIR}:${USER_DIR}/bin - - ${USER_VOLUME_WORKBINDIR}:${USER_VOLUME_WORKDIR}/bin - ${USER_DIR}/.ssh:${USER_DIR}/.ssh - - ${USER_VOLUME_DATADIR}:/data - - ${USER_VOLUME_WORKDIR}/.config:/config - - ${USER_VOLUME_WORKDIR}/.config/git/config:${XDG_CONFIG_HOME}/git + + + # Optional for UI tools - /tmp/.X11-unix:/tmp/.X11-unix - /usr/lib/x86_64-linux-gnu/mesa:/usr/lib/x86_64-linux-gnu/mesa - networks: - - tuxbox-network - #hostname: ${LOCAL_HOSTNAME} + + devices: + - /dev/dri:/dev/dri # For GPU acceleration if needed + + ports: + - "8080:80" # Webserver + - "222:22" # SSH + + tty: true + working_dir: / + cap_add: - SYS_ADMIN + restart: unless-stopped networks: - tuxbox-network: + default: driver: bridge - -volumes: - tuxbox-volumes: - driver: local - - - diff --git a/.bashrc b/files/.bashrc similarity index 61% rename from .bashrc rename to files/.bashrc index 95ed114..1573b0b 100644 --- a/.bashrc +++ b/files/.bashrc @@ -58,11 +58,12 @@ if [ -n "$force_color_prompt" ]; then fi if [ "$color_prompt" = yes ]; then - PS1='\[\033[01;33m\]\u\[\033[01;33m\]@\[\033[01;33m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' + PS1='\[\033[01;33m\]\u\[\033[01;33m\]@@LOCAL_HOSTNAME@\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' else - PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' + PS1='${debian_chroot:+($debian_chroot)}\u@@LOCAL_HOSTNAME@:\w\$ ' fi + unset color_prompt force_color_prompt # If this is an xterm set the title to user@host:dir @@ -116,8 +117,56 @@ fi cd @START_PATH@ -while IFS= read -r line; do echo -e "$line"; done < /etc/terminal-splash.txt -echo -e "--------------------------------------------------------------" -echo -e "Tuxbox-Builder Version: @VERSION@" -echo -e "--------------------------------------------------------------" +echo -e "--------------------------------------------------------------------" +while IFS= read -r line; do + echo -e "$line" +done < /etc/terminal-splash.txt +echo -e "--------------------------------------------------------------------" +echo -e "docker-buildenv: v@DOCKER_BUILDENV_VERSION@\t| @DOCKER_BUILDENV_GIT_URL@" +echo -e "buildenv: $(git -C @START_PATH@ describe --tags --long | sed -e 's/-g[0-9a-f]\{7,\}$//' -e 's/-\([0-9]\+\)$/.\1/')\t| @BUILDENV_GIT_URL@" +if [ -f /etc/os-release ]; then + PRETTY_NAME=$(grep '^PRETTY_NAME=' /etc/os-release | cut -d= -f2 | tr -d '"') + echo -e "OS-Version: $PRETTY_NAME" +fi +echo -e "Kernel-Version: $(uname -r)" +echo -e "Container-Hostname: $(hostname)" +echo -e "Container-IP: $(hostname -I | awk '{print $1}')" +echo -e "--------------------------------------------------------------------" echo -e "" + +convert_locale() { + local input_locale="$1" + echo "${input_locale%.*}:${input_locale%%_*}" +} +export LANG=@LANG@ +export LANGUAGE=$(convert_locale $LANG) +export LC_ALL=$LANG + +# Set the directory to check +DIR_TO_CHECK=@START_PATH@ + +# Detect system locale +LOCALE=$(locale | grep LANG= | cut -d= -f2 | cut -d_ -f1) + +# Set link based on locale +if [[ "$LOCALE" == "de" ]]; then + LINK="https://github.com/tuxbox-neutrino/buildenv/blob/master/README-de.md#14-init-skript-ausf%C3%BChren" +else + LINK="https://github.com/tuxbox-neutrino/buildenv/blob/master/README-us.md#14-init-script" +fi + +# Check for subdirectories starting with 'meta-' +if ! find "$DIR_TO_CHECK" -type d -name "meta-*" | grep -q .; then + # Print bold and user-friendly message if no subdirectory matches + echo -e "--------------------------------------------------------------" + echo -e "\033[1m\033[33mNOTE: Your build environment seems to be uninitialized!\033[0m" + echo -e "--------------------------------------------------------------" + echo -e "\033[1mPlease run the init script to set up your environment.\033[0m" + echo -e "" + echo -e "./init && cd poky-@BUILDENV_VERSION@" + echo -e "" + echo -e "--------------------------------------------------------------" + echo -e "Refer to the instructions here:" + echo -e "\033[4m$LINK\033[0m" + echo -e "" +fi diff --git a/files/init.sh b/files/init.sh new file mode 100755 index 0000000..426e772 --- /dev/null +++ b/files/init.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# Initialize tuxbox-builder container... +echo 'Initialize tuxbox-builder container...' + +# Define a dedicated user group +GROUP_NAME="${USER_GROUP:-$USER}" + +# Ensure the group exists, create it if necessary +if ! getent group "$GROUP_NAME" > /dev/null; then + echo "Group $GROUP_NAME does not exist. Creating..." + groupadd "$GROUP_NAME" +fi + +# Ensure the user exists, create it if necessary +if ! id "$USER" &>/dev/null; then + echo "User $USER does not exist. Creating..." + useradd -m -s /bin/bash -g "$GROUP_NAME" -G www-data "$USER" +else + usermod -aG "$GROUP_NAME" "$USER" + usermod -aG www-data "$USER" +fi + +# Prepare global Git configuration +mkdir -p "${XDG_CONFIG_HOME:-$USER_DIR/.config}/git" +echo 'Setting up global Git configuration...' +echo -e "[user]\n\temail = ${GIT_EMAIL}\n\tname = ${GIT_USER}" > "${XDG_CONFIG_HOME}/git/config" +chown -R "$USER":"$GROUP_NAME" "${XDG_CONFIG_HOME}/git" + +# Prepare SSH configuration +mkdir -p "${USER_DIR}/.ssh" + +# Optimize chown: Only change ownership if incorrect +for dir in "$USER_VOLUME_WORKDIR" "$WWW_DOCDIR"; do + if [ -d "$dir" ]; then + current_owner=$(stat -c "%U:%G" "$dir") + if [ "$current_owner" != "$USER:$GROUP_NAME" ]; then + echo "Updating ownership for $dir..." + chown -R "$USER":"$GROUP_NAME" "$dir" + fi + fi +done + +# Optimize chmod: Only change permissions if incorrect +for dir in "$USER_VOLUME_WORKDIR" "$WWW_DOCDIR"; do + if [ -d "$dir" ]; then + if find "$dir" -not -perm -g+rw | grep . > /dev/null 2>&1; then + echo "Updating permissions for $dir..." + chmod -R g+rw "$dir" + fi + fi +done + +echo "User $USER is set up with group $GROUP_NAME and www-data for shared access." + +# Prepare build environment +if [ ! -d "${USER_VOLUME_WORKDIR}/${BUILDENV_PREFIX}/.git" ]; then + if cd "${USER_VOLUME_WORKDIR}"; then + echo "Cloning build environment repository..." + git clone "${BUILDENV_GIT_URL}" "${BUILDENV_PREFIX}" + else + echo "Error: Could not change directory to ${USER_VOLUME_WORKDIR}" >&2 + exit 1 + fi +else + echo "Repository [${USER_VOLUME_WORKDIR}/${BUILDENV_PREFIX}] already exists. Not modified!" +fi +chown -R "$USER":"$GROUP_NAME" "$USER_VOLUME_WORKDIR" + +# Detect the build environment version +BUILDENV_DISTRO_VERSION=$(grep 'DEFAULT_IMAGE_VERSION=' "${START_PATH}/init.sh" | cut -d'=' -f2 | tr -d '"') +echo "Detected DISTRO_VERSION = $BUILDENV_DISTRO_VERSION within ${START_PATH}" + +# Prepare web server content if enabled +if [ "${EXPLORER_ENABLE}" != "false" ]; then + + if [ ! -d "${WWW_DOCDIR}/.git" ]; then + echo 'Cloning File Explorer web content repository...' + git clone "${EXPLORER_GIT_URL}" "${WWW_DOCDIR}" + fi + + # Download default configuration file if it does not exist + if [ ! -f "${WWW_DOCDIR}/config/config.php" ]; then + echo "[${WWW_DOCDIR}/config/config.php] does not exist. Downloading..." + curl -o "${WWW_DOCDIR}/config/config.php" "https://raw.githubusercontent.com/dbt1/support/master/docker-buildenv/config-sample.php" + else + echo "Repository [${WWW_DOCDIR}] already exists and configured. Not modified!" + fi + + # Find the build directory based on detected distro version + BUILD_DIR=$(find "${START_PATH}" -type d -path "*-${BUILDENV_DISTRO_VERSION}/build" ! -path "*-${BUILDENV_DISTRO_VERSION}/build/*" 2>/dev/null) + if [ -n "$BUILD_DIR" ]; then + sed -i "s|#@FILES_DIRECTORY@|\\\$FILES_DIRECTORY = '$BUILD_DIR'|g" "${WWW_DOCDIR}/config/config.php" + fi + + chown -R "$USER":"$GROUP_NAME" "$WWW_DOCDIR" + +else + echo "EXPLORER_ENABLE is disabled. Skipping web server setup." +fi + +# Prepare user profile with environment variables +echo 'Configuring user profile...' +BASH_RC_FILE="${USER_DIR}/.bashrc" +sed -i "s|@START_PATH@|${START_PATH}|g" "$BASH_RC_FILE" +sed -i "s|@BUILDENV_GIT_URL@|${BUILDENV_GIT_URL}|g" "$BASH_RC_FILE" +sed -i "s|@DOCKER_BUILDENV_VERSION@|${DOCKER_BUILDENV_VERSION}|g" "$BASH_RC_FILE" +sed -i "s|@HISTFILE@|${HISTFILE}|g" "$BASH_RC_FILE" +sed -i "s|@LANG@|${LOCALE_LANG}|g" "$BASH_RC_FILE" +sed -i "s|@BUILDENV_VERSION@|${BUILDENV_DISTRO_VERSION}|g" "$BASH_RC_FILE" +sed -i "s|@DOCKER_BUILDENV_GIT_URL@|${DOCKER_BUILDENV_GIT_URL}|g" "$BASH_RC_FILE" +sed -i "s|@LOCAL_HOSTNAME@|${LOCAL_HOSTNAME}|g" "$BASH_RC_FILE" +chown "$USER":"$GROUP_NAME" "$BASH_RC_FILE" + +# Mark container as ready +touch /tmp/container_ready +echo "Container setup complete. Ready to start services..." +echo "Enjoy...!" + +# Start services using runsvdir +exec runsvdir -P /etc/service diff --git a/files/show-env.sh b/files/show-env.sh new file mode 100755 index 0000000..59b2a86 --- /dev/null +++ b/files/show-env.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +echo "" +echo "=== Environment Info for Normal Users, 'sshd', and 'root' ===" +echo "" + +# Read all users from /etc/passwd +while IFS=: read -r username _ uid gid _ home _; do + # Include normal users (UID >= 1000), 'sshd', and 'root' + if [ "$uid" -ge 1000 ] || [ "$username" == "sshd" ] || [ "$username" == "root" ]; then + echo "User: $username" + echo "USER_ID: $uid" + echo "USER_GROUP: $(getent group $gid | cut -d: -f1)" + echo "USER_GROUP_ID: $gid" + + # Git configuration, if available + if [ -f "$home/.gitconfig" ]; then + git_user=$(git config --global --file "$home/.gitconfig" user.name 2>/dev/null) + git_email=$(git config --global --file "$home/.gitconfig" user.email 2>/dev/null) + echo "GIT_USER: ${git_user:-Not configured}" + echo "GIT_EMAIL: ${git_email:-Not configured}" + fi + + # Timezone, Locale, PATH, DISPLAY, and TERM + echo "TIMEZONE: $(cat /etc/timezone)" + + if [ -d "$home" ]; then + locale_lang=$(LANG=$LANG HOME=$home bash -c 'echo $LANG' 2>/dev/null) + user_path=$(HOME=$home bash -c 'echo $PATH' 2>/dev/null) + display_var=$(HOME=$home bash -c 'echo $DISPLAY' 2>/dev/null) + term_var=$(HOME=$home bash -c 'echo $TERM' 2>/dev/null) + echo "LOCALE_LANG: ${locale_lang:-Not set}" + echo "PATH: ${user_path:-Not set}" + echo "DISPLAY: ${display_var:-Not set}" + echo "TERM: ${term_var:-Not set}" + echo "USER_HOME:" + # Limit tree output to 6 levels, max 3 directories per level + tree -L 6 -d "$home" | awk '{count[$1]++; if (count[$1] <= 3) print}' + fi + echo "-------------" + fi +done < /etc/passwd + +echo "=== End of Environment Info ===" diff --git a/terminal-splash.txt b/files/terminal-splash.txt similarity index 100% rename from terminal-splash.txt rename to files/terminal-splash.txt