#!/usr/bin/env bash # # Shared build functions for LedGrab distribution packaging. # Sourced by build-dist.sh (Linux) and build-dist-windows.sh (Windows). # # Expected variables set by the caller before sourcing: # SCRIPT_DIR, BUILD_DIR, DIST_DIR, SERVER_DIR, APP_DIR # ── Version detection ──────────────────────────────────────── detect_version() { # Usage: detect_version [explicit_version] local version="${1:-}" if [ -z "$version" ]; then version=$(git describe --tags --exact-match 2>/dev/null || true) fi if [ -z "$version" ]; then version="${GITEA_REF_NAME:-${GITHUB_REF_NAME:-}}" fi if [ -z "$version" ]; then version=$(grep -oP '^version\s*=\s*"\K[^"]+' "$SERVER_DIR/pyproject.toml" 2>/dev/null || echo "0.0.0") fi VERSION_CLEAN="${version#v}" # Stamp the resolved version into pyproject.toml so that # importlib.metadata reads the correct value at runtime. sed -i "s/^version = .*/version = \"${VERSION_CLEAN}\"/" "$SERVER_DIR/pyproject.toml" } # ── Clean previous build ───────────────────────────────────── clean_dist() { if [ -d "$DIST_DIR" ]; then echo " Cleaning previous build..." rm -rf "$DIST_DIR" fi mkdir -p "$DIST_DIR" } # ── Build frontend ─────────────────────────────────────────── build_frontend() { echo " Building frontend bundle..." (cd "$SERVER_DIR" && npm ci --loglevel error && npm run build) 2>&1 | { grep -v 'RemoteException' || true } } # ── Copy application files ─────────────────────────────────── copy_app_files() { echo " Copying application files..." mkdir -p "$APP_DIR" cp -r "$SERVER_DIR/src" "$APP_DIR/src" cp -r "$SERVER_DIR/config" "$APP_DIR/config" mkdir -p "$DIST_DIR/data" "$DIST_DIR/logs" # Clean up source maps and __pycache__ find "$APP_DIR" -name "*.map" -delete 2>/dev/null || true find "$APP_DIR" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true } # ── Site-packages cleanup ──────────────────────────────────── # # Strips tests, type stubs, unused submodules, and debug symbols # from the installed site-packages directory. # # Args: # $1 — path to site-packages directory # $2 — native extension suffix: "pyd" (Windows) or "so" (Linux) # $3 — native lib suffix for OpenCV ffmpeg: "dll" or "so" cleanup_site_packages() { local sp_dir="$1" local ext_suffix="${2:-so}" local lib_suffix="${3:-so}" echo " Cleaning up site-packages to reduce size..." # ── Generic cleanup ────────────────────────────────────── find "$sp_dir" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true find "$sp_dir" -type d -name tests -exec rm -rf {} + 2>/dev/null || true find "$sp_dir" -type d -name test -exec rm -rf {} + 2>/dev/null || true find "$sp_dir" -type d -name "*.dist-info" -exec rm -rf {} + 2>/dev/null || true find "$sp_dir" -name "*.pyi" -delete 2>/dev/null || true # ── pip / setuptools (not needed at runtime) ───────────── rm -rf "$sp_dir"/pip "$sp_dir"/pip-* 2>/dev/null || true rm -rf "$sp_dir"/setuptools "$sp_dir"/setuptools-* "$sp_dir"/pkg_resources 2>/dev/null || true rm -rf "$sp_dir"/_distutils_hack 2>/dev/null || true # ── OpenCV ─────────────────────────────────────────────── local cv2_dir="$sp_dir/cv2" if [ -d "$cv2_dir" ]; then # Remove ffmpeg (28 MB on Windows), Haar cascades, dev files rm -f "$cv2_dir"/opencv_videoio_ffmpeg*."$lib_suffix" 2>/dev/null || true rm -rf "$cv2_dir/data" "$cv2_dir/gapi" "$cv2_dir/misc" "$cv2_dir/utils" 2>/dev/null || true rm -rf "$cv2_dir/typing_stubs" "$cv2_dir/typing" 2>/dev/null || true fi # ── NumPy ──────────────────────────────────────────────── # Remove unused submodules (only core, fft, random are used) for mod in polynomial linalg ma lib distutils f2py typing _pyinstaller; do rm -rf "$sp_dir/numpy/$mod" 2>/dev/null || true done rm -rf "$sp_dir/numpy/tests" "$sp_dir/numpy/*/tests" 2>/dev/null || true # ── Pillow (only used for system tray icon) ────────────── rm -rf "$sp_dir/PIL/tests" 2>/dev/null || true # Remove unused image format plugins (keep JPEG, PNG, ICO, BMP) for plugin in Eps Gif Tiff Webp Psd Pcx Xbm Xpm Dds Ftex Gbr Grib \ Icns Im Imt Iptc McIrdas Mpo Msp Pcd Pixar Ppm Sgi \ Spider Sun Tga Wal Wmf; do rm -f "$sp_dir/PIL/${plugin}ImagePlugin.py" 2>/dev/null || true rm -f "$sp_dir/PIL/${plugin}ImagePlugin.pyc" 2>/dev/null || true done # ── zeroconf ───────────────────────────────────────────── rm -rf "$sp_dir/zeroconf/_services" 2>/dev/null || true # ── Strip debug symbols ────────────────────────────────── if command -v strip &>/dev/null; then echo " Stripping debug symbols from .$ext_suffix files..." find "$sp_dir" -name "*.$ext_suffix" -exec strip --strip-debug {} \; 2>/dev/null || true fi # ── Remove .py source (keep .pyc bytecode) ─────────────── echo " Removing .py source from site-packages (keeping .pyc)..." find "$sp_dir" -name "*.py" ! -name "__init__.py" -delete 2>/dev/null || true # ── Remove wled_controller if pip-installed ─────────────── rm -rf "$sp_dir"/wled_controller* "$sp_dir"/wled*.dist-info 2>/dev/null || true local cleaned_size cleaned_size=$(du -sh "$sp_dir" | cut -f1) echo " Site-packages after cleanup: $cleaned_size" }