#!/bin/bash # -------------------------------------------------------------------- # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # --------------------------------------------------------------------- # ---------------------------------------------------------------------------- # Packaging script for SaiCore, for Debian-compatible distributions. # # This should be run after `build.sh`. # # The generated package structure is as follows : # # DEBIAN/ # | control # | md5sums # | prerm # | postinst # usr/ # | bin/ # | | SaiCore <-- actually a symlink to run.sh or SaiCore # | share/ # | | applications/ # | | | SaiCore.desktop # opt/ # | SaiCore/ # | | library/ # | | etc/ # | | qtlib/ (*) # | | plugins/ (*) # | | SaiCore # | | SaiCore.png # | | run.sh (*) # # (*) Only included if Qt libs and plugins are bundled. It is necessary to # bundle these if the target system doesn't provide Qt 5.5.1, for example. # ---------------------------------------------------------------------------- initializeVariables() { # This script's path SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" PROJECT_ROOT="$SCRIPT_PATH/../.." # Where the application was built (see build.sh) BUILD_DIR="$PROJECT_ROOT/build/linux/release" PRODUCT_PATH="$BUILD_DIR/product" # Where the package is built to PACKAGE_BUILD_DIR="$PROJECT_ROOT/install" # Temporary folder, where we put all the files that will be built into the # package BASE_WORKING_DIR="debianPackage" APPLICATION_NAME="SaiCore" APPLICATION_CODE="SaiCore" APPLICATION_PATH="opt" PACKAGE_DIRECTORY=$BASE_WORKING_DIR/$APPLICATION_PATH/$APPLICATION_CODE PACKAGE_QT_DIRECTORY="$PACKAGE_DIRECTORY/qt" QT_LIBRARY_DEST_PATH="$PACKAGE_QT_DIRECTORY/lib" QT_LIBRARY_EXECUTABLES_DEST_PATH="$PACKAGE_QT_DIRECTORY/libexec" QT_PLUGINS_DEST_PATH="$PACKAGE_QT_DIRECTORY/plugins" QT_RESOURCES_DEST_PATH="$PACKAGE_QT_DIRECTORY/resources" QT_TRANSLATIONS_DEST_PATH="$PACKAGE_QT_DIRECTORY/translations" DESKTOP_FILE_PATH="$BASE_WORKING_DIR/usr/share/applications" APPLICATION_SHORTCUT="$DESKTOP_FILE_PATH/${APPLICATION_CODE}.desktop" DESCRIPTION="SaiCore, an interactive white board application" VERSION=`cat $BUILD_DIR/version` ARCHITECTURE=`cat buildContext` # Include Qt libraries and plugins in the package, or not # (this is necessary if the target system doesn't provide Qt 5.5.1) BUNDLE_QT=true # Qt installation path. This may vary across machines QT_PATH="/home/dev/Qt/6.9.3/gcc_64" QT_SHARE_PATH="/usr/share/qt5/" GUI_TRANSLATIONS_DIRECTORY_PATH="$QT_PATH/translations" QT_LIBRARY_SOURCE_PATH="$QT_PATH/lib" QT_LIBRARY_EXECUTABLES_SOURCE_PATH="$QT_PATH/libexec" QT_PLUGINS_SOURCE_PATH="$QT_PATH/plugins" QT_RESOURCES_SOURCE_PATH="$QT_PATH/resources" QT_TRANSLATIONS_SOURCE_PATH="$QT_PATH/translations" NOTIFY_CMD=`which notify-send` ZIP_PATH=`which zip` } checkUser() { if [ `id -u` -ne 0 ]; then echo "Please run the script as root" exit 1 fi } checkBuild() { if [ -z "$ARCHITECTURE" ]; then echo "Make sure you have built the software first using ./build.sh" exit 1 fi } notifyError(){ if [ -e "$NOTIFY_CMD" ]; then $NOTIFY_CMD -t 0 -i "/usr/share/icons/oxygen/64x64/status/dialog-error.png" "$1" fi printf "\033[31merror:\033[0m $1\n" exit 1 } notifyProgress(){ if [ -e "$NOTIFY_CMD" ]; then $NOTIFY_CMD "$1" "$2" fi printf "\033[32m--> \033[0m $1:\n\t$2\n" } copyQtLibrary(){ echo -e "\t $1" if ls "$QT_LIBRARY_SOURCE_PATH/$1.so" &> /dev/null; then cp -P $QT_LIBRARY_SOURCE_PATH/$1.so "$QT_LIBRARY_DEST_PATH/" cp -P $QT_LIBRARY_SOURCE_PATH/$1.so.* "$QT_LIBRARY_DEST_PATH/" strip $QT_LIBRARY_DEST_PATH/$1.so chmod 644 $QT_LIBRARY_DEST_PATH/$1.so.* # 644 = rw-r-r else notifyError "$1 library not found in path: $QT_LIBRARY_SOURCE_PATH" fi } copyQtPlugin(){ echo -e "\t $1" if ls "$QT_PLUGINS_SOURCE_PATH/$1" &> /dev/null; then cp -r $QT_PLUGINS_SOURCE_PATH/$1 $QT_PLUGINS_DEST_PATH/ strip $QT_PLUGINS_DEST_PATH/$1/* chmod 644 $QT_PLUGINS_DEST_PATH/$1/* # 644 = rw-r-r chmod +rx $QT_PLUGINS_DEST_PATH/$1 else notifyError "$1 plugin not found in path: $QT_PLUGINS_SOURCE_PATH" fi } removeQtDebugFiles() { notifyProgress "removing Qt debug files" find $PACKAGE_QT_DIRECTORY -name "*.debug" -print0 | xargs -0 rm } # ---------------------------------------------------------------------------- # Copying the application, libs etc. to the temporary working directory # ---------------------------------------------------------------------------- initializeVariables checkBuild checkUser cd $PROJECT_ROOT rm -rf $PACKAGE_DIRECTORY mkdir -p $PACKAGE_DIRECTORY rm -rf $PACKAGE_BUILD_DIR notifyProgress "Copying product directory and resources" cp -R $PRODUCT_PATH/* $PACKAGE_DIRECTORY chown -R root:root $PACKAGE_DIRECTORY cp -R resources/customizations $PACKAGE_DIRECTORY/ cp resources/linux/SaiCore-ubz.xml $PACKAGE_DIRECTORY/etc/ cp resources/linux/application-ubz.png $PACKAGE_DIRECTORY/etc/ if $BUNDLE_QT; then cp -R resources/linux/run.sh $PACKAGE_DIRECTORY/ chmod a+x $PACKAGE_DIRECTORY/run.sh fi notifyProgress "Stripping main executable" strip $PACKAGE_DIRECTORY/$APPLICATION_NAME # copying startup hints notifyProgress "copying startupHints" cp -R resources/startupHints $PACKAGE_DIRECTORY/ if $BUNDLE_QT; then notifyProgress "Copying and stripping Qt plugins" mkdir -p $QT_PLUGINS_DEST_PATH #copyQtPlugin audio #copyQtPlugin bearer copyQtPlugin egldeviceintegrations copyQtPlugin generic copyQtPlugin help copyQtPlugin iconengines copyQtPlugin imageformats copyQtPlugin multimedia copyQtPlugin networkinformation copyQtPlugin platforminputcontexts copyQtPlugin platforms copyQtPlugin platformthemes copyQtPlugin position copyQtPlugin printsupport #copyQtPlugin sceneparsers copyQtPlugin tls copyQtPlugin wayland-graphics-integration-client copyQtPlugin wayland-decoration-client copyQtPlugin wayland-graphics-integration-server copyQtPlugin wayland-shell-integration copyQtPlugin xcbglintegrations notifyProgress "Copying and stripping Qt libraries" mkdir -p $QT_LIBRARY_DEST_PATH copyQtLibrary libQt6Concurrent copyQtLibrary libQt6Core copyQtLibrary libQt6Core5Compat copyQtLibrary libQt6DBus copyQtLibrary libQt6Gui copyQtLibrary libQt6Multimedia #copyQtLibrary libQt6MultimediaGstTools copyQtLibrary libQt6MultimediaWidgets copyQtLibrary libQt6Network copyQtLibrary libQt6OpenGL copyQtLibrary libQt6Positioning copyQtLibrary libQt6PrintSupport copyQtLibrary libQt6Qml copyQtLibrary libQt6QmlModels copyQtLibrary libQt6QmlMeta copyQtLibrary libQt6QmlWorkerScript copyQtLibrary libQt6Quick #copyQtLibrary libQt6Sensors copyQtLibrary libQt6Sql copyQtLibrary libQt6Svg copyQtLibrary libQt6WebChannel copyQtLibrary libQt6WebEngineCore copyQtLibrary libQt6WebEngineWidgets copyQtLibrary libQt6QuickWidgets #copyQtLibrary libQt6WebSockets copyQtLibrary libQt6Widgets copyQtLibrary libQt6XcbQpa copyQtLibrary libQt6Xml #copyQtLibrary libQt6XmlPatterns copyQtLibrary libicuuc copyQtLibrary libicui18n copyQtLibrary libicudata removeQtDebugFiles fi notifyProgress "Copying Qt translations" mkdir -p $PACKAGE_DIRECTORY/i18n cp $GUI_TRANSLATIONS_DIRECTORY_PATH/qt_??.qm $PACKAGE_DIRECTORY/i18n/ cp $GUI_TRANSLATIONS_DIRECTORY_PATH/qtbase*.qm $PACKAGE_DIRECTORY/i18n/ #cp $GUI_TRANSLATIONS_DIRECTORY_PATH/qtscript*.qm $PACKAGE_DIRECTORY/i18n/ cp $GUI_TRANSLATIONS_DIRECTORY_PATH/qtmultimedia*.qm $PACKAGE_DIRECTORY/i18n/ #cp $GUI_TRANSLATIONS_DIRECTORY_PATH/qtxmlpatterns*.qm $PACKAGE_DIRECTORY/i18n/ # ---------------------------------------------------------------------------- # QT WebEngine # ---------------------------------------------------------------------------- notifyProgress "Copying Qt WebEngine dependencies" mkdir -p "$QT_LIBRARY_EXECUTABLES_DEST_PATH" cp $QT_LIBRARY_EXECUTABLES_SOURCE_PATH/QtWebEngineProcess $QT_LIBRARY_EXECUTABLES_DEST_PATH mkdir -p "$QT_RESOURCES_DEST_PATH" cp $QT_RESOURCES_SOURCE_PATH/* $QT_RESOURCES_DEST_PATH mkdir -p "$QT_TRANSLATIONS_DEST_PATH/qtwebengine_locales" cp $QT_TRANSLATIONS_SOURCE_PATH/qtwebengine_locales/* $QT_TRANSLATIONS_DEST_PATH/qtwebengine_locales # ---------------------------------------------------------------------------- # FFmpeg # ---------------------------------------------------------------------------- notifyProgress "Copying Qt FFmpeg dependencies" cp $QT_LIBRARY_SOURCE_PATH/libavcodec* $QT_LIBRARY_DEST_PATH/ cp $QT_LIBRARY_SOURCE_PATH/libavformat* $QT_LIBRARY_DEST_PATH/ cp $QT_LIBRARY_SOURCE_PATH/libavutil* $QT_LIBRARY_DEST_PATH/ cp $QT_LIBRARY_SOURCE_PATH/libswscale* $QT_LIBRARY_DEST_PATH/ cp $QT_LIBRARY_SOURCE_PATH/libswresample* $QT_LIBRARY_DEST_PATH/ cp $QT_LIBRARY_SOURCE_PATH/libQt6FFmpegStub* $QT_LIBRARY_DEST_PATH/ # ---------------------------------------------------------------------------- # DEBIAN directory of package (control, md5sums, postinst etc) # ---------------------------------------------------------------------------- notifyProgress "Generating control files for package" mkdir -p "$BASE_WORKING_DIR/DEBIAN" # Copy prerm script cp -r "$SCRIPT_PATH/debian_package_files/prerm" "$BASE_WORKING_DIR/DEBIAN/" chmod 755 "$BASE_WORKING_DIR/DEBIAN/prerm" # Generate postinst script (can't copy it like prerm because some paths vary depending on # the values of the variables in this script) SYMLINK_TARGET="/$APPLICATION_PATH/$APPLICATION_CODE/$APPLICATION_NAME" if $BUNDLE_QT ; then SYMLINK_TARGET="/$APPLICATION_PATH/$APPLICATION_CODE/run.sh" fi cat > "$BASE_WORKING_DIR/DEBIAN/postinst" << EOF #!/bin/bash # -------------------------------------------------------------------- # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # --------------------------------------------------------------------- xdg-desktop-menu install --novendor /usr/share/applications/${APPLICATION_CODE}.desktop xdg-mime install --mode system /$APPLICATION_PATH/$APPLICATION_CODE/etc/SaiCore-ubz.xml xdg-mime default /usr/share/applications/${APPLICATION_CODE}.desktop application/ubz xdg-icon-resource install --context mimetypes --size 48 /$APPLICATION_PATH/$APPLICATION_CODE/etc/application-ubz.png application-ubz ln -s $SYMLINK_TARGET /usr/bin/$APPLICATION_CODE exit 0 EOF chmod 755 "$BASE_WORKING_DIR/DEBIAN/postinst" # Generate md5 sums of everything in the application path (e.g /opt) and the desktop entry cd $BASE_WORKING_DIR find $APPLICATION_PATH/ -exec md5sum {} > DEBIAN/md5sums 2>/dev/null \; find $DESKTOP_FILE_PATH/ -exec md5sum {} >> DEBIAN/md5sums 2>/dev/null \; cd $PROJECT_ROOT # Generate control file CONTROL_FILE="$BASE_WORKING_DIR/DEBIAN/control" echo "Package: ${APPLICATION_CODE}" > "$CONTROL_FILE" echo "Version: $VERSION" >> "$CONTROL_FILE" echo "Section: education" >> "$CONTROL_FILE" echo "Priority: optional" >> "$CONTROL_FILE" echo "Architecture: $ARCHITECTURE" >> "$CONTROL_FILE" echo "Essential: no" >> "$CONTROL_FILE" echo "Installed-Size: `du -s $PACKAGE_DIRECTORY | awk '{ print $1 }'`" >> "$CONTROL_FILE" echo "Maintainer: ${APPLICATION_NAME} Developers team " >> "$CONTROL_FILE" echo "Homepage: https://github.com/DIP-SEM/SaiCore" >> "$CONTROL_FILE" # Generate dependency list echo -n "Depends: " >> "$CONTROL_FILE" unset tab declare -a tab let count=0 if $BUNDLE_QT; then for l in `objdump -p $PACKAGE_DIRECTORY/${APPLICATION_NAME} | grep NEEDED | awk '{ print $2 }'`; do for lib in `dpkg -S $l | grep -v "libqt5" | grep -v "qt55" | awk -F":" '{ print $1 }'`; do presence=`echo ${tab[*]} | grep -c "$lib"`; if [ "$presence" == "0" ]; then if [ "$lib" != "SaiCore" ]; then echo "adding $lib to needed dependencies" tab[$count]=$lib; ((count++)); fi; fi; done; done; else for l in `objdump -p $PACKAGE_DIRECTORY/${APPLICATION_NAME} | grep NEEDED | awk '{ print $2 }'`; do for lib in `dpkg -S $l | awk -F":" '{ print $1 }'`; do presence=`echo ${tab[*]} | grep -c "$lib"`; if [ "$presence" == "0" ]; then tab[$count]=$lib; ((count++)); fi; done; done; fi for ((i=0;i<${#tab[@]};i++)); do if [ $i -ne "0" ]; then echo -n ", " >> "$CONTROL_FILE" fi # conditional dependency when libavcodec is found depdVer=$(apt-cache show ${tab[$i]} | grep "Version: " | head -1 | awk '{ print $2 }' | sed -e 's/\([~:. 0-9?]*\).*/\1/g' | sed -e 's/\.$//') if [[ "${tab[$i]}" == *"libavcodec"* ]]; then depName="${tab[$i]::-2}" versionNumber="${tab[$i]: -2}" depdVer_part1=`echo ${depdVer} | awk -F'.' '{print $1}'` depdVer_part2=`echo ${depdVer} | awk -F'.' '{print $2}'` echo -n "${depName}${versionNumber} (>= ${depdVer_part1}.${depdVer_part2}) | ${depName}-extra${versionNumber} (>= ${depdVer_part1}.${depdVer_part2})" >> "$CONTROL_FILE" else echo -n "${tab[$i]} (>= ${depdVer})" >> "$CONTROL_FILE" fi done echo -n ", onboard" >> "$CONTROL_FILE" if $BUNDLE_QT; then # Listing some dependencies manually; ideally we should use dpkg -p recursively # to get the dependencies of the bundled shared libs & plugins. Or use static libs. echo -n ", libxcb1" >> "$CONTROL_FILE" echo -n ", libxcb-icccm4" >> "$CONTROL_FILE" echo -n ", libxcb-xkb1" >> "$CONTROL_FILE" echo -n ", libxcb-image0" >> "$CONTROL_FILE" echo -n ", libxcb-render-util0" >> "$CONTROL_FILE" echo -n ", libxcb-xinerama0" >> "$CONTROL_FILE" else echo -n ", libqt5multimedia5-plugins" >> "$CONTROL_FILE" fi echo "" >> "$CONTROL_FILE" echo "Description: $DESCRIPTION" >> "$CONTROL_FILE" # ---------------------------------------------------------------------------- # .desktop file # ---------------------------------------------------------------------------- mkdir -p $DESKTOP_FILE_PATH echo "[Desktop Entry]" > $APPLICATION_SHORTCUT echo "Version=$VERSION" >> $APPLICATION_SHORTCUT echo "Encoding=UTF-8" >> $APPLICATION_SHORTCUT echo "Name=${APPLICATION_NAME}" >> $APPLICATION_SHORTCUT echo "Comment=$DESCRIPTION" >> $APPLICATION_SHORTCUT echo "Exec=$APPLICATION_CODE %f" >> $APPLICATION_SHORTCUT echo "Icon=/$APPLICATION_PATH/$APPLICATION_CODE/${APPLICATION_NAME}.png" >> $APPLICATION_SHORTCUT echo "StartupNotify=true" >> $APPLICATION_SHORTCUT echo "Terminal=false" >> $APPLICATION_SHORTCUT echo "Type=Application" >> $APPLICATION_SHORTCUT echo "MimeType=application/ubz" >> $APPLICATION_SHORTCUT echo "Categories=Education;" >> $APPLICATION_SHORTCUT cp "resources/images/${APPLICATION_NAME}.png" "$PACKAGE_DIRECTORY/${APPLICATION_NAME}.png" # ---------------------------------------------------------------------------- # Building the package # ---------------------------------------------------------------------------- notifyProgress "Building package" mkdir -p "$PACKAGE_BUILD_DIR/linux" PACKAGE_NAME="${APPLICATION_NAME}_`lsb_release -is`_`lsb_release -rs`_${VERSION}_$ARCHITECTURE.deb" PACKAGE_NAME=`echo "$PACKAGE_NAME" | awk '{print tolower($0)}'` dpkg -b "$BASE_WORKING_DIR" "$PACKAGE_BUILD_DIR/linux/$PACKAGE_NAME" #clean up mess rm -rf $BASE_WORKING_DIR notifyProgress "${APPLICATION_NAME}" "Package built" exit 0