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)