mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-05 10:10:35 +00:00
package.sh built its own Arch package with nfpm while the shared release workflow also built one with makepkg, because has-arch defaults to true. Both wrote designcraft-<version>-linux-<arch>.pkg.tar.zst, the draft release merges the release-* artifacts last-writer-wins, and 0.17.0 shipped the nfpm copy, which declared fewer dependencies than the makepkg template. Drop arch from the formats this script builds and remove the archlinux section from nfpm.yaml, so the shared action is the single builder. It names the package after the .desktop bundle id, declares the same provides/conflicts against the AUR packages, and adds the optdepends nfpm could not express.
178 lines
8.2 KiB
Bash
Executable File
178 lines
8.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build and package DesignCraft for Linux (<arch> is x86_64 or aarch64, or riscv64 when cross-compiling):
|
|
#
|
|
# $DIST/designcraft-<version>-linux-<arch>.AppImage any distro with glibc >= the build host's
|
|
# $DIST/designcraft-<version>-linux-<arch>.AppImage.zsync delta updates (needs zsyncmake)
|
|
# $DIST/designcraft-<version>-linux-<arch>.deb Debian, Ubuntu, Mint, Pop!_OS, ...
|
|
# $DIST/designcraft-<version>-linux-<arch>.rpm Fedora, openSUSE, RHEL, ...
|
|
# $DIST/designcraft-<version>-linux-<arch>.tar.gz plain FHS-style tree (bin/, share/)
|
|
#
|
|
# The Arch package (.pkg.tar.zst) is not built here. The release workflow builds it with
|
|
# craft-common-actions/actions/arch-package from this script's tarball, which names it after the
|
|
# .desktop bundle id (ai.storyteller.designcraft, not designcraft, so an AUR helper does not claim
|
|
# it) and declares provides/conflicts against the AUR packages. Building a second one here under
|
|
# the same asset name is what made the published package depend on upload order.
|
|
#
|
|
# Usage: packaging/linux/package.sh [--skip-build] [--formats "appimage deb rpm tar"]
|
|
#
|
|
# Needs: cargo; nfpm for deb/rpm (https://nfpm.goreleaser.com); appimagetool for the AppImage
|
|
# (downloaded into $CARGO_TARGET_DIR if missing). Build on an old distro (CI: Ubuntu 22.04,
|
|
# glibc 2.35) so the binaries run on newer ones. Optional: desktop-file-validate, appstreamcli,
|
|
# zsyncmake (the zsync package) for the AppImage's .zsync.
|
|
set -euo pipefail
|
|
# shellcheck source=../env.sh
|
|
. "$(dirname "${BASH_SOURCE[0]}")/../env.sh"
|
|
HERE="$ROOT/packaging/linux"
|
|
APP_ID=ai.storyteller.designcraft
|
|
|
|
SKIP_BUILD=0
|
|
FORMATS="appimage deb rpm tar"
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--skip-build) SKIP_BUILD=1; shift ;;
|
|
--formats) FORMATS="$2"; shift 2 ;;
|
|
-h | --help) sed -n '2,16p' "$0"; exit 0 ;;
|
|
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
ARCH="${CROSS_ARCH:-$(uname -m)}"
|
|
case "$ARCH" in
|
|
riscv64) DEB_ARCH=riscv64 ;;
|
|
x86_64) DEB_ARCH=amd64 ;;
|
|
aarch64 | arm64) ARCH=aarch64; DEB_ARCH=arm64 ;;
|
|
*) echo "unsupported architecture $ARCH" >&2; exit 2 ;;
|
|
esac
|
|
export DESIGNCRAFT_MAINTAINER="${DESIGNCRAFT_MAINTAINER:-DesignCraft maintainers <designcraft@storyteller.ai>}"
|
|
BASENAME="designcraft-$VERSION-linux-$ARCH"
|
|
|
|
echo "==> DesignCraft $VERSION for Linux $ARCH ($FORMATS)"
|
|
|
|
has() {
|
|
local fmt="$1"
|
|
case " $FORMATS " in *" $fmt "*) return 0 ;; *) return 1 ;; esac
|
|
}
|
|
|
|
if has arch; then
|
|
echo "error: the Arch package is built by the release workflow's makepkg job, not by this script" >&2
|
|
exit 2
|
|
fi
|
|
|
|
if [[ "$SKIP_BUILD" = 0 ]]; then
|
|
if [[ -n "${CROSS_TARGET:-}" ]]; then
|
|
(cd "$ROOT" && cargo build --release --locked -p designcraft -p designcraft-cli --target "$CROSS_TARGET")
|
|
else
|
|
(cd "$ROOT" && cargo build --release --locked -p designcraft -p designcraft-cli)
|
|
fi
|
|
fi
|
|
BIN="$CARGO_TARGET_DIR/${CROSS_TARGET:+$CROSS_TARGET/}release"
|
|
WORK="$CARGO_TARGET_DIR/linux-package"
|
|
STAGE="$WORK/root"
|
|
rm -rf "$WORK"
|
|
|
|
# ---- stage an FHS tree (shared by every format) -------------------------------------------------
|
|
install -Dm755 "$BIN/designcraft" "$STAGE/usr/bin/designcraft"
|
|
install -Dm755 "$BIN/designcraft-cli" "$STAGE/usr/bin/designcraft-cli"
|
|
"${CROSS_COMPILE:-}strip" "$STAGE/usr/bin/designcraft" "$STAGE/usr/bin/designcraft-cli" 2>/dev/null || true
|
|
install -Dm644 "$HERE/$APP_ID.desktop" "$STAGE/usr/share/applications/$APP_ID.desktop"
|
|
install -Dm644 "$HERE/$APP_ID.mime.xml" "$STAGE/usr/share/mime/packages/$APP_ID.xml"
|
|
install -Dm644 "$HERE/$APP_ID.thumbnailer" "$STAGE/usr/share/thumbnailers/$APP_ID.thumbnailer"
|
|
mkdir -p "$STAGE/usr/share/metainfo"
|
|
sed -e "s/@VERSION@/$VERSION/g" -e "s/@DATE@/$DESIGNCRAFT_BUILD_DATE/g" \
|
|
"$HERE/$APP_ID.metainfo.xml.in" >"$STAGE/usr/share/metainfo/$APP_ID.metainfo.xml"
|
|
mkdir -p "$STAGE/usr/share/icons"
|
|
cp -R "$ROOT/assets/app-icon/hicolor" "$STAGE/usr/share/icons/"
|
|
mkdir -p "$STAGE/usr/share/doc/designcraft"
|
|
copy_docs "$STAGE/usr/share/doc/designcraft"
|
|
|
|
if command -v desktop-file-validate >/dev/null; then
|
|
desktop-file-validate "$STAGE/usr/share/applications/$APP_ID.desktop"
|
|
fi
|
|
if command -v appstreamcli >/dev/null; then
|
|
appstreamcli validate --no-net --explain "$STAGE/usr/share/metainfo/$APP_ID.metainfo.xml"
|
|
fi
|
|
|
|
# ---- .tar.gz ------------------------------------------------------------------------------------
|
|
if has tar; then
|
|
mkdir -p "$WORK/tar"
|
|
cp -R "$STAGE/usr" "$WORK/tar/$BASENAME"
|
|
tar -C "$WORK/tar" -czf "$DIST/$BASENAME.tar.gz" "$BASENAME"
|
|
echo "wrote $DIST/$BASENAME.tar.gz"
|
|
fi
|
|
|
|
# ---- .deb / .rpm --------------------------------------------------------------------------------
|
|
if has deb || has rpm; then
|
|
command -v nfpm >/dev/null || { echo "error: nfpm not found (https://nfpm.goreleaser.com/install/)" >&2; exit 1; }
|
|
export VERSION
|
|
export NFPM_ARCH="$DEB_ARCH"
|
|
# nfpm expands env vars in fields like `version` and `arch`, but not in `contents[].src`.
|
|
sed "s|\${STAGE}|$STAGE|g" "$HERE/nfpm.yaml" >"$WORK/nfpm.yaml"
|
|
for fmt in deb rpm; do
|
|
if has "$fmt"; then (cd "$ROOT" && nfpm package -f "$WORK/nfpm.yaml" -p "$fmt" -t "$DIST/$BASENAME.$fmt"); fi
|
|
done
|
|
fi
|
|
|
|
# ---- AppImage -----------------------------------------------------------------------------------
|
|
if has appimage; then
|
|
APPIMAGETOOL_VERSION=1.9.1
|
|
case "$ARCH" in
|
|
x86_64) APPIMAGETOOL_SHA256=ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0 ;;
|
|
aarch64) APPIMAGETOOL_SHA256=f0837e7448a0c1e4e650a93bb3e85802546e60654ef287576f46c71c126a9158 ;;
|
|
# No pinned download (e.g. riscv64): set APPIMAGETOOL or put appimagetool on PATH.
|
|
*) APPIMAGETOOL_SHA256="" ;;
|
|
esac
|
|
APPDIR="$WORK/DesignCraft.AppDir"
|
|
cp -R "$STAGE" "$APPDIR"
|
|
# Keep sctk-adwaita's MIT notice in the AppImage.
|
|
install -Dm644 "$ROOT/NOTICE" "$APPDIR/usr/share/doc/designcraft/NOTICE"
|
|
ln -s usr/bin/designcraft "$APPDIR/AppRun"
|
|
cp "$HERE/$APP_ID.desktop" "$APPDIR/$APP_ID.desktop"
|
|
cp "$ROOT/assets/app-icon/hicolor/256x256/apps/$APP_ID.png" "$APPDIR/$APP_ID.png"
|
|
ln -s "$APP_ID.png" "$APPDIR/.DirIcon"
|
|
|
|
TOOL="${APPIMAGETOOL:-$(command -v appimagetool || true)}"
|
|
if [[ -z "$TOOL" ]]; then
|
|
TOOL="$CARGO_TARGET_DIR/appimagetool-$APPIMAGETOOL_VERSION-$ARCH.AppImage"
|
|
if [[ ! -x "$TOOL" ]]; then
|
|
download="$TOOL.download"
|
|
curl --proto '=https' -fsSL -o "$download" \
|
|
"https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-$ARCH.AppImage"
|
|
printf '%s %s\n' "$APPIMAGETOOL_SHA256" "$download" | sha256sum -c -
|
|
chmod 755 "$download"
|
|
mv "$download" "$TOOL"
|
|
fi
|
|
printf '%s %s\n' "$APPIMAGETOOL_SHA256" "$TOOL" | sha256sum -c -
|
|
fi
|
|
# Absolute, because appimagetool runs in $DIST below (CARGO_TARGET_DIR or APPIMAGETOOL may be
|
|
# relative, e.g. target/agent-<name>).
|
|
OUT="$(cd "$DIST" && pwd)/$BASENAME.AppImage"
|
|
APPDIR="$(cd "$APPDIR" && pwd)"
|
|
TOOL="$(cd "$(dirname "$TOOL")" && pwd)/$(basename "$TOOL")"
|
|
# A .zsync left by an earlier run would hide a missing zsyncmake and describe another file.
|
|
rm -f "$OUT.zsync"
|
|
# Update information: AppImageUpdate, AppImageLauncher and the like read it from the file and
|
|
# fetch only the blocks that changed in a newer release, through the .zsync published next to
|
|
# each AppImage on GitHub Releases. `latest` is the newest published release that is not a
|
|
# pre-release. A fork's builds point at its own releases through GITHUB_REPOSITORY.
|
|
REPO="${GITHUB_REPOSITORY:-storytold/designcraft}"
|
|
UPDATE_INFO="gh-releases-zsync|${REPO%%/*}|${REPO#*/}|latest|designcraft-*-linux-$ARCH.AppImage.zsync"
|
|
# Extract-and-run: works without FUSE (containers, CI). The output embeds the static runtime,
|
|
# so users don't need libfuse2 either. With zsyncmake on the host (CI installs the zsync
|
|
# package) appimagetool also writes the .zsync, into its working directory, hence the cd.
|
|
(cd "$DIST" && ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream -u "$UPDATE_INFO" "$APPDIR" "$OUT")
|
|
echo "wrote $OUT"
|
|
if [[ -s "$OUT.zsync" ]]; then
|
|
echo "wrote $OUT.zsync"
|
|
else
|
|
warn "zsyncmake not found, so $OUT.zsync was not written; AppImage delta updates need it"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "${CROSS_TARGET:-}" ]]; then
|
|
"$STAGE/usr/bin/designcraft-cli" --version
|
|
elif [[ -n "${EMULATOR:-}" ]]; then
|
|
"$EMULATOR" "$STAGE/usr/bin/designcraft-cli" --version
|
|
fi
|
|
echo "==> done"
|
|
ls -lh "$DIST"
|