A script to automate the creation of AppImages and to upload the finished AppImage to a server
This AppImage can update itself. I use zsync to update. Which means that very little data has to be downloaded when updating.
The script detects whether it is 32- or 64-bit architecture.
You need to edit to match the versions of Qt you are using. You also need to adapt the script to the folder structure of the server to which you upload the finished AppImage.
The script also creates a text file with information about the AppImage's MD5 sum, the ApppImage's size and the date and time of the upload. The text file is uploaded at the same time as the AppImage is uploaded to the server.
Light | Dark
# EDIT
QT5=5.15.10
QT6=6.5.2
EXECUTABLE=streamcapture2
SUPORTEDGLIBC=2.31
# STOP EDIT
BIN_DIR="/bin.ceicer.com/public_html/${EXECUTABLE}/bin/linux/GLIBC${GLIBCVERSION}"
ZSYNC_ADDRESS="http://bin.ceicer.com/zsync/${EXECUTABLE}/GLIBC${GLIBCVERSION}/"
ZSYNC_DIR="/bin.ceicer.com/public_html/zsync/${EXECUTABLE}/GLIBC${GLIBCVERSION}"
My script uses
Example (Double click for full screen)
Download script
I use a small c++ program so that the script knows which GLIBC version is used when creating the AppImage. A script works just as well.
The source code for the c++ program | Light | Dark | Copy to clipboard
#include <stdio.h>
#ifdef __GLIBC__
#include <gnu/libc-version.h>
#endif
int main(void)
{
#ifdef __GLIBC__
printf("%u.%u\n", __GLIBC__, __GLIBC_MINOR__);
return 0;
#else
return 1;
#endif
}
build_appimage.sh | Light | Dark | Open in new tab | Copy to clipboard
#!/bin/bash
# build_appimage.sh Copyright (C) 2023 Ingemar Ceicer
# https://ceicer.eu
# programming@ceicer.com
# build_appimage.sh 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, version 3.
# 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.
# EDIT
QT5=5.15.10
QT6=6.5.2
EXECUTABLE=streamcapture2
SUPORTEDGLIBC=2.31
# STOP EDIT
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
BOLD=$(tput bold)
NORMAL=$(tput sgr0)
GLIBCVERSION=$(glibcversion)
READMORE=https://gitlab.com/posktomten/${EXECUTABLE}
if [ $(getconf LONG_BIT) = 64 ]; then
GCC="gcc_64"
else
GCC="gcc_32"
fi
function doZsynkMake() {
PS3=$(echo -e "${BLUE}Pleas Select Stable or BETA ${NC}")
stable_or_beta=("Stable" "BETA" "Quit")
select opt in "${stable_or_beta[@]}"; do
case "$opt" in
"Stable")
BIN_DIR="/bin.ceicer.com/public_html/${EXECUTABLE}/bin/linux/GLIBC${GLIBCVERSION}"
ZSYNC_ADDRESS="http://bin.ceicer.com/zsync/${EXECUTABLE}/GLIBC${GLIBCVERSION}/"
ZSYNC_DIR="/bin.ceicer.com/public_html/zsync/${EXECUTABLE}/GLIBC${GLIBCVERSION}"
echo "${EXECUTABLE} AppImage will be uploaded to"
echo $BIN_DIR
break
;;
"BETA")
BIN_DIR="/bin.ceicer.com/public_html/${EXECUTABLE}/bin/linux/GLIBC${GLIBCVERSION}/BETA"
ZSYNC_ADDRESS="http://bin.ceicer.com/zsync/${EXECUTABLE}/GLIBC${GLIBCVERSION}/BETA/"
ZSYNC_DIR="/bin.ceicer.com/public_html/zsync/${EXECUTABLE}/GLIBC${GLIBCVERSION}/BETA"
echo "${EXECUTABLE} AppImage will be uploaded to"
echo $BIN_DIR
break
;;
"Quit")
echo "Goodbye!"
exit 0
break
;;
esac
done
whitespace=" "
date_now=$(date "+%F %H:%M:%S")
for i in *.AppImage; do
filelenght=$(("${#i}" + 41))
#if [[ $filelenght -le 57 ]] ;
# then
# filelenght=56
#fi
streck=""
while [[ ${#streck} -le ${filelenght} ]]; do
streck="${streck}-"
done
echo "${streck}" >"$i-MD5.txt"
echo "MD5 HASH SUM" >>"$i-MD5.txt"
md5sum "$i" >>"$i-MD5.txt"
echo "${streck}" >>"$i-MD5.txt"
filesize=$(stat -c%s "$i")
mb=$(bc <<<"scale=6; $filesize / 1048576")
mb2=$(echo $mb | awk '{printf "%f", $1 + $2}')
echo "Uploaded: $date_now" >>"$i-MD5.txt"
echo "Size:$whitespace$mb2 MB" >>"$i-MD5.txt"
echo "$i" requires GLIBC higher than or equal to "${GLIBCVERSION}" >>"$i-MD5.txt"
echo "${streck}" >>"$i-MD5.txt"
echo "HOW TO CHECK THE HASH SUM" >>"$i-MD5.txt"
echo "${streck}" >>"$i-MD5.txt"
echo "LINUX" >>"$i-MD5.txt"
echo "\"md5sum\" is included in most Linus distributions." >>"$i-MD5.txt"
echo "md5sum $i" >>"$i-MD5.txt"
echo "${streck}" >>"$i-MD5.txt"
echo "WINDOWS" >>"$i-MD5.txt"
echo "\"certutil\" is included in Windows." >>"$i-MD5.txt"
echo "certutil -hashfile $i md5" >>"$i-MD5.txt"
echo "${streck}" >>"$i-MD5.txt"
echo "READ MORE" >>"$i-MD5.txt"
echo "$READMORE" >>"$i-MD5.txt"
echo "${streck}" >>"$i-MD5.txt"
echo
echo " _ _ _____ _ " >>"$i-MD5.txt"
echo "| | | | __ _ __ __ ___ | ___|_ _ _ __ | |" >>"$i-MD5.txt"
echo "| |_| | / _ |\ \ / // _ \ | |_ | | | || _ \ | |" >>"$i-MD5.txt"
echo "| _ || (_| | \ V /| __/ | _| | |_| || | | ||_|" >>"$i-MD5.txt"
echo "|_| |_| \__,_| \_/ \___| |_| \__,_||_| |_|(_)" >>"$i-MD5.txt"
done
echo "----------------------------------------------------------------"
PS3=$(echo -e "${BLUE}Please enter your choice: ${NC}")
options=("Upload AppImage" "Upload AppImage later" "Quit")
select opt in "${options[@]}"; do
case $opt in
"Upload AppImage")
echo "You chose $REPLY which is $opt"
cp -f *.AppImage ${EXECUTABLE}-zsyncmake/
cp -f *.AppImage-MD5.txt ${EXECUTABLE}-zsyncmake/
cd ${EXECUTABLE}-zsyncmake
for i in *.AppImage; do
./zsyncmake "$i" -u "${ZSYNC_ADDRESS}/${i}"
done
HOST="$(sed -n 1p ../../secret)"
USER="$(sed -n 2p ../../secret)"
PASSWORD="$(sed -n 3p ../../secret)"
for fil in *.AppImage; do
ftp -v -inv $HOST <<EOF
passive
user $USER $PASSWORD
cd "$BIN_DIR"
put $fil
cd "$ZSYNC_DIR"
put $fil
bye
EOF
done
for fil in *.zsync; do
ftp -v -inv $HOST <<EOF
passive
user $USER $PASSWORD
cd "$ZSYNC_DIR"
put $fil
bye
EOF
done
for fil in *AppImage-MD5.txt; do
ftp -v -inv $HOST <<EOF
passive
user $USER $PASSWORD
cd "$BIN_DIR"
put $fil
bye
EOF
done
break
;;
"Upload AppImage later")
cp -f *.AppImage ${EXECUTABLE}-zsyncmake/
cd ${EXECUTABLE}-zsyncmake
for i in *.AppImage; do
./zsyncmake "$i" -u "${ZSYNC_ADDRESS}/$i"
done
break
;;
"Quit")
echo "Goodbye"
exit 0
;;
*)
echo "invalid option $REPLY"
;;
esac
done
} #doZsynkMake
possibleappdirs=$($(echo ls -d AppDir*))
for i in ${possibleappdirs[*]}; do
options+=(${i})
done
PS3=$(echo -e "${BLUE}Pleas Select AppDir to create AppImage from\nor create *.zsync file and MD5 sum: ${NC}")
select opt in "${options[@]}" "Create *.zsync fil and MD5 sum" "Quit"; do
case "$REPLY" in
$((${#options[@]} + 1)))
echo "Create *.zsync file and MD5 sum"
doZsynkMake
break
;;
$((${#options[@]} + 2)))
echo "Goodbye!"
exit 0
break
;;
esac
[ $REPLY -gt $((${#options[@]} + 1)) -o $REPLY -lt 1 ] && echo "Invalid selection" || break
done
echo "You chose $opt which is $(pwd)/${options[(($REPLY - 1))]}"
appdirname="${options[(($REPLY - 1))]}"
if [ -d "$(pwd)/$appdirname" ]; then
echo "You have chosen to create an AppImage from the folder $(pwd)/$appdirname"
else
echo "Error: Directory $(pwd)/$appdirname does not exists."
fi
echo "----------------------------------------------------------------"
PS3=$(echo -e "${BLUE}Please enter Qt version: ${NC}")
options=("5.15.2" "${QT5}" "${QT6}" "Create *.zsync file and MD5 sum" "Quit")
select opt in "${options[@]}"; do
case $opt in
"5.15.2 64-bit")
export LD_LIBRARY_PATH="/opt/Qt/5.15.2/${GCC}/lib:${LD_LIBRARY_PATH}"
export PATH="/opt/Qt/5.15.2/${GCC}/bin:${PATH}"
echo "You chose $REPLY which is $opt"
qmakeexecutable="/opt/Qt/5.15.2/${GCC}/bin/qmake"
break
;;
"${QT5}")
export LD_LIBRARY_PATH="/opt/Qt/${QT5}/${GCC}/lib:${LD_LIBRARY_PATH}"
export PATH="/opt/Qt/${QT5}/${GCC}/bin:${PATH}"
echo "You chose $REPLY which is $opt"
qmakeexecutable="/opt/Qt/${QT5}/${GCC}/bin/qmake"
break
;;
"${QT6}")
export LD_LIBRARY_PATH="/opt/Qt/${QT6}/${GCC}/lib:${LD_LIBRARY_PATH}"
export PATH="/opt/Qt/${QT6}/${GCC}/bin:${PATH}"
echo "You chose $REPLY which is $opt"
qmakeexecutable="/opt/Qt/${QT6}/${GCC}/bin/qmake"
break
;;
"Create *.zsync file and MD5 sum")
echo "You chose $REPLY which is $opt"
doZsynkMake
break
;;
"Quit")
echo "Goodbye"
echo "You chose $REPLY which is $opt"
exit 0
;;
*) echo "invalid option $REPLY" ;;
esac
done
echo -----------------------------------------------------------
PS3=$(echo -e "${BLUE}Please enter your choice: ${NC}")
options=("Sign AppImage" "Do not sign AppImage" "Quit")
select opt in "${options[@]}"; do
case $opt in
"Sign AppImage")
echo "You chose $REPLY which is $opt"
signera=1
break
;;
"Do not sign AppImage")
echo "You chose $REPLY which is $opt"
signera=0
break
;;
"Quit")
echo "Goodbye"
exit 0
;;
*) echo "invalid option $REPLY" ;;
esac
done
echo "----------------------------------------------------------------"
PS3=$(echo -e "${BLUE}Please enter your choice: ${NC}")
options=("Make an AppImage" "Quit")
select opt in "${options[@]}"; do
case $opt in
"Make an AppImage")
echo "You chose $REPLY which is $opt"
if [[ (${GLIBCVERSION} > ${SUPORTEDGLIBC}) ]]; then
echo -e ${BLUE}${BOLD}UNSUPORTED!${NORMAL}${NC}
~/bin/linuxdeployqt ${appdirname}/usr/bin/${EXECUTABLE} -qmake=$qmakeexecutable -bundle-non-qt-libs -verbose=2 -no-translations -no-copy-copyright-files -unsupported-allow-new-glibc
else
echo -e ${BLUE}${BOLD}SUPORTED!${NORMAL}${NC}
~/bin/linuxdeployqt ${appdirname}/usr/bin/${EXECUTABLE} -qmake=$qmakeexecutable -bundle-non-qt-libs -verbose=2 -no-translations -no-copy-copyright-files
fi
MACHINE_TYPE=$(uname -m)
if [ ${MACHINE_TYPE} == 'x86_64' ]; then
if [ "$signera" -gt 0 ]; then
ARCH=x86_64 ~/bin/appimagetool --sign ${appdirname}
else
ARCH=x86_64 ~/bin/appimagetool ${appdirname}
fi
else
if [ "$signera" -gt 0 ]; then
ARCH=i386 ~/bin/appimagetool --sign ${appdirname}
else
ARCH=i386 ~/bin/appimagetool ${appdirname}
fi
fi
break
;;
"Quit")
echo "Goodbye"
exit 0
;;
*) echo "invalid option $REPLY" ;;
esac
done