fix(build): normalize non-PEP440 versions, fix .py/compileall ordering, wipe NSIS payload dirs
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:
2026-04-07 23:04:38 +03:00
parent 7a9c368448
commit b5842e6424
4 changed files with 69 additions and 7 deletions
+42 -4
View File
@@ -24,6 +24,14 @@ detect_version() {
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
# importlib.metadata reads the correct value at runtime.
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
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
@@ -138,3 +142,37 @@ cleanup_site_packages() {
cleaned_size=$(du -sh "$sp_dir" | cut -f1)
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
}