From 61d9a40f176e3ced9a1627c911e91f99826750dd Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 24 Sep 2023 16:57:58 +0200 Subject: [PATCH] feat(appimage): switch to appimage-builder This commits introduces appimage-builder in favor of the hand-crafted shell script. It allows a stable build environment, up-to-date library versions and multi-platform builds. --- .github/workflows/appimage.yml | 31 ++++++- AppImageBuilder.yml | 85 +++++++++++++++++ Dockerfile | 45 +++++---- appimage-build.sh | 164 --------------------------------- scripts/appimage-AppRun.sh | 4 +- 5 files changed, 141 insertions(+), 188 deletions(-) create mode 100644 AppImageBuilder.yml delete mode 100755 appimage-build.sh diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 0fa02e5e..e815464e 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -1,5 +1,9 @@ name: Build and publish AppImages +env: + UBUNTU_RELEASE: jammy + UBUNTU_PUBKEY: 871920D1991BC93C + on: pull_request: push: @@ -16,6 +20,7 @@ jobs: matrix: platform: - linux/amd64 + - linux/arm64 steps: - uses: actions/checkout@v4 @@ -34,16 +39,34 @@ jobs: platforms: ${{ matrix.platform }} outputs: build build-args: | - APPIMAGE_VERSION=${{ env.GITHUB_REF_SLUG }} - REPO_OWNER=${{ env.GITHUB_REPOSITORY_OWNER }} + UBUNTU_RELEASE + + - name: Prepare environment for building AppImage + env: + TARGET_PLATFORM: ${{ matrix.platform }} + shell: bash + run: | + set -eua + . build/.build-metadata.env + rm build/.build-metadata.env + APPIMAGE_SOURCE=build + APPIMAGE_VERSION="${GITHUB_REF_SLUG}" + APPIMAGE_APT_ARCH="${TARGETARCH}" + APPIMAGE_APT_DISTRO="${UBUNTU_RELEASE}" + APPIMAGE_APT_PUBKEY="${UBUNTU_PUBKEY}" + APPIMAGE_ARCH="${TARGETMACHINE}" + printenv | grep ^APPIMAGE_ >>"${GITHUB_ENV}" + + - name: Build AppImage + uses: AppImageCrafters/build-appimage@v1.3 - name: Upload artifacts uses: actions/upload-artifact@v3 with: name: appimages path: | - ./build/*.AppImage - ./build/*.AppImage.zsync + ./*.AppImage + ./*.AppImage.zsync if-no-files-found: error release: diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml new file mode 100644 index 00000000..270f8b2c --- /dev/null +++ b/AppImageBuilder.yml @@ -0,0 +1,85 @@ +version: 1 + +script: +- | + mv "{{APPIMAGE_SOURCE}}" "${TARGET_APPDIR}" + # Manual installation is required until fix of https://github.com/AppImageCrafters/build-appimage/issues/5 + if ! command -v mksquashfs >/dev/null; then + apt-get update && apt-get install -y --no-install-recommends squashfs-tools + fi + +AppDir: + app_info: + id: org.ryochan7.sc-controller + name: sc-controller + version: "{{APPIMAGE_VERSION}}" + icon: sc-controller + exec: bin/bash + exec_args: entrypoint $@ + + after_runtime: | + source="${TARGET_APPDIR}/usr/share/applications/sc-controller.desktop" + target="${TARGET_APPDIR}/org.ryochan7.sc-controller.desktop" + sed -i -E '/^(Comment|Categories)=.*$/d' "${target}" + grep -v -P '^(\[Desktop Entry\])|(Name|Exec|Type|Icon)=.*$' "${source}" >>"${target}" + + apt: + arch: + - "{{APPIMAGE_APT_ARCH}}" + sources: + - sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ "{{APPIMAGE_APT_DISTRO}}" main universe + key_url: "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x{{APPIMAGE_APT_PUBKEY}}" + - sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ "{{APPIMAGE_APT_DISTRO}}"-updates main universe + - sourceline: deb [arch=amd64] http://security.ubuntu.com/ubuntu/ "{{APPIMAGE_APT_DISTRO}}"-security main universe + - sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ "{{APPIMAGE_APT_DISTRO}}" main universe + - sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ "{{APPIMAGE_APT_DISTRO}}"-updates main universe + - sourceline: deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ "{{APPIMAGE_APT_DISTRO}}"-security main universe + include: + - bash + - gir1.2-rsvg-2.0 + - libc-bin + - libbluetooth3 + - librsvg2-common + - python3-gi-cairo + - python3-evdev + - python3-pylibacl + - python3-vdf + exclude: + - 'gcc*' + - 'libblkid*' + - 'libc6*' + - 'libdb*' + - 'libgcc*' + - 'libicu*' + - 'libmount*' + - 'libncurses*' + - 'libreadline*' + - 'libssl*' + - 'libstdc*' + - 'libtirpc*' + - 'readline*' + - '*crypt*' + - '*krb*' + - '*sqlite*' + + files: + exclude: + - usr/share/man + - usr/share/doc + - usr/share/gtk-doc + - usr/share/local + - usr/share/thumbnailers + - usr/share/icu + - usr/lib/*/glib-2.0 + - usr/lib/*/gdk-pixbuf-2.0/*/loaders/libpixbufloader-[!s]*.so + + runtime: + path_mappings: + - '/sbin/ldconfig.real:${APPDIR}/sbin/ldconfig.real' + env: + PYTHONPATH: '${APPDIR}/usr/lib/python3/dist-packages:${PYTHONPATH}' + GI_TYPELIB_PATH: '${APPDIR}/usr/lib/{{APPIMAGE_ARCH}}-linux-gnu/girepository-1.0' + +AppImage: + arch: "{{APPIMAGE_ARCH}}" + update-information: "gh-releases-zsync|Ryochan7|sc-controller|latest|sc-controller-*.glibc-{{APPIMAGE_ARCH}}.AppImage.zsync" diff --git a/Dockerfile b/Dockerfile index 0c2f0f01..45ca9b89 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,28 +8,37 @@ RUN apt-get update && \ libacl1-dev imagemagick librsvg2-2 \ zsync -RUN curl -sSL -o /tmp/appimagetool.AppImage "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$(uname -m).AppImage" && \ - chmod +x /tmp/appimagetool.AppImage && \ - cd /opt && /tmp/appimagetool.AppImage --appimage-extract && \ - mv squashfs-root appimage-tool.AppDir && \ - ln -s /opt/appimage-tool.AppDir/AppRun /usr/bin/appimagetool && \ - rm /tmp/appimagetool.AppImage - COPY . /work WORKDIR /work -RUN if [ ! -d /usr/include/linux ]; then \ - ln -s "$(find /usr -xdev -type f -name 'input-event-codes.h' -exec dirname '{}' \; -quit)" /usr/include/linux; \ - fi -RUN ./appimage-build.sh +ARG TARGET=/work/appimage + +# Build and install +RUN python3 setup.py build --executable "/usr/bin/env python3" && \ + python3 setup.py install --single-version-externally-managed --prefix "${TARGET}/usr" --record /dev/null + +# Provide input-event-codes.h as fallback for runtime systems without linux headers +RUN cp -a \ + "$(find /usr -type f -name input-event-codes.h -print -quit)" \ + "$(find "${TARGET}" -type f -name uinput.py -printf '%h\n' -quit)" + +# Create symlinks with short names for static libraries +RUN suffix=".cpython-*-$(uname -m)-linux-gnu.so" && \ + find "${TARGET}/usr" -type f -path "*/site-packages/*${suffix}" \ + | while read -r path; do ln -sfr "${path}" "${path%${suffix}}.so"; done + +# Put AppStream metadata into required location +RUN mkdir -p ${TARGET}/usr/share/metainfo && \ + cp scripts/sc-controller.appdata.xml "${TARGET}/usr/share/metainfo/" + +# Convert icon to PNG (required for icons in .desktop file) +RUN convert -background none "${TARGET}/usr/share/pixmaps/sc-controller.svg" "${TARGET}/sc-controller.png" + +# Copy start script +RUN cp -a scripts/appimage-AppRun.sh "${TARGET}/entrypoint" +# Store build metadata ARG TARGETOS TARGETARCH TARGETVARIANT RUN export "TARGETMACHINE=$(uname -m)" && printenv | grep ^TARGET >>.build-metadata.env -ARG APPIMAGE_VERSION=latest -ARG REPO_OWNER=Ryochan7 -ARG APPIMAGE_UPDATE_INFO -RUN set -a && . ./.build-metadata.env && \ - update_info="${APPIMAGE_UPDATE_INFO:-gh-releases-zsync|${REPO_OWNER}|sc-controller|latest|sc-controller-*.glibc-${TARGETMACHINE}.AppImage.zsync}" && \ - appimagetool -n -u "${update_info}" appimage "sc-controller-${APPIMAGE_VERSION}.glibc-${TARGETMACHINE}.AppImage" FROM scratch AS export-stage -COPY --from=build-stage /work/*.AppImage* /work/appimage /work/.build-metadata.env / +COPY --from=build-stage /work/appimage /work/.build-metadata.env / diff --git a/appimage-build.sh b/appimage-build.sh deleted file mode 100755 index d5cfb6d7..00000000 --- a/appimage-build.sh +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash -APP="sc-controller" -EXEC="scc" -LIB="lib" - -EVDEV_VERSION=1.6.1 -[ x"$BUILD_APPDIR" == "x" ] && BUILD_APPDIR=$(pwd)/appimage -PYTHON_VERSION=$(python3 -c 'import sys; version=sys.version_info[:3]; print("{0}.{1}".format(*version))') -SITE_PACKAGES_PATH="/usr/${LIB}/python${PYTHON_VERSION}/site-packages" -SITE_PACKAGES64_PATH="$(echo "${SITE_PACKAGES_PATH}" | sed 's:/lib/:/lib64/:g')" - -if [ -z ${SITE_PACKAGES_PATH} ]; then - echo "Could not determine global site-packages path. Exiting"; - exit 1; -fi - -function download_dep() { - NAME=$1 - URL=$2 - if [ -e ../../${NAME}.obstargz ] ; then - # Special case for OBS - cp ../../${NAME}.obstargz /tmp/${NAME}.tar.gz - elif [ -e ${NAME}.tar.gz ] ; then - cp ${NAME}.tar.gz /tmp/${NAME}.tar.gz - elif [ -e /tmp/${NAME}.tar.gz ] ; then - echo "/tmp/${NAME}.tar.gz already downloaded" - else - curl -sSL -C - -o "/tmp/${NAME}.tar.gz" "${URL}" - fi -} - -function build_dep() { - NAME="$1" - mkdir -p /tmp/${NAME} - pushd /tmp/${NAME} - tar --extract --strip-components=1 -f /tmp/${NAME}.tar.gz - PYTHONPATH=${BUILD_APPDIR}/${SITE_PACKAGES_PATH} python3 \ - setup.py install --optimize=1 \ - --prefix="/usr/" --root="${BUILD_APPDIR}" - mkdir -p "${BUILD_APPDIR}/${SITE_PACKAGES_PATH}" - python3 setup.py install --prefix="/usr/" --root="${BUILD_APPDIR}" - popd -} - -function unpack_dep() { - NAME="$1" - pushd ${BUILD_APPDIR} - tar --extract --exclude="usr/include**" --exclude="usr/lib/pkgconfig**" \ - --exclude="usr/lib/python2.7**" -f /tmp/${NAME}.tar.gz - popd -} - -set -ex # display commands, terminate after 1st failure - -# Download deps -download_dep "python-evdev-${EVDEV_VERSION}" "https://github.com/gvalkov/python-evdev/archive/refs/tags/v${EVDEV_VERSION}.tar.gz" -download_dep "pylibacl-0.6.0" "https://github.com/iustin/pylibacl/releases/download/v0.6.0/pylibacl-0.6.0.tar.gz" -download_dep "python-gobject-3.36.1" "https://archive.archlinux.org/packages/p/python-gobject/python-gobject-3.36.1-1-x86_64.pkg.tar.zst" -download_dep "python-vdf-3.4" "https://github.com/ValvePython/vdf/archive/v3.4.tar.gz" -download_dep "libpng-1.6.34" "https://archive.archlinux.org/packages/l/libpng/libpng-1.6.34-2-x86_64.pkg.tar.xz" -download_dep "gdk-pixbuf-2.36.9" "https://archive.archlinux.org/packages/g/gdk-pixbuf2/gdk-pixbuf2-2.36.9-1-x86_64.pkg.tar.xz" -download_dep "libcroco-0.6.13" "https://archive.archlinux.org/packages/l/libcroco/libcroco-0.6.13-1-x86_64.pkg.tar.xz" -download_dep "libxml2-2.9.10" "https://archive.archlinux.org/packages/l/libxml2/libxml2-2.9.10-2-x86_64.pkg.tar.zst" -download_dep "librsvg-2.48.7" "https://archive.archlinux.org/packages/l/librsvg/librsvg-2%3A2.48.7-1-x86_64.pkg.tar.zst" -download_dep "icu-67.1" "https://archive.archlinux.org/packages/i/icu/icu-67.1-1-x86_64.pkg.tar.zst" -download_dep "zlib-1:1.2.12" "https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.12-2-x86_64.pkg.tar.zst" -download_dep "libffi-3.4.3" "https://archive.archlinux.org/packages/l/libffi/libffi-3.4.3-1-x86_64.pkg.tar.zst" -download_dep "cairo-1.17.6" "https://archive.archlinux.org/packages/c/cairo/cairo-1.17.6-2-x86_64.pkg.tar.zst" -download_dep "bluez-libs-5.68" "https://archive.archlinux.org/packages/b/bluez-libs/bluez-libs-5.68-1-x86_64.pkg.tar.zst" -download_dep "binutils-2.40" "https://archive.archlinux.org/packages/b/binutils-2.40-2-x86_64.pkg.tar.zst" -download_dep "libelf-0.188" "https://archive.archlinux.org/packages/l/libelf/libelf-0.188-3-x86_64.pkg.tar.zst" -download_dep "jansson-2.14" "https://archive.archlinux.org/packages/j/jansson/jansson-2.14-2-x86_64.pkg.tar.zst" - -# Prepare & build deps -export PYTHONPATH=${BUILD_APPDIR}/${SITE_PACKAGES_PATH} -mkdir -p "$PYTHONPATH" -if [[ $(grep ID_LIKE /etc/os-release) == *"suse"* ]] ; then - # Special handling for OBS - ln -s lib64 ${BUILD_APPDIR}/usr/lib - export PYTHONPATH="${PYTHONPATH}:${BUILD_APPDIR}/${SITE_PACKAGES64_PATH}" - LIB=lib64 - SITE_PACKAGES_PATH="usr/${LIB}/python${PYTHON_VERSION}/site-packages" -fi - -build_dep "python-evdev-${EVDEV_VERSION}" -build_dep "pylibacl-0.6.0" -build_dep "python-vdf-3.4" -unpack_dep "python-gobject-3.36.1" -unpack_dep "libpng-1.6.34" -unpack_dep "gdk-pixbuf-2.36.9" -unpack_dep "libcroco-0.6.13" -unpack_dep "libxml2-2.9.10" -unpack_dep "librsvg-2.48.7" -unpack_dep "icu-67.1" -unpack_dep "zlib-1:1.2.12" -unpack_dep "libffi-3.4.3" -unpack_dep "cairo-1.17.6" -unpack_dep "bluez-libs-5.68" -unpack_dep "binutils-2.40" -unpack_dep "libelf-0.188" -unpack_dep "jansson-2.14" - -# Remove uneeded files -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-ani.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-bmp.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-gif.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-icns.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-ico.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-jasper.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-jpeg.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-qtif.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-tga.so" -rm -f "${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-tiff.so" -rm -R "${BUILD_APPDIR}/usr/lib/cmake" -rm -R "${BUILD_APPDIR}/usr/share/doc" -rm -R "${BUILD_APPDIR}/usr/share/gtk-doc" -rm -R "${BUILD_APPDIR}/usr/share/locale" -rm -R "${BUILD_APPDIR}/usr/share/man" -rm -R "${BUILD_APPDIR}/usr/share/thumbnailers" -rm -R "${BUILD_APPDIR}/usr/share/vala" -rm -R "${BUILD_APPDIR}/usr/share/icu" - -# Build important part. Need executable flag to place custom interpreter line. -# Setuptools overrrides original #! line in scripts with /usr/bin/python. -# Ubuntu 22.04 LTS does not provide an executable at /usr/bin/python -# by default. -python3 setup.py build --executable "/usr/bin/env python3" - -# Need to use single-version-externally-managed due to setuptools behavior -python3 setup.py install --single-version-externally-managed --prefix ${BUILD_APPDIR}/usr --record /dev/null - -# Move udev stuff -mv ${BUILD_APPDIR}/usr/lib/udev/rules.d/69-${APP}.rules ${BUILD_APPDIR}/ -rmdir ${BUILD_APPDIR}/usr/lib/udev/rules.d/ -rmdir ${BUILD_APPDIR}/usr/lib/udev/ -mkdir -p ${BUILD_APPDIR}/${SITE_PACKAGES_PATH}/scc/ -cp "/usr/include/linux/input-event-codes.h" ${BUILD_APPDIR}/${SITE_PACKAGES_PATH}/scc/ - -# Move & patch desktop file -mv ${BUILD_APPDIR}/usr/share/applications/${APP}.desktop ${BUILD_APPDIR}/ -sed -i "s/Icon=.*/Icon=${APP}/g" ${BUILD_APPDIR}/${APP}.desktop -sed -i "s/Exec=.*/Exec=.\/usr\/bin\/scc gui/g" ${BUILD_APPDIR}/${APP}.desktop - -# Convert icon -convert -background none ${BUILD_APPDIR}/usr/share/pixmaps/${APP}.svg ${BUILD_APPDIR}/${APP}.png - -# Copy appdata.xml -mkdir -p ${BUILD_APPDIR}/usr/share/metainfo/ -cp scripts/${APP}.appdata.xml ${BUILD_APPDIR}/usr/share/metainfo/${APP}.appdata.xml - -# Make symlinks -for lib in libcemuhook libhiddrv libremotepad libsc_by_bt libuinput posix1e; do - find "${BUILD_APPDIR}" -type f -name "${lib}.cpython-*-$(uname -m)-linux-gnu.so" | while read -r path; do - ln -sfr "${path}" "$(dirname "${path}")/${lib}.so" - done -done - -# Copy AppRun script -sed -e "s:/usr/lib/python3.10/site-packages:${SITE_PACKAGES_PATH}:g" \ - -e "s:/usr/lib64/python3.10/site-packages:${SITE_PACKAGES64_PATH}:g" \ - scripts/appimage-AppRun.sh >"${BUILD_APPDIR}/AppRun" -chmod +x ${BUILD_APPDIR}/AppRun - -echo "Run appimagetool -n ${BUILD_APPDIR} to finish prepared appimage" diff --git a/scripts/appimage-AppRun.sh b/scripts/appimage-AppRun.sh index 5aca5e9e..ed101a85 100755 --- a/scripts/appimage-AppRun.sh +++ b/scripts/appimage-AppRun.sh @@ -2,8 +2,8 @@ export PATH=${APPDIR}:${APPDIR}/usr/bin:$PATH export LD_LIBRARY_PATH=${APPDIR}/usr/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=${APPDIR}/usr/lib64:$LD_LIBRARY_PATH -export GI_TYPELIB_PATH=${APPDIR}/usr/lib/girepository-1.0 -export GDK_PIXBUF_MODULEDIR=${APPDIR}/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders +export GI_TYPELIB_PATH="${APPDIR}/usr/lib/girepository-1.0:${GI_TYPELIB_PATH}" +export GDK_PIXBUF_MODULEDIR="${GDK_PIXBUF_MODULEDIR:-${APPDIR}/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders}" export PYTHONPATH=${APPDIR}/usr/lib/python3.10/site-packages:$PYTHONPATH export PYTHONPATH=${APPDIR}/usr/lib64/python3.10/site-packages:$PYTHONPATH export SCC_SHARED=${APPDIR}/usr/share/scc