build: wire desktop-bundle pipeline (CI matrix + per-platform installers)
Stand up the seamless-download path for non-technical buyers:
* .github/workflows/build.yml — matrix CI (mac/win/linux) that builds
PyInstaller bundles and packages them per platform on tag push,
attaching the resulting installers to a GitHub Release.
* build/installer.iss — Inno Setup script for the Windows installer
(per-user install, optional desktop shortcut, runs on finish).
* build/macos/build_dmg.sh — wraps DataTools.app into a .dmg with a
drag-to-/Applications layout.
* build/appimage/{AppRun,datatools.desktop,build.sh} — AppImage recipe.
* src/__init__.py — single source of truth for __version__; the spec
reads it (was hardcoded), CI passes it through to all packagers.
Buyer download path now lives in the top-level README. Per-build
README documents the Phase 2 step (signing/notarization) that needs
the owner's Apple Developer + Windows code-signing credentials —
those are intentionally not in CI yet because they require setup
outside this repo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
build/appimage/build.sh
Executable file
62
build/appimage/build.sh
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wrap dist/DataTools/ (PyInstaller folder mode) into a distributable
|
||||
# AppImage.
|
||||
#
|
||||
# Usage:
|
||||
# bash build/appimage/build.sh <version>
|
||||
#
|
||||
# Requires ``appimagetool`` on PATH (CI installs it; locally grab the
|
||||
# latest release from https://github.com/AppImage/AppImageKit/releases).
|
||||
#
|
||||
# Output: dist/DataTools-<version>-linux-x86_64.AppImage
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${1:-0.0.0-dev}"
|
||||
DIST="dist/DataTools"
|
||||
OUT="dist/DataTools-${VERSION}-linux-x86_64.AppImage"
|
||||
|
||||
if [[ ! -d "$DIST" ]]; then
|
||||
echo "Error: $DIST not found. Run pyinstaller build/datatools.spec first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v appimagetool >/dev/null 2>&1; then
|
||||
echo "Error: appimagetool not on PATH. See build/appimage/build.sh header." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Lay out the AppDir.
|
||||
APPDIR="$(mktemp -d)/DataTools.AppDir"
|
||||
trap 'rm -rf "$(dirname -- "$APPDIR")"' EXIT
|
||||
mkdir -p "$APPDIR/usr/bin"
|
||||
|
||||
cp -R "$DIST" "$APPDIR/usr/bin/"
|
||||
cp build/appimage/AppRun "$APPDIR/AppRun"
|
||||
chmod +x "$APPDIR/AppRun"
|
||||
cp build/appimage/datatools.desktop "$APPDIR/datatools.desktop"
|
||||
|
||||
# Icon. AppImage requires a top-level <appname>.png next to the
|
||||
# .desktop. Use the build/icon.png if present, otherwise generate a
|
||||
# blank placeholder so the build doesn't fail on a fresh checkout.
|
||||
if [[ -f build/icon.png ]]; then
|
||||
cp build/icon.png "$APPDIR/datatools.png"
|
||||
else
|
||||
# 256x256 single-colour PNG via printf — appimagetool needs *some*
|
||||
# icon present. Replace with a real 1024x1024 PNG before launch.
|
||||
python3 - <<'PY'
|
||||
import struct, zlib, os
|
||||
def chunk(t, d): return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
|
||||
W = H = 256
|
||||
ihdr = struct.pack(">IIBBBBB", W, H, 8, 2, 0, 0, 0) # 8-bit RGB
|
||||
raw = b"".join(b"\x00" + b"\x16\x19\x22" * W for _ in range(H)) # filter byte + dark pixels
|
||||
idat = zlib.compress(raw, 9)
|
||||
png = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", ihdr) + chunk(b"IDAT", idat) + chunk(b"IEND", b"")
|
||||
out = os.environ["APPDIR"] + "/datatools.png"
|
||||
open(out, "wb").write(png)
|
||||
PY
|
||||
fi
|
||||
export APPDIR
|
||||
|
||||
ARCH=x86_64 appimagetool "$APPDIR" "$OUT"
|
||||
echo "Built $OUT"
|
||||
Reference in New Issue
Block a user