build: add AppImage packaging pipeline and build scripts

This commit is contained in:
dev 2026-03-04 11:08:29 +00:00
parent 7b4a9c1fe3
commit 26eaf8cf68
6 changed files with 220 additions and 0 deletions

View file

@ -0,0 +1,91 @@
version: 1
AppDir:
path: !ENV '${SCANSLICER_APPDIR}'
app_info:
id: scanslicer
name: ScanSlicer
icon: scanslicer
version: "1.0.0"
exec: usr/bin/python3
exec_args: "-m scanslicer $@"
apt:
arch: amd64
allow_unauthenticated: false
sources:
- sourceline: "deb https://archive.ubuntu.com/ubuntu/ noble main restricted universe multiverse"
key_url: "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C"
include:
- python3
- python3-pip
- libdbus-1-3
- libfontconfig1
- libegl1
- libgl1
- libglib2.0-0
- libglib2.0-bin
- libsm6
- libwayland-client0
- libwayland-cursor0
- libwayland-egl1
- libxkbcommon0
- libx11-xcb1
- libxcb-cursor0
- libgdk-pixbuf2.0-bin
- libgtk-3-bin
files:
include:
- /usr/bin/python3
- /usr/bin/pip3
- /usr/lib
- /usr/share
exclude:
- usr/share/man
- usr/share/doc/*/README.*
- usr/share/doc/*/changelog.*
- usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.*
- usr/lib/x86_64-linux-gnu/libQt6*.so*
- usr/lib/x86_64-linux-gnu/qt6/**
runtime:
env:
APPDIR: "${APPDIR}"
PYTHONHOME: "${APPDIR}/usr"
PYTHONNOUSERSITE: "1"
QT_PLUGIN_PATH: "${APPDIR}/usr/local/lib/python3.12/dist-packages/PySide6/Qt/plugins"
LD_LIBRARY_PATH: "${APPDIR}/usr/local/lib/python3.12/dist-packages/PySide6/Qt/lib:${APPDIR}/usr/local/lib/python3.12/dist-packages/opencv_python.libs:${APPDIR}/usr/lib:${APPDIR}/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH}"
PATH: "${APPDIR}/usr/bin:${PATH}"
after_bundle: |
APPDIR_PATH="${APPDIR:-${SCANSLICER_APPDIR:-}}"
if [ -z "${APPDIR_PATH}" ]; then
echo "AppDir path is not set (SCANSLICER_APPDIR/APPDIR)." >&2
exit 1
fi
mkdir -p "${APPDIR_PATH}/usr/share/applications"
mkdir -p "${APPDIR_PATH}/usr/share/icons"
mkdir -p "${APPDIR_PATH}/usr/share/pixmaps"
mkdir -p "${APPDIR_PATH}/icons"
mkdir -p "${APPDIR_PATH}/pixmaps"
cp "${SCANSLICER_ROOT}/packaging/appimage/scanslicer.desktop" "${APPDIR_PATH}/usr/share/applications/scanslicer.desktop"
cp "${SCANSLICER_ROOT}/packaging/appimage/scanslicer.svg" "${APPDIR_PATH}/usr/share/icons/scanslicer.svg"
cp "${SCANSLICER_ROOT}/packaging/appimage/scanslicer.svg" "${APPDIR_PATH}/usr/share/pixmaps/scanslicer.svg"
rsvg-convert -w 256 -h 256 "${SCANSLICER_ROOT}/packaging/appimage/scanslicer.svg" > "${APPDIR_PATH}/usr/share/icons/scanslicer.png"
cp "${APPDIR_PATH}/usr/share/icons/scanslicer.png" "${APPDIR_PATH}/usr/share/pixmaps/scanslicer.png"
cp "${APPDIR_PATH}/usr/share/icons/scanslicer.png" "${APPDIR_PATH}/icons/scanslicer.png"
cp "${APPDIR_PATH}/usr/share/icons/scanslicer.png" "${APPDIR_PATH}/pixmaps/scanslicer.png"
cp "${APPDIR_PATH}/usr/share/icons/scanslicer.png" "${APPDIR_PATH}/.DirIcon"
test -f "${APPDIR_PATH}/usr/share/icons/scanslicer.png"
test -f "${APPDIR_PATH}/usr/share/pixmaps/scanslicer.png"
test -f "${APPDIR_PATH}/icons/scanslicer.png"
test -f "${APPDIR_PATH}/pixmaps/scanslicer.png"
test -f "${APPDIR_PATH}/.DirIcon"
rm -rf "${APPDIR_PATH}/usr/lib/x86_64-linux-gnu/qt6"
rm -f "${APPDIR_PATH}"/usr/lib/x86_64-linux-gnu/libQt6*.so*
python3 -m pip install --no-cache-dir --upgrade --ignore-installed --prefix=/usr --root="${APPDIR_PATH}" -r "${SCANSLICER_REQUIREMENTS}"
AppImage:
arch: x86_64

View file

@ -0,0 +1,34 @@
FROM ubuntu:24.04
COPY --from=ghcr.io/astral-sh/uv:0.10.2 /uv /uvx /usr/local/bin/
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
RUN apt-get update && apt-get install -y --no-install-recommends \
binutils \
ca-certificates \
desktop-file-utils \
fakeroot \
file \
libgdk-pixbuf2.0-bin \
libglib2.0-bin \
libgtk-3-bin \
libfuse2 \
librsvg2-bin \
patchelf \
python3 \
python3-pip \
python3-setuptools \
squashfs-tools \
strace \
xz-utils \
zsync \
&& rm -rf /var/lib/apt/lists/*
RUN python3 -m pip install --no-cache-dir --break-system-packages \
"packaging<21" \
appimage-builder
WORKDIR /work

View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
IMAGE_NAME="${APPIMAGE_DOCKER_IMAGE:-scanslicer-appimage-builder}"
HOST_UID="${HOST_UID:-$(id -u)}"
HOST_GID="${HOST_GID:-$(id -g)}"
if ! command -v docker >/dev/null 2>&1; then
echo "Missing required command: docker" >&2
exit 1
fi
docker build \
-f "${ROOT_DIR}/packaging/appimage/Dockerfile" \
-t "${IMAGE_NAME}" \
"${ROOT_DIR}"
docker run --rm \
-e HOST_UID="${HOST_UID}" \
-e HOST_GID="${HOST_GID}" \
-v "${ROOT_DIR}:/work" \
-w /work \
--entrypoint bash \
"${IMAGE_NAME}" \
-lc 'set -euo pipefail; bash packaging/appimage/build-appimage.sh; if [ -d /work/appimage ]; then chown -R "${HOST_UID}:${HOST_GID}" /work/appimage; fi'
echo "Docker AppImage build complete. Output in ${ROOT_DIR}/appimage/dist"

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
APPIMAGE_ROOT="${ROOT_DIR}/appimage"
BUILD_DIR="${APPIMAGE_ROOT}/build"
APPDIR="${BUILD_DIR}/AppDir"
DIST_DIR="${APPIMAGE_ROOT}/dist"
APPIMAGE_BUILDER_BIN="${APPIMAGE_BUILDER_BIN:-appimage-builder}"
for cmd in uv "${APPIMAGE_BUILDER_BIN}"; do
if ! command -v "${cmd}" >/dev/null 2>&1; then
echo "Missing required command: ${cmd}" >&2
echo "See docs/appimage.md for setup instructions." >&2
exit 1
fi
done
mkdir -p "${BUILD_DIR}" "${DIST_DIR}"
rm -rf "${APPDIR}"
mkdir -p "${APPDIR}"
cd "${ROOT_DIR}"
uv export \
--frozen \
--no-dev \
--no-emit-project \
--no-hashes \
--format requirements-txt \
--output-file "${BUILD_DIR}/requirements.txt"
uv build --wheel --out-dir "${BUILD_DIR}"
WHEEL_PATH="$(ls -1 "${BUILD_DIR}"/scanslicer-*.whl | head -n 1)"
if [[ -z "${WHEEL_PATH}" ]]; then
echo "Could not find built wheel in ${BUILD_DIR}" >&2
exit 1
fi
printf "%s\n" "${WHEEL_PATH}" >> "${BUILD_DIR}/requirements.txt"
export SCANSLICER_ROOT="${ROOT_DIR}"
export SCANSLICER_APPDIR="${APPDIR}"
export SCANSLICER_REQUIREMENTS="${BUILD_DIR}/requirements.txt"
cd "${BUILD_DIR}"
"${APPIMAGE_BUILDER_BIN}" --recipe "${ROOT_DIR}/packaging/appimage/AppImageBuilder.yml"
mkdir -p "${DIST_DIR}"
find "${BUILD_DIR}" -maxdepth 1 -type f \( -name "*.AppImage" -o -name "*.zsync" \) -exec mv -f {} "${DIST_DIR}/" \;
echo "AppImage build complete. Output in ${DIST_DIR}"

View file

@ -0,0 +1,9 @@
[Desktop Entry]
Type=Application
Name=ScanSlicer
Comment=Detect, straighten and save photos from flatbed scans
Exec=scanslicer %F
Icon=scanslicer
Terminal=false
Categories=Graphics;Photography;
StartupWMClass=ScanSlicer

View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
<rect x="16" y="16" width="224" height="224" rx="24" fill="#2d3748"/>
<rect x="40" y="40" width="176" height="176" rx="16" fill="#4a5568"/>
<rect x="68" y="68" width="120" height="80" rx="8" fill="#e2e8f0"/>
<rect x="68" y="160" width="52" height="20" rx="4" fill="#90cdf4"/>
<rect x="136" y="160" width="52" height="20" rx="4" fill="#f6ad55"/>
</svg>

After

Width:  |  Height:  |  Size: 450 B