fix(build): normalize non-PEP440 versions, fix .py/compileall ordering, wipe NSIS payload dirs
Lint & Test / test (push) Successful in 3m18s
Lint & Test / test (push) Successful in 3m18s
- build-common.sh: detect_version() normalizes non-PEP440 labels (e.g. 'dev', 'nightly') to 0.0.0.dev0 so stamping pyproject.toml doesn't break pip install. - build-common.sh: split .py deletion out of cleanup_site_packages into a new compile_and_strip_sources() that runs 'compileall -b' FIRST, then removes sources. compileall now fails loud instead of silently no-op'ing. - build-dist.sh: add missing compile_and_strip_sources call on Linux site-packages (previous tarballs shipped empty packages with no .py and no .pyc). - build-dist-windows.sh: reorder so compile_and_strip_sources runs right after cleanup_site_packages, not after .py files have already been deleted. - installer.nsi: RMDir /r payload dirs (python/, app/, scripts/) and delete LedGrab.bat at the top of SecCore before File /r. NSIS File /r MERGES into existing dirs, so upgrades left half-old/half-new state that surfaced as 'version mismatch' or duplicate-package ImportErrors. data/ and logs/ remain untouched to preserve user config.
This commit is contained in:
+42
-4
@@ -24,6 +24,14 @@ detect_version() {
|
|||||||
|
|
||||||
VERSION_CLEAN="${version#v}"
|
VERSION_CLEAN="${version#v}"
|
||||||
|
|
||||||
|
# Normalize non-PEP440 version labels (e.g. "dev", "nightly", "snapshot")
|
||||||
|
# to a valid PEP440 dev release. Without this, pip/setuptools rejects the
|
||||||
|
# pyproject.toml with: `project.version` must be pep440.
|
||||||
|
if ! [[ "$VERSION_CLEAN" =~ ^[0-9]+(\.[0-9]+)*((a|b|rc|\.dev|\.post)[0-9]+)*(\+[a-zA-Z0-9.]+)?$ ]]; then
|
||||||
|
echo " Warning: '$VERSION_CLEAN' is not PEP440-compliant, using 0.0.0.dev0"
|
||||||
|
VERSION_CLEAN="0.0.0.dev0"
|
||||||
|
fi
|
||||||
|
|
||||||
# Stamp the resolved version into pyproject.toml so that
|
# Stamp the resolved version into pyproject.toml so that
|
||||||
# importlib.metadata reads the correct value at runtime.
|
# importlib.metadata reads the correct value at runtime.
|
||||||
sed -i "s/^version = .*/version = \"${VERSION_CLEAN}\"/" "$SERVER_DIR/pyproject.toml"
|
sed -i "s/^version = .*/version = \"${VERSION_CLEAN}\"/" "$SERVER_DIR/pyproject.toml"
|
||||||
@@ -127,10 +135,6 @@ cleanup_site_packages() {
|
|||||||
find "$sp_dir" -name "*.$ext_suffix" -exec strip --strip-debug {} \; 2>/dev/null || true
|
find "$sp_dir" -name "*.$ext_suffix" -exec strip --strip-debug {} \; 2>/dev/null || true
|
||||||
fi
|
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 ───────────────
|
# ── Remove wled_controller if pip-installed ───────────────
|
||||||
rm -rf "$sp_dir"/wled_controller* "$sp_dir"/wled*.dist-info 2>/dev/null || true
|
rm -rf "$sp_dir"/wled_controller* "$sp_dir"/wled*.dist-info 2>/dev/null || true
|
||||||
|
|
||||||
@@ -138,3 +142,37 @@ cleanup_site_packages() {
|
|||||||
cleaned_size=$(du -sh "$sp_dir" | cut -f1)
|
cleaned_size=$(du -sh "$sp_dir" | cut -f1)
|
||||||
echo " Site-packages after cleanup: $cleaned_size"
|
echo " Site-packages after cleanup: $cleaned_size"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Pre-compile .py → .pyc and strip sources ─────────────────
|
||||||
|
#
|
||||||
|
# MUST run AFTER cleanup_site_packages (so we don't waste work compiling
|
||||||
|
# files that are about to be deleted) and BEFORE any step that ships the
|
||||||
|
# result. Uses `compileall -b` to produce legacy `foo.pyc` next to
|
||||||
|
# `foo.py` (not `__pycache__/foo.cpython-XX.pyc`), which survives the
|
||||||
|
# __pycache__ cleanup and works without a matching .py file at import.
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# $1 — directory to compile (site-packages or app/src)
|
||||||
|
# $2 — python executable to use (default: python3)
|
||||||
|
|
||||||
|
compile_and_strip_sources() {
|
||||||
|
local target_dir="$1"
|
||||||
|
local py_cmd="${2:-python3}"
|
||||||
|
|
||||||
|
if [ ! -d "$target_dir" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Pre-compiling Python bytecode in $(basename "$target_dir")..."
|
||||||
|
"$py_cmd" -m compileall -b -q "$target_dir" 2>/dev/null || {
|
||||||
|
echo " ERROR: compileall failed for $target_dir — aborting"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo " Removing .py source (keeping .pyc)..."
|
||||||
|
# Keep __init__.py so package discovery still works in edge cases
|
||||||
|
# where namespace detection checks for the file.
|
||||||
|
find "$target_dir" -name "*.py" ! -name "__init__.py" -delete 2>/dev/null || true
|
||||||
|
# __pycache__ dirs are redundant now that we have legacy .pyc files
|
||||||
|
find "$target_dir" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|||||||
@@ -273,6 +273,12 @@ rm -rf "$SITE_PACKAGES"/pythonwin 2>/dev/null || true
|
|||||||
rm -f "$SITE_PACKAGES"/PyWin32.chm 2>/dev/null || true
|
rm -f "$SITE_PACKAGES"/PyWin32.chm 2>/dev/null || true
|
||||||
find "$SITE_PACKAGES/winrt" -name "*.pyi" -delete 2>/dev/null || true
|
find "$SITE_PACKAGES/winrt" -name "*.pyi" -delete 2>/dev/null || true
|
||||||
|
|
||||||
|
# Pre-compile and strip .py sources. MUST run AFTER cleanup (so we don't
|
||||||
|
# waste work compiling files about to be deleted). Uses host python —
|
||||||
|
# PYTHON_VERSION above must match the embedded Python major.minor or
|
||||||
|
# the generated .pyc will ImportError on the target.
|
||||||
|
compile_and_strip_sources "$SITE_PACKAGES" "python"
|
||||||
|
|
||||||
WHEEL_COUNT=$(ls "$WHEEL_DIR"/*.whl 2>/dev/null | wc -l)
|
WHEEL_COUNT=$(ls "$WHEEL_DIR"/*.whl 2>/dev/null | wc -l)
|
||||||
echo " Installed $WHEEL_COUNT packages"
|
echo " Installed $WHEEL_COUNT packages"
|
||||||
|
|
||||||
@@ -286,10 +292,9 @@ build_frontend
|
|||||||
echo "[8/9] Copying application files..."
|
echo "[8/9] Copying application files..."
|
||||||
copy_app_files
|
copy_app_files
|
||||||
|
|
||||||
# Pre-compile Python bytecode for faster startup
|
# Pre-compile app source for faster startup (keep .py too — app source
|
||||||
echo " Pre-compiling Python bytecode..."
|
# is small and easier to debug in-place if a user reports an issue)
|
||||||
python -m compileall -b -q "$APP_DIR/src" 2>/dev/null || true
|
python -m compileall -b -q "$APP_DIR/src" 2>/dev/null || true
|
||||||
python -m compileall -b -q "$SITE_PACKAGES" 2>/dev/null || true
|
|
||||||
|
|
||||||
# ── Create launcher ──────────────────────────────────────────
|
# ── Create launcher ──────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ SITE_PACKAGES=$(echo "$VENV_DIR"/lib/python*/site-packages)
|
|||||||
# Clean up with shared function
|
# Clean up with shared function
|
||||||
cleanup_site_packages "$SITE_PACKAGES" "so" "so"
|
cleanup_site_packages "$SITE_PACKAGES" "so" "so"
|
||||||
|
|
||||||
|
# Pre-compile and strip .py sources (must happen AFTER cleanup)
|
||||||
|
compile_and_strip_sources "$SITE_PACKAGES" "python"
|
||||||
|
|
||||||
# ── Build frontend ───────────────────────────────────────────
|
# ── Build frontend ───────────────────────────────────────────
|
||||||
|
|
||||||
echo "[4/7] Building frontend..."
|
echo "[4/7] Building frontend..."
|
||||||
@@ -63,6 +66,10 @@ build_frontend
|
|||||||
echo "[5/7] Copying application files..."
|
echo "[5/7] Copying application files..."
|
||||||
copy_app_files
|
copy_app_files
|
||||||
|
|
||||||
|
# Pre-compile app source for faster startup (keep .py too — app source
|
||||||
|
# is small and easier to debug in-place if a user reports an issue)
|
||||||
|
python -m compileall -b -q "$APP_DIR/src" 2>/dev/null || true
|
||||||
|
|
||||||
# ── Create launcher ──────────────────────────────────────────
|
# ── Create launcher ──────────────────────────────────────────
|
||||||
|
|
||||||
echo "[6/7] Creating launcher..."
|
echo "[6/7] Creating launcher..."
|
||||||
|
|||||||
@@ -87,6 +87,18 @@ Section "!${APPNAME} (required)" SecCore
|
|||||||
|
|
||||||
SetOutPath "$INSTDIR"
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
; Wipe prior payload dirs before extracting. NSIS File /r MERGES files
|
||||||
|
; on top of existing ones — on an upgrade, stale .pyc/.pyd from the old
|
||||||
|
; version (and any files removed or renamed since) would survive,
|
||||||
|
; producing a half-old/half-new install that presents as "version
|
||||||
|
; mismatch" or "duplicate package" ImportErrors at runtime.
|
||||||
|
; IMPORTANT: only touch payload dirs — never $INSTDIR\data or
|
||||||
|
; $INSTDIR\logs (user config must be preserved across upgrades).
|
||||||
|
RMDir /r "$INSTDIR\python"
|
||||||
|
RMDir /r "$INSTDIR\app"
|
||||||
|
RMDir /r "$INSTDIR\scripts"
|
||||||
|
Delete "$INSTDIR\LedGrab.bat"
|
||||||
|
|
||||||
; Copy the entire portable build
|
; Copy the entire portable build
|
||||||
File /r "build\LedGrab\python"
|
File /r "build\LedGrab\python"
|
||||||
File /r "build\LedGrab\app"
|
File /r "build\LedGrab\app"
|
||||||
|
|||||||
Reference in New Issue
Block a user