diff --git a/.github/workflows/debrepo/package_depends.sh b/.github/workflows/debrepo/package_depends.sh index 59f21bf16a..a0fd321bd2 100755 --- a/.github/workflows/debrepo/package_depends.sh +++ b/.github/workflows/debrepo/package_depends.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -27,25 +27,9 @@ function exit_usage() { } case "$1_$2" in -# ubuntu distros -"focal_linux_client") - echo "libc6,libxss1 (>= 1.2.3)" +"focal_linux_client" | "jammy_linux_client" | "buster_linux_client" | "bullseye_linux_client" | "bookworm_linux_client") + echo "libc6,libxss1 (>= 1.2.3),ca-certificates" ;; -"jammy_linux_client") - echo "libc6,libxss1 (>= 1.2.3)" - ;; - -# debian distros -"buster_linux_client") - echo "libc6,libxss1 (>= 1.2.3)" - ;; -"bullseye_linux_client") - echo "libc6,libxss1 (>= 1.2.3)" - ;; -"bookworm_linux_client") - echo "libc6,libxss1 (>= 1.2.3)" - ;; - *) echo "libc6" ;; diff --git a/.github/workflows/debrepo/package_prepare.sh b/.github/workflows/debrepo/package_prepare.sh index 3de2086c8f..e4d24cf704 100755 --- a/.github/workflows/debrepo/package_prepare.sh +++ b/.github/workflows/debrepo/package_prepare.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -33,7 +33,7 @@ function exit_usage() { function prepare_client() { # prepare dir structure - mkdir -p usr/bin + mkdir -p usr/local/bin exit_on_fail mkdir -p etc/boinc-client etc/default etc/init.d exit_on_fail @@ -41,39 +41,54 @@ function prepare_client() { exit_on_fail mkdir -p var/lib/boinc exit_on_fail - mkdir -p etc/bash_completion.d/ + mkdir -p etc/bash_completion.d/ etc/X11/Xsession.d + exit_on_fail + mkdir -p usr/local/share/locale/ + exit_on_fail + mkdir -p DEBIAN exit_on_fail # copy files and directories - mv boinc boinccmd usr/bin/ + mv postinst DEBIAN/ + exit_on_fail + mv boinc boinccmd usr/local/bin/ exit_on_fail mv boinc-client.service usr/lib/systemd/system/ exit_on_fail - cp boinc-client etc/default/ + mv boinc-client.conf etc/default/boinc-client exit_on_fail mv boinc-client etc/init.d/ exit_on_fail - mv boinc-client.conf etc/boinc-client/boinc.conf - exit_on_fail mv boinc.bash etc/bash_completion.d/ exit_on_fail + mv 36x11-common_xhost-boinc etc/X11/Xsession.d/ + exit_on_fail + for dir in $(find ./locale -maxdepth 1 -mindepth 1 -type d); do mkdir -p usr/local/share/$dir/LC_MESSAGES; for file in $(find $dir -type f -iname BOINC-Client.mo); do mv $file usr/local/share/$dir/LC_MESSAGES/; done; done + exit_on_fail + rm -rf locale/ } function prepare_manager() { # prepare dir structure - mkdir -p usr/bin + mkdir -p usr/local/bin exit_on_fail - mkdir -p usr/share/applications usr/share/boinc-manager usr/share/icons/boinc usr/share/locale/boinc + mkdir -p usr/local/share/applications usr/local/share/boinc-manager usr/local/share/icons usr/local/share/locale/ + exit_on_fail + mkdir -p DEBIAN exit_on_fail # copy files and directories - mv boincmgr usr/bin/ + mv boincmgr usr/local/bin/ exit_on_fail - mv boinc.desktop usr/share/applications/ + mv boinc.desktop usr/local/share/applications/ exit_on_fail - mv skins/ usr/share/boinc-manager/ + mv boinc.png usr/local/share/icons/ exit_on_fail - mv locale/* usr/share/locale/boinc/ + mv boinc.svg usr/local/share/icons/ + exit_on_fail + mv skins/ usr/local/share/boinc-manager/ + exit_on_fail + for dir in $(find ./locale -maxdepth 1 -mindepth 1 -type d); do mkdir -p usr/local/share/$dir/LC_MESSAGES; for file in $(find $dir -type f -iname BOINC-Manager.mo); do mv $file usr/local/share/$dir/LC_MESSAGES/; done; done exit_on_fail rm -rf locale/ } @@ -85,9 +100,7 @@ BASEPKG="$2" # name of the artifact type # validity check case "$BASEPKG" in - "linux_client") - ;; - "linux_manager") + "linux_client" | "linux_manager") ;; *) echo "ERROR: Unknown package preparation requested" @@ -111,10 +124,6 @@ exit_on_fail find . -# required for deb package (same for debian and ubuntu) -mkdir -p DEBIAN -exit_on_fail - # specialized prepare case "$BASEPKG" in "linux_client") diff --git a/.github/workflows/debrepo/repo_update.sh b/.github/workflows/debrepo/repo_update.sh index 945751c81d..47ba91d2c4 100755 --- a/.github/workflows/debrepo/repo_update.sh +++ b/.github/workflows/debrepo/repo_update.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License diff --git a/.github/workflows/linux-package.yml b/.github/workflows/linux-package.yml index 82c72ae3f8..663076076d 100644 --- a/.github/workflows/linux-package.yml +++ b/.github/workflows/linux-package.yml @@ -1,6 +1,6 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -92,11 +92,11 @@ jobs: - name: Configure client if: success() && matrix.type == 'client' - run: linux/ci_configure_client.sh + run: linux/ci_configure_client.sh --exec_prefix "/usr/local" - name: Configure manager if: success() && matrix.type == 'manager' - run: linux/ci_configure_manager.sh + run: linux/ci_configure_manager.sh --exec_prefix "/usr/local" - name: Make if: success() @@ -193,6 +193,7 @@ jobs: Package:${PKG_NAME} Version:${PKG_VERSION} Maintainer:${{ env.MANTAINER }} + Build-Depends: debhelper-compat (= 13) Depends:${PKG_DEPS} Architecture:${{ env.ARCH }} Homepage:${{ env.HOMEPAGE }} @@ -325,12 +326,24 @@ jobs: echo "PUBKEY_HASH=$(gpg --list-keys | grep -Eo '([0-9A-F]{40})')" >> $GITHUB_ENV cp "boinc.pub.key" "${{ env.PUBKEY }}" - - name: Create RPM Definition - if: success() + - name: Create RPM client Definition + if: ${{ success() && matrix.type == 'client' }} run: | # Derive the package dependencies for the selected package / os / release combination selected PKG_DEPS=$(bash .github/workflows/rpmrepo/package_depends.sh ${{ matrix.os }} linux_${{ matrix.type }}) PKG_FILELIST=$(bash .github/workflows/rpmrepo/package_filelist.sh ${{ matrix.os }} linux_${{ matrix.type }}) + BOINCUSER=boinc + BOINCGROUP=boinc + BOINCDIR=/var/lib/boinc + + case ${{ matrix.os }} in + "fc37" | "fc38" | "fc39") + CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt" + ;; + "suse15_4" | "suse15_5") + CA_BUNDLE="/etc/ssl/ca-bundle.pem" + ;; + esac cd rpmbuild echo """ @@ -358,6 +371,161 @@ jobs: %install cp -rfa * %{buildroot} + %post + set_perm() { + chown \$2:\$3 \"\$1\" + chmod \$4 \"\$1\" + } + set_perm_recursive() { + chown -R \$2:\$3 \"\$1\" + chmod -R \$4 \"\$1\" + } + set_perm_dir() { + for file in $(ls \"\$1\") + do + path=\"\$1/\${file}\" + set_perm \"\${path}\" \$2 \$3 \$4 + done + } + update_nested_dirs() { + chmod \$2 \"\${1}\" + for file in \$(ls \"\$1\") + do + if [ -d \"\${1}/\${file}\" ] ; then + update_nested_dirs \"\${1}/\${file}\" \$2 + fi + done + } + if ! getent group ${BOINCGROUP} >/dev/null; then + groupadd -r ${BOINCGROUP} + fi + if ! getent passwd ${BOINCUSER} >/dev/null; then + useradd -r -g ${BOINCGROUP} -d ${BOINCDIR} -s /usr/sbin/nologin -c \"BOINC user\" ${BOINCUSER} + fi + if ! getent group ${BOINCGROUP} | grep -q ${BOINCUSER}; then + usermod -a -G ${BOINCGROUP} ${BOINCUSER} + fi + if getent group video >/dev/null; then + if ! getent group video | grep -q ${BOINCUSER}; then + usermod -a -G video ${BOINCUSER} + fi + fi + if getent group render >/dev/null; then + if ! getent group render | grep -q ${BOINCUSER}; then + usermod -a -G render ${BOINCUSER} + fi + fi + if [ -n \"\$SUDO_USER\" ]; then + if ! getent group ${BOINCGROUP} | grep -q \"\$SUDO_USER\"; then + usermod -a -G ${BOINCGROUP} \"\$SUDO_USER\" + fi + fi + if [ ! -d /etc/boinc-client ] ; then + mkdir -p /etc/boinc-client + fi + if [ ! -f ${BOINCDIR}/cc_config.xml ] ; then + echo \"\"\" + + + + \"\"\" > ${BOINCDIR}/cc_config.xml + ln -s ${BOINCDIR}/cc_config.xml /etc/boinc-client/cc_config.xml + fi + if [ ! -f ${BOINCDIR}/global_prefs_override.xml ] ; then + echo \"\"\" + + + + \"\"\" > ${BOINCDIR}/global_prefs_override.xml + ln -s ${BOINCDIR}/global_prefs_override.xml /etc/boinc-client/global_prefs_override.xml + fi + if [ ! -f ${BOINCDIR}/gui_rpc_auth.cfg ] ; then + echo \"\" > ${BOINCDIR}/gui_rpc_auth.cfg + ln -s ${BOINCDIR}/gui_rpc_auth.cfg /etc/boinc-client/gui_rpc_auth.cfg + fi + if [ ! -f ${BOINCDIR}/remote_hosts.cfg ] ; then + echo \"\"\" + # This file contains a list of remote host names or IP addresses (one per line) + # that are allowed to connect to the BOINC client via the GUI RPC interface. + # Only the hosts listed in this file will be allowed to connect. + # Lines starting with '#' and ';' are comments and are ignored. + \"\"\" > ${BOINCDIR}/remote_hosts.cfg + ln -s ${BOINCDIR}/remote_hosts.cfg /etc/boinc-client/remote_hosts.cfg + fi + if [ ! -e ${BOINCDIR}/ca-bundle.crt ] ; then + ln -s ${CA_BUNDLE} ${BOINCDIR}/ca-bundle.crt + fi + set_perm_recursive ${BOINCDIR} ${BOINCUSER} ${BOINCGROUP} u+rw,g+rw,o+r-w + set_perm ${BOINCDIR} ${BOINCUSER} ${BOINCGROUP} 0775 + if [ -f ${BOINCDIR}/gui_rpc_auth.cfg ] ; then + set_perm ${BOINCDIR}/gui_rpc_auth.cfg ${BOINCUSER} ${BOINCGROUP} 0660 + fi + if [ -f ${BOINC_DIR}/remote_hosts.cfg ] ; then + set_perm ${BOINCDIR}/remote_hosts.cfg ${BOINCUSER} ${BOINCGROUP} 0660 + fi + if [ -d ${BOINCDIR}/projects ] ; then + set_perm ${BOINCDIR}/projects ${BOINCUSER} ${BOINCGROUP} 0775 + update_nested_dirs ${BOINCDIR}/projects u+x,g+x,o+x + fi + if [ -d ${BOINCDIR}/slots ] ; then + set_perm ${BOINCDIR}/slots ${BOINCUSER} ${BOINCGROUP} 0775 + update_nested_dirs ${BOINCDIR}/slots u+x,g+x,o+x + fi + if [ -x /bin/systemctl ] ; then + systemctl enable --now boinc-client.service + fi + + %files + ${PKG_FILELIST} + """ > SPECS/${PKG_FULL}.spec + + echo "------------------------" + cat SPECS/${PKG_FULL}.spec + echo "------------------------" + + - name: Create RPM manager Definition + if: ${{ success() && matrix.type == 'manager' }} + run: | + # Derive the package dependencies for the selected package / os / release combination selected + PKG_DEPS=$(bash .github/workflows/rpmrepo/package_depends.sh ${{ matrix.os }} linux_${{ matrix.type }}) + PKG_FILELIST=$(bash .github/workflows/rpmrepo/package_filelist.sh ${{ matrix.os }} linux_${{ matrix.type }}) + + cd rpmbuild + echo """ + Name:${PKG_NAME} + Version:${PKG_VERSION} + Release:${{ github.run_number }} + BuildArch:${{ env.ARCH }} + URL:${{ env.HOMEPAGE }} + Summary:${{ env.DESCRIPTION }} + License:LGPL3+ + Requires:${PKG_DEPS} + + %changelog + # not extracted + + %description + ${{ env.DESCRIPTION }} + + %pre + # nothing build is not done here + + %build + # nothing to build + + %install + cp -rfa * %{buildroot} + + %post + # nothing to do + %files ${PKG_FILELIST} """ > SPECS/${PKG_FULL}.spec @@ -523,13 +691,13 @@ jobs: if: success() uses: actions/download-artifact@v3 with: - name: linux-package_client_fc${{ matrix.OS }}_${{ github.event.pull_request.head.sha }} + name: linux-package_client_fc${{ matrix.os }}_${{ github.event.pull_request.head.sha }} - name: Download manager if: success() uses: actions/download-artifact@v3 with: - name: linux-package_manager_fc${{ matrix.OS }}_${{ github.event.pull_request.head.sha }} + name: linux-package_manager_fc${{ matrix.os }}_${{ github.event.pull_request.head.sha }} - name: Install client and manager if: success() @@ -565,24 +733,19 @@ jobs: - name: Get OS name if: success() run: | - if [[ "${{ matrix.os }}" == "15.4" ]]; then - OS="suse15_4" - elif [[ "${{ matrix.os }}" == "15.5" ]]; then - OS="suse15_5" - fi - echo "OS=${OS}" >> $GITHUB_ENV + echo "OS=`echo ${{ matrix.os }} | sed 's/\./_/g'`" >> $GITHUB_ENV - name: Download client if: success() uses: actions/download-artifact@v3 with: - name: linux-package_client_${{ env.OS }}_${{ github.event.pull_request.head.sha }} + name: linux-package_client_suse${{ env.OS }}_${{ github.event.pull_request.head.sha }} - name: Download manager if: success() uses: actions/download-artifact@v3 with: - name: linux-package_manager_${{ env.OS }}_${{ github.event.pull_request.head.sha }} + name: linux-package_manager_suse${{ env.OS }}_${{ github.event.pull_request.head.sha }} - name: Install client and manager if: success() diff --git a/.github/workflows/rpmrepo/package_depends.sh b/.github/workflows/rpmrepo/package_depends.sh index d2ec564d16..2afa265507 100755 --- a/.github/workflows/rpmrepo/package_depends.sh +++ b/.github/workflows/rpmrepo/package_depends.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -25,12 +25,12 @@ function exit_usage() { case "$1_$2" in # fedora distros -"fc*_linux_client") - echo "glibc,libXScrnSaver >= 1.2.3" +"fc37_linux_client" | "fc38_linux_client" | "fc38_linux_client") + echo "glibc,libXScrnSaver >= 1.2.3,ca-certificates" ;; # opensuse distros -"suse*_linux_client") - echo "glibc,libXss1 >= 1.2.3" +"suse15_4_linux_client" | "suse15_5_linux_client") + echo "glibc,libXss1 >= 1.2.2,ca-certificates" ;; *) echo "glibc" diff --git a/.github/workflows/rpmrepo/package_filelist.sh b/.github/workflows/rpmrepo/package_filelist.sh index 82e8863af4..86667b5ee8 100755 --- a/.github/workflows/rpmrepo/package_filelist.sh +++ b/.github/workflows/rpmrepo/package_filelist.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -18,104 +18,25 @@ # along with BOINC. If not, see . case "$1_$2" in -# fedora variants -"fc37_linux_client") - echo """/etc/boinc-client/* -/etc/default/* +"fc37_linux_client" | "fc38_linux_client" | "fc39_linux_client" | "suse15_4_linux_client" | "suse15_5_linux_client") + echo """/etc/default/* /etc/init.d/* /etc/bash_completion.d/* +/etc/X11/Xsession.d/* /var/lib/* /usr/lib/systemd/system/* -/usr/bin/* -/usr/lib/* -""" - ;; -"fc38_linux_client") - echo """/etc/boinc-client/* -/etc/default/* -/etc/init.d/* -/etc/bash_completion.d/* -/var/lib/* -/usr/lib/systemd/system/* -/usr/bin/* -/usr/lib/* -""" - ;; -"fc39_linux_client") - echo """/etc/boinc-client/* -/etc/default/* -/etc/init.d/* -/etc/bash_completion.d/* -/var/lib/* -/usr/lib/systemd/system/* -/usr/bin/* +/usr/local/bin/* /usr/lib/* +/usr/local/share/locale/* """ ;; -"fc37_linux_manager") - echo """/usr/bin/* -/usr/share/applications/* -/usr/share/boinc-manager/* -/usr/share/locale/boinc/* -/usr/share/icons/boinc -""" - ;; -"fc38_linux_manager") - echo """/usr/bin/* -/usr/share/applications/* -/usr/share/boinc-manager/* -/usr/share/locale/boinc/* -/usr/share/icons/boinc -""" - ;; -"fc39_linux_manager") - echo """/usr/bin/* -/usr/share/applications/* -/usr/share/boinc-manager/* -/usr/share/locale/boinc/* -/usr/share/icons/boinc -""" - ;; - -# suse variants -"suse15_4_linux_client") - echo """/etc/boinc-client/* -/etc/default/* -/etc/init.d/* -/etc/bash_completion.d/* -/var/lib/* -/usr/lib/systemd/system/* -/usr/bin/* -/usr/lib/* -""" - ;; -"suse15_5_linux_client") - echo """/etc/boinc-client/* -/etc/default/* -/etc/init.d/* -/etc/bash_completion.d/* -/var/lib/* -/usr/lib/systemd/system/* -/usr/bin/* -/usr/lib/* -""" - ;; - -"suse15_5_linux_manager") - echo """/usr/bin/* -/usr/share/applications/* -/usr/share/boinc-manager/* -/usr/share/locale/boinc/* -/usr/share/icons/boinc -""" - ;; -"suse15_4_linux_manager") - echo """/usr/bin/* -/usr/share/applications/* -/usr/share/boinc-manager/* -/usr/share/locale/boinc/* -/usr/share/icons/boinc +"fc37_linux_manager" | "fc38_linux_manager" | "fc39_linux_manager" | "suse15_4_linux_manager" | "suse15_5_linux_manager") + echo """/usr/local/bin/* +/usr/local/share/applications/* +/usr/local/share/boinc-manager/* +/usr/local/share/locale/* +/usr/local/share/icons/* """ ;; diff --git a/.github/workflows/rpmrepo/package_prepare.sh b/.github/workflows/rpmrepo/package_prepare.sh index 112ba253a2..7de93e45b8 100755 --- a/.github/workflows/rpmrepo/package_prepare.sh +++ b/.github/workflows/rpmrepo/package_prepare.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -40,7 +40,7 @@ RPM_BUILDROOT=$ROOT/rpmbuild/BUILD function prepare_client() { # prepare dir structure - mkdir -p $RPM_BUILDROOT/usr/bin + mkdir -p $RPM_BUILDROOT/usr/local/bin exit_on_fail mkdir -p $RPM_BUILDROOT/etc/boinc-client $RPM_BUILDROOT/etc/default $RPM_BUILDROOT/etc/init.d exit_on_fail @@ -48,39 +48,48 @@ function prepare_client() { exit_on_fail mkdir -p $RPM_BUILDROOT/var/lib/boinc exit_on_fail - mkdir -p $RPM_BUILDROOT/etc/bash_completion.d/ + mkdir -p $RPM_BUILDROOT/etc/bash_completion.d/ $RPM_BUILDROOT/etc/X11/Xsession.d + exit_on_fail + mkdir -p $RPM_BUILDROOT/usr/local/share/locale/ exit_on_fail # copy files and directories - mv boinc boinccmd $RPM_BUILDROOT/usr/bin/ + mv boinc boinccmd $RPM_BUILDROOT/usr/local/bin/ exit_on_fail mv boinc-client.service $RPM_BUILDROOT/usr/lib/systemd/system/ exit_on_fail - cp boinc-client $RPM_BUILDROOT/etc/default/ + mv boinc-client.conf $RPM_BUILDROOT/etc/default/boinc-client exit_on_fail mv boinc-client $RPM_BUILDROOT/etc/init.d/ exit_on_fail - mv boinc-client.conf $RPM_BUILDROOT/etc/boinc-client/boinc.conf - exit_on_fail mv boinc.bash $RPM_BUILDROOT/etc/bash_completion.d/ exit_on_fail + mv 36x11-common_xhost-boinc $RPM_BUILDROOT/etc/X11/Xsession.d/ + exit_on_fail + for dir in $(find ./locale -maxdepth 1 -mindepth 1 -type d); do mkdir -p $RPM_BUILDROOT/usr/local/share/$dir/LC_MESSAGES; for file in $(find $dir -type f -iname BOINC-Client.mo); do mv $file $RPM_BUILDROOT/usr/local/share/$dir/LC_MESSAGES/; done; done + exit_on_fail + rm -rf locale/ } function prepare_manager() { # prepare dir structure - mkdir -p $RPM_BUILDROOT/usr/bin + mkdir -p $RPM_BUILDROOT/usr/local/bin exit_on_fail - mkdir -p $RPM_BUILDROOT/usr/share/applications $RPM_BUILDROOT/usr/share/boinc-manager $RPM_BUILDROOT/usr/share/icons/boinc $RPM_BUILDROOT/usr/share/locale/boinc + mkdir -p $RPM_BUILDROOT/usr/local/share/applications $RPM_BUILDROOT/usr/local/share/boinc-manager $RPM_BUILDROOT/usr/local/share/icons $RPM_BUILDROOT/usr/local/share/locale exit_on_fail # copy files and directories - mv boincmgr $RPM_BUILDROOT/usr/bin/ + mv boincmgr $RPM_BUILDROOT/usr/local/bin/ exit_on_fail - mv boinc.desktop $RPM_BUILDROOT/usr/share/applications/ + mv boinc.desktop $RPM_BUILDROOT/usr/local/share/applications/ exit_on_fail - mv skins/ $RPM_BUILDROOT/usr/share/boinc-manager/ + mv boinc.png $RPM_BUILDROOT/usr/local/share/icons exit_on_fail - mv locale/* $RPM_BUILDROOT/usr/share/locale/boinc/ + mv boinc.svg $RPM_BUILDROOT/usr/local/share/icons + exit_on_fail + mv skins/ $RPM_BUILDROOT/usr/local/share/boinc-manager/ + exit_on_fail + for dir in $(find ./locale -maxdepth 1 -mindepth 1 -type d); do mkdir -p $RPM_BUILDROOT/usr/local/share/$dir/LC_MESSAGES; for file in $(find $dir -type f -iname BOINC-Manager.mo); do mv $file $RPM_BUILDROOT/usr/local/share/$dir/LC_MESSAGES/; done; done exit_on_fail rm -rf locale/ } diff --git a/.github/workflows/rpmrepo/repo_update.sh b/.github/workflows/rpmrepo/repo_update.sh index 4fdd3f281e..5a0772d3ab 100755 --- a/.github/workflows/rpmrepo/repo_update.sh +++ b/.github/workflows/rpmrepo/repo_update.sh @@ -2,7 +2,7 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License diff --git a/3rdParty/vcpkg_ports/configs/client/vcpkg.json b/3rdParty/vcpkg_ports/configs/client/vcpkg.json index 9e4ae58669..9c0913228b 100644 --- a/3rdParty/vcpkg_ports/configs/client/vcpkg.json +++ b/3rdParty/vcpkg_ports/configs/client/vcpkg.json @@ -11,6 +11,7 @@ "name": "openssl", "features": ["ssl3", "weak-ssl-ciphers"], "default-features": false - } + }, + "freetype" ] } diff --git a/3rdParty/vcpkg_ports/configs/manager/linux/vcpkg.json b/3rdParty/vcpkg_ports/configs/manager/linux/vcpkg.json index 32c5f8de02..a53e5e2711 100644 --- a/3rdParty/vcpkg_ports/configs/manager/linux/vcpkg.json +++ b/3rdParty/vcpkg_ports/configs/manager/linux/vcpkg.json @@ -15,6 +15,7 @@ { "name": "wxwidgets", "default-features": false - } + }, + "freetype" ] } diff --git a/deploy/prepare_deployment.py b/deploy/prepare_deployment.py index dd1e6ae3f0..350bec7730 100644 --- a/deploy/prepare_deployment.py +++ b/deploy/prepare_deployment.py @@ -1,6 +1,6 @@ # This file is part of BOINC. # http://boinc.berkeley.edu -# Copyright (C) 2023 University of California +# Copyright (C) 2024 University of California # # BOINC is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License @@ -25,7 +25,10 @@ linux_client_list = [ './client/scripts/boinc-client.service', './client/scripts/boinc-client', './client/scripts/boinc.bash', - './client/scripts/boinc-client.conf' + './client/scripts/boinc-client.conf', + './packages/deb/*', + './packages/generic/36x11-common_xhost-boinc', + 'locale/*/*.mo', ] linux_apps_list = [ @@ -50,6 +53,8 @@ linux_manager_list = [ './clientgui/boincmgr', './clientgui/skins', './clientgui/res/boinc.desktop', + './clientgui/res/boinc.png', + './clientgui/res/boinc.svg', 'locale/*/*.mo', ] diff --git a/linux/ci_configure_client.sh b/linux/ci_configure_client.sh index 523a8c26de..04bf2c0803 100755 --- a/linux/ci_configure_client.sh +++ b/linux/ci_configure_client.sh @@ -1,6 +1,40 @@ #!/bin/sh + +# This file is part of BOINC. +# https://boinc.berkeley.edu +# Copyright (C) 2024 University of California +# +# BOINC is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. +# +# BOINC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with BOINC. If not, see . + set -e +exec_prefix="" + +while [ $# -gt 0 ]; do + key="$1" + case $key in + --exec_prefix) + exec_prefix="--exec_prefix=$2" + shift + ;; + *) + echo "unrecognized option $key" + ;; + esac + shift # past argument or value +done + if [ ! -d "linux" ]; then echo "start this script in the source root directory" exit 1 @@ -13,4 +47,4 @@ export VCPKG_DIR="$VCPKG_ROOT/installed/x64-linux" linux/update_vcpkg_client.sh export _libcurl_pc="$VCPKG_DIR/lib/pkgconfig/libcurl.pc" -./configure --with-libcurl=$VCPKG_DIR --with-ssl=$VCPKG_DIR --disable-server --enable-client --disable-manager +./configure --with-libcurl=$VCPKG_DIR --with-ssl=$VCPKG_DIR --disable-server --enable-client --disable-manager $exec_prefix diff --git a/linux/ci_configure_manager.sh b/linux/ci_configure_manager.sh index 004afc554f..41eb885f30 100755 --- a/linux/ci_configure_manager.sh +++ b/linux/ci_configure_manager.sh @@ -1,6 +1,40 @@ #!/bin/sh + +# This file is part of BOINC. +# https://boinc.berkeley.edu +# Copyright (C) 2024 University of California +# +# BOINC is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. +# +# BOINC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with BOINC. If not, see . + set -e +exec_prefix="" + +while [ $# -gt 0 ]; do + key="$1" + case $key in + --exec_prefix) + exec_prefix="--exec_prefix=$2" + shift + ;; + *) + echo "unrecognized option $key" + ;; + esac + shift # past argument or value +done + if [ ! -d "linux" ]; then echo "start this script in the source root directory" exit 1 @@ -16,4 +50,4 @@ linux/update_vcpkg_manager.sh export _libcurl_pc="$VCPKG_DIR/lib/pkgconfig/libcurl.pc" export PKG_CONFIG_PATH=$VCPKG_DIR/lib/pkgconfig/ -./configure --enable-vcpkg --disable-server --disable-client --with-wx-config=$VCPKG_DIR/tools/wxwidgets/wx-config CPPFLAGS="-DwxDEBUG_LEVEL=0" GTK_LIBS="$(pkg-config --libs gtk+-3.0)" +./configure --enable-vcpkg --disable-server --disable-client --with-wx-config=$VCPKG_DIR/tools/wxwidgets/wx-config CPPFLAGS="-DwxDEBUG_LEVEL=0" GTK_LIBS="$(pkg-config --libs gtk+-3.0)" $exec_prefix diff --git a/packages/deb/postinst b/packages/deb/postinst new file mode 100755 index 0000000000..f9e43abeab --- /dev/null +++ b/packages/deb/postinst @@ -0,0 +1,156 @@ +#!/bin/sh + +# This file is part of BOINC. +# https://boinc.berkeley.edu +# Copyright (C) 2024 University of California +# +# BOINC is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. +# +# BOINC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with BOINC. If not, see . + +set -e + +BOINCUSER=boinc +BOINCGROUP=boinc +BOINCDIR=/var/lib/boinc + +set_perm() { + chown $2:$3 "$1" + chmod $4 "$1" +} + +set_perm_recursive() { + chown -R $2:$3 "$1" + chmod -R $4 "$1" +} + +set_perm_dir() { + for file in $(ls "$1") + do + path="$1/${file}" + set_perm "${path}" $2 $3 $4 + done +} + +update_nested_dirs() { + chmod $2 "${1}" + + for file in $(ls "$1") + do + if [ -d "${1}/${file}" ] ; then + update_nested_dirs "${1}/${file}" $2 + fi + done +} + +if ! getent group ${BOINCGROUP} >/dev/null; then + groupadd -r ${BOINCGROUP} +fi + +if ! getent passwd ${BOINCUSER} >/dev/null; then + useradd -r -g ${BOINCGROUP} -d ${BOINCDIR} -s /usr/sbin/nologin -c "BOINC user" ${BOINCUSER} +fi + +if ! getent group ${BOINCGROUP} | grep -q ${BOINCUSER}; then + usermod -a -G ${BOINCGROUP} ${BOINCUSER} +fi + +if getent group video >/dev/null; then + if ! getent group video | grep -q ${BOINCUSER}; then + usermod -a -G video ${BOINCUSER} + fi +fi + +if getent group render >/dev/null; then + if ! getent group render | grep -q ${BOINCUSER}; then + usermod -a -G render ${BOINCUSER} + fi +fi + +if [ -n "$SUDO_USER" ]; then + if ! getent group ${BOINCGROUP} | grep -q $SUDO_USER; then + usermod -a -G ${BOINCGROUP} $SUDO_USER + fi +fi + +if [ ! -d /etc/boinc-client ] ; then + mkdir -p /etc/boinc-client +fi + +if [ ! -f ${BOINCDIR}/cc_config.xml ] ; then + echo """ + + + + """ > ${BOINCDIR}/cc_config.xml + ln -s ${BOINCDIR}/cc_config.xml /etc/boinc-client/cc_config.xml +fi + +if [ ! -f ${BOINCDIR}/global_prefs_override.xml ] ; then + echo """ + + + + """ > ${BOINCDIR}/global_prefs_override.xml + ln -s ${BOINCDIR}/global_prefs_override.xml /etc/boinc-client/global_prefs_override.xml +fi + +if [ ! -f ${BOINCDIR}/gui_rpc_auth.cfg ] ; then + echo "" > ${BOINCDIR}/gui_rpc_auth.cfg + ln -s ${BOINCDIR}/gui_rpc_auth.cfg /etc/boinc-client/gui_rpc_auth.cfg +fi + +if [ ! -f ${BOINCDIR}/remote_hosts.cfg ] ; then + echo """ + # This file contains a list of remote host names or IP addresses (one per line) + # that are allowed to connect to the BOINC client via the GUI RPC interface. + # Only the hosts listed in this file will be allowed to connect. + # Lines starting with '#' and ';' are comments and are ignored. + """ > ${BOINCDIR}/remote_hosts.cfg + ln -s ${BOINCDIR}/remote_hosts.cfg /etc/boinc-client/remote_hosts.cfg +fi + +if [ ! -e ${BOINCDIR}/ca-bundle.crt ] ; then + ln -s /etc/ssl/certs/ca-certificates.crt ${BOINCDIR}/ca-bundle.crt +fi + +set_perm_recursive ${BOINCDIR} ${BOINCUSER} ${BOINCGROUP} u+rw,g+rw,o+r-w +set_perm ${BOINCDIR} ${BOINCUSER} ${BOINCGROUP} 0775 + +if [ -f ${BOINCDIR}/gui_rpc_auth.cfg ] ; then + set_perm ${BOINCDIR}/gui_rpc_auth.cfg ${BOINCUSER} ${BOINCGROUP} 0660 +fi + +if [ -f ${BOINC_DIR}/remote_hosts.cfg ] ; then + set_perm ${BOINCDIR}/remote_hosts.cfg ${BOINCUSER} ${BOINCGROUP} 0660 +fi + +if [ -d ${BOINCDIR}/projects ] ; then + set_perm ${BOINCDIR}/projects ${BOINCUSER} ${BOINCGROUP} 0775 + update_nested_dirs ${BOINCDIR}/projects u+x,g+x,o+x +fi + +if [ -d ${BOINCDIR}/slots ] ; then + set_perm ${BOINCDIR}/slots ${BOINCUSER} ${BOINCGROUP} 0775 + update_nested_dirs ${BOINCDIR}/slots u+x,g+x,o+x +fi + +if [ -x /bin/systemctl ] ; then + systemctl enable --now boinc-client.service +fi diff --git a/packages/generic/36x11-common_xhost-boinc b/packages/generic/36x11-common_xhost-boinc new file mode 100644 index 0000000000..e08a08b10c --- /dev/null +++ b/packages/generic/36x11-common_xhost-boinc @@ -0,0 +1,24 @@ +# This file is part of BOINC. +# https://boinc.berkeley.edu +# Copyright (C) 2024 University of California +# +# BOINC is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. +# +# BOINC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with BOINC. If not, see . + +BOINCUSER=boinc + +if type xhost >/dev/null; then + if id -u $BOINCUSER >/dev/null; then + xhost +SI:localuser:$BOINCUSER || : + fi +fi diff --git a/tests/linux_package_tests/integration_tests.py b/tests/linux_package_tests/integration_tests.py index b231225b56..4a2ddb7958 100644 --- a/tests/linux_package_tests/integration_tests.py +++ b/tests/linux_package_tests/integration_tests.py @@ -1 +1,164 @@ -print("Here will be integration tests") +# This file is part of BOINC. +# https://boinc.berkeley.edu +# Copyright (C) 2024 University of California +# +# BOINC is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. +# +# BOINC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with BOINC. If not, see . + +import os +import pathlib +import re +import sys +import testset + +class IntegrationTests: + def __init__(self): + self.result = True + self.result &= self.test_files_exist() + self.result &= self.test_version() + self.result &= self.test_user() + self.result &= self.test_selected_values_from_boinc_client_service_file() + self.result &= self.test_files_permissions() + + def _get_test_executable_file_path(self, filename): + path = os.popen("echo $PATH").read().strip() + for p in path.split(":"): + if os.path.exists(os.path.join(p, filename)): + return os.path.join(p, filename) + return "" + + def _get_current_version_number(self): + with open("version.h", "r") as f: + lines = f.readlines() + for line in lines: + res = re.search("#define BOINC_VERSION_STRING \"([\d]+.[\d]+.[\d]+)\"", line) + if res is not None: + return res[1] + return "" + + def _get_version_from_string(self, string): + res = re.search("([\d]+.[\d]+.[\d]+)", string) + if res is not None: + return res[1] + return "" + + def _get_file_version(self, filename): + return self._get_version_from_string(os.popen(("{app} --version").format(app=self._get_test_executable_file_path(filename))).read().strip()) + + def _get_user_exists(self, username): + return os.popen("id -un {username}".format(username=username)).read().strip() == username + + def _get_group_exists(self, groupname): + return os.popen("getent group {groupname}".format(groupname=groupname)).read().strip() != "" + + def _get_user_in_group(self, username, groupname): + return os.popen("id -Gn {username}".format(username=username)).read().strip().find(groupname) != -1 + + def _get_key_value_pairs_from_file(self, filename): + result = {} + with open(filename, "r") as f: + lines = f.readlines() + for line in lines: + if (line.find("=") != -1): + key, value = line.split("=") + result[key.strip()] = value.strip() + return result + + def _get_file_owner(self, filename): + if os.path.islink(filename): + path = pathlib.Path(os.readlink(filename)) + else: + path = pathlib.Path(filename) + return "{owner}:{group}".format(owner=path.owner(), group=path.group()) + + def _get_ca_certificates_file_path(self): + if os.path.exists("/etc/ssl/certs/ca-certificates.crt"): + return "/etc/ssl/certs/ca-certificates.crt" + if os.path.exists("/etc/ssl/ca-bundle.pem"): + return "/etc/ssl/ca-bundle.pem" + return "" + + def test_files_exist(self): + ts = testset.TestSet("Test files exist") + ts.expect_equal("/usr/local/bin/boinc", self._get_test_executable_file_path("boinc"), "Test 'boinc' file location") + ts.expect_equal("/usr/local/bin/boinccmd", self._get_test_executable_file_path("boinccmd"), "Test 'boinccmd' file location") + ts.expect_equal("/usr/local/bin/boincmgr", self._get_test_executable_file_path("boincmgr"), "Test 'boincmgr' file location") + ts.expect_true(os.path.exists("/usr/lib/systemd/system/boinc-client.service"), "Test 'boinc-client.service' file exists in '/usr/lib/systemd/system/'") + ts.expect_true(os.path.exists("/etc/default/boinc-client"), "Test 'boinc-client' file exists in '/etc/default/'") + ts.expect_true(os.path.exists("/etc/init.d/boinc-client"), "Test 'boinc-client' file exists in '/etc/init.d/'") + ts.expect_true(os.path.exists("/etc/bash_completion.d/boinc.bash"), "Test 'boinc.bash' file exists in '/etc/bash_completion.d/'") + ts.expect_true(os.path.exists("/etc/X11/Xsession.d/36x11-common_xhost-boinc"), "Test '36x11-common_xhost-boinc' file exists in '/etc/X11/Xsession.d/'") + ts.expect_true(os.path.exists("/usr/local/share/applications/boinc.desktop"), "Test 'boinc.desktop' file exists in '/usr/local/share/applications/'") + ts.expect_true(os.path.exists("/usr/local/share/icons/boinc.png"), "Test 'boinc.png' file exists in '/usr/local/share/icons/'") + ts.expect_true(os.path.exists("/usr/local/share/icons/boinc.svg"), "Test 'boinc.svg' file exists in '/usr/local/share/icons/'") + ts.expect_true(os.path.exists("/var/lib/boinc/cc_config.xml"), "Test 'cc_config.xml' file exists in '/var/lib/boinc/'") + ts.expect_true(os.path.islink("/etc/boinc-client/cc_config.xml"), "Test '/etc/boinc-client/cc_config.xml' file is a symbolic link") + ts.expect_equal("/var/lib/boinc/cc_config.xml", os.readlink("/etc/boinc-client/cc_config.xml"), "Test '/etc/boinc-client/cc_config.xml' file is a symbolic link to '/var/lib/boinc/cc_config.xml'") + ts.expect_true(os.path.exists("/var/lib/boinc/global_prefs_override.xml"), "Test 'global_prefs_override.xml' file exists in '/var/lib/boinc/'") + ts.expect_true(os.path.islink("/etc/boinc-client/global_prefs_override.xml"), "Test '/etc/boinc-client/global_prefs_override.xml' file is a symbolic link") + ts.expect_equal("/var/lib/boinc/global_prefs_override.xml", os.readlink("/etc/boinc-client/global_prefs_override.xml"), "Test '/etc/boinc-client/global_prefs_override.xml' file is a symbolic link to '/var/lib/boinc/global_prefs_override.xml'") + ts.expect_true(os.path.exists("/var/lib/boinc/remote_hosts.cfg"), "Test 'remote_hosts.cfg' file exists in '/var/lib/boinc/'") + ts.expect_true(os.path.islink("/etc/boinc-client/remote_hosts.cfg"), "Test '/etc/boinc-client/remote_hosts.cfg' file is a symbolic link") + ts.expect_equal("/var/lib/boinc/remote_hosts.cfg", os.readlink("/etc/boinc-client/remote_hosts.cfg"), "Test '/etc/boinc-client/remote_hosts.cfg' file is a symbolic link to '/var/lib/boinc/remote_hosts.cfg'") + ts.expect_true(os.path.exists("/var/lib/boinc/gui_rpc_auth.cfg"), "Test 'gui_rpc_auth.cfg' file exists in '/var/lib/boinc/'") + ts.expect_true(os.path.islink("/etc/boinc-client/gui_rpc_auth.cfg"), "Test '/etc/boinc-client/gui_rpc_auth.cfg' file is a symbolic link") + ts.expect_equal("/var/lib/boinc/gui_rpc_auth.cfg", os.readlink("/etc/boinc-client/gui_rpc_auth.cfg"), "Test '/etc/boinc-client/gui_rpc_auth.cfg' file is a symbolic link to '/var/lib/boinc/gui_rpc_auth.cfg'") + ts.expect_not_equal("", self._get_ca_certificates_file_path(), "Test system 'ca-certificates.crt' file exists") + ts.expect_true(os.path.exists("/var/lib/boinc/ca-bundle.crt"), "Test 'ca-bundle.crt' file exists in '/var/lib/boinc/'") + ts.expect_true(os.path.islink("/var/lib/boinc/ca-bundle.crt"), "Test '/var/lib/boinc/ca-bundle.crt' file is a symbolic link") + ts.expect_equal(self._get_ca_certificates_file_path(), os.readlink("/var/lib/boinc/ca-bundle.crt"), "Test '/var/lib/boinc/ca-bundle.crt' file is a symbolic link to the system 'ca-certificates.crt' file") + return ts.result() + + def test_version(self): + ts = testset.TestSet("Test version is correct") + current_version = self._get_current_version_number() + ts.expect_not_equal("", current_version, "Test current version could be read from the 'version.h' file") + ts.expect_equal(current_version, self._get_file_version("boinc"), "Test 'boinc' version is correctly set") + ts.expect_equal(current_version, self._get_file_version("boinccmd"), "Test 'boinccmd' version is correctly set") + return ts.result() + + def test_user(self): + ts = testset.TestSet("Test 'boinc' user and 'boinc' group exist") + ts.expect_true(self._get_user_exists("boinc"), "Test 'boinc' user exists") + ts.expect_true(self._get_group_exists("boinc"), "Test 'boinc' group exists") + ts.expect_true(self._get_user_in_group("boinc", "boinc"), "Test 'boinc' user is in 'boinc' group") + if (self._get_group_exists("video")): + ts.expect_true(self._get_user_in_group("boinc", "video"), "Test 'boinc' user is in 'video' group") + if (self._get_group_exists("render")): + ts.expect_true(self._get_user_in_group("boinc", "render"), "Test 'boinc' user is in 'render' group") + return ts.result() + + def test_selected_values_from_boinc_client_service_file(self): + ts = testset.TestSet("Test selected values from the '/usr/lib/systemd/system/boinc-client.service' file") + data = self._get_key_value_pairs_from_file("/usr/lib/systemd/system/boinc-client.service") + ts.expect_equal(data["ReadWritePaths"], "-/var/lib/boinc -/etc/boinc-client", "Test 'ReadWritePaths' is correctly set") + ts.expect_equal(data["User"], "boinc", "Test 'User' is correctly set") + ts.expect_equal(data["WorkingDirectory"], "/var/lib/boinc", "Test 'WorkingDirectory' is correctly set") + ts.expect_equal(data["ExecStart"], "/usr/local/bin/boinc", "Test 'ExecStart' is correctly set") + ts.expect_equal(data["ExecStop"], "/usr/local/bin/boinccmd --quit", "Test 'ExecStop' is correctly set") + ts.expect_equal(data["ExecReload"], "/usr/local/bin/boinccmd --read_cc_config", "Test 'ExecReload' is correctly set") + ts.expect_equal(data["ExecStopPost"], "/bin/rm -f lockfile", "Test 'ExecStopPost' is correctly set") + return ts.result() + + def test_files_permissions(self): + ts = testset.TestSet("Test files permissions") + ts.expect_equal("boinc:boinc", self._get_file_owner("/var/lib/boinc/cc_config.xml"), "Test '/var/lib/boinc/cc_config.xml' file owner") + ts.expect_equal("boinc:boinc", self._get_file_owner("/var/lib/boinc/global_prefs_override.xml"), "Test '/var/lib/boinc/global_prefs_override.xml' file owner") + ts.expect_equal("boinc:boinc", self._get_file_owner("/var/lib/boinc/remote_hosts.cfg"), "Test '/var/lib/boinc/remote_hosts.cfg' file owner") + ts.expect_equal("boinc:boinc", self._get_file_owner("/var/lib/boinc/gui_rpc_auth.cfg"), "Test '/var/lib/boinc/gui_rpc_auth.cfg' file owner") + return ts.result() + +if __name__ == "__main__": + if not IntegrationTests().result: + sys.exit(1) + sys.exit(0) diff --git a/tests/linux_package_tests/testset.py b/tests/linux_package_tests/testset.py new file mode 100644 index 0000000000..78fc35eb6b --- /dev/null +++ b/tests/linux_package_tests/testset.py @@ -0,0 +1,70 @@ +# This file is part of BOINC. +# https://boinc.berkeley.edu +# Copyright (C) 2024 University of California +# +# BOINC is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, +# either version 3 of the License, or (at your option) any later version. +# +# BOINC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with BOINC. If not, see . + +class TestSet: + def __init__(self, name): + self.name = name + self.passed = 0 + self.failed = 0 + print(("Running test set [{name}]...").format(name=self.name)) + + def __del__(self): + print(("Test set [{name}]: \033[92mpassed [{passed}]\033[0m, \033[91mfailed [{failed}]\033[0m.").format(name=self.name, passed=self.passed, failed=self.failed)) + + def _print_success_report(self, test_name): + self.passed += 1 + self._print_success(("Passed [{test_name}]").format(test_name=test_name)) + + def _print_success(self, message): + print(("\033[92m{message}\033[0m").format(message=message)) + + def _print_failure(self, message): + print(("\033[91m{message}\033[0m").format(message=message)) + + def result(self): + return self.failed == 0 + + def expect_true(self, condition, test_name): + if not condition: + self.failed += 1 + self._print_failure(("Failed [{test_name}]: expected True, got False").format(test_name=test_name)) + return False + self._print_success_report(test_name) + return True + + def expect_false(self, condition, test_name): + if condition: + self.failed += 1 + self._print_failure(("Failed [{test_name}]: expected False, got True").format(test_name=test_name)) + return False + self._print_success_report(test_name) + return True + + def expect_equal(self, expected, actual, test_name): + if expected != actual: + self.failed += 1 + self._print_failure(("Failed [{test_name}]: expected [{expected}], got [{actual}]").format(test_name=test_name, expected=expected, actual=actual)) + return False + self._print_success_report(test_name) + return True + + def expect_not_equal(self, a, b, test_name): + if a == b: + self.failed += 1 + self._print_failure(("Failed [{test_name}]: expected {a} != {b}").format(test_name=test_name, a=a, b=b)) + return False + self._print_success_report(test_name)