Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
+206
View File
@@ -0,0 +1,206 @@
#!/usr/bin/env bash
# Сборка OTA-релиза WESP: код + полный vendor/wheels (offline-установка на клиенте).
#
# Каждый ZIP — самодостаточный пакет: pip download → verify → zip.
# x86 и ARM — разные релизы: собирайте на машине той же ОС/arch, что терминалы
# в проде, и публикуйте в отдельный Gitea-репозиторий.
#
# Полный цикл (пути с пробелами — в кавычках):
# bash "./scripts/build_release.sh" 2.0.5
# → dist/wesp-2.0.5-linux-x86_64.zip (или darwin-x86_64, linux-aarch64 …)
# Собирайте на той же ОС/Python, что на терминалах в проде (см. WESP_PREPARE_PYTHON).
#
# Только wheelhouse (без ZIP):
# ./scripts/build_release.sh --wheelhouse-only
#
# ZIP без повторного pip download (wheels уже собраны на этой же машине):
# ./scripts/build_release.sh --skip-prepare 2.0.5
set -euo pipefail
SKIP_PREPARE=0
WHEELHOUSE_ONLY=0
VERSION=""
while [[ $# -gt 0 ]]; do
case "$1" in
--skip-prepare) SKIP_PREPARE=1; shift ;;
--wheelhouse-only) WHEELHOUSE_ONLY=1; shift ;;
-h|--help)
sed -n '2,16p' "$0"
exit 0
;;
-*) echo "Unknown option: $1" >&2; exit 1 ;;
*)
if [[ -z "$VERSION" ]]; then
VERSION="$1"
else
echo "Unexpected argument: $1" >&2
exit 1
fi
shift
;;
esac
done
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
PYTHON="${WESP_PREPARE_PYTHON:-python3}"
REQ="${ROOT}/requirements-prod.txt"
WHEELS="${ROOT}/vendor/wheels"
BUILD_ARCH="$(uname -m 2>/dev/null || echo unknown)"
BUILD_PLATFORM="$("$PYTHON" -c 'import platform; print(platform.system())' 2>/dev/null || uname -s 2>/dev/null || echo unknown)"
BUILD_OS="$(echo "$BUILD_PLATFORM" | tr '[:upper:]' '[:lower:]')"
BUILD_TAG="${BUILD_OS}-${BUILD_ARCH}"
log_build_target() {
echo "==> Build target: ${BUILD_PLATFORM} / ${BUILD_ARCH} (${BUILD_TAG})"
echo " ZIP содержит vendor/wheels для этой ОС. Другая arch → другой репозиторий."
}
wheelhouse_file_count() {
find "$WHEELS" -type f \( -name '*.whl' -o -name '*.tar.gz' -o -name '*.zip' \) 2>/dev/null | wc -l | tr -d ' '
}
clean_wheelhouse() {
echo "==> Clean vendor/wheels (кроме .gitkeep)"
mkdir -p "$WHEELS"
find "$WHEELS" -mindepth 1 ! -name '.gitkeep' -delete
}
prepare_wheelhouse() {
log_build_target
clean_wheelhouse
echo "==> Download wheels (PyPI) → vendor/wheels/ [requirements-prod.txt + транзитивные deps]"
"$PYTHON" -m pip download --prefer-binary -r "$REQ" -d "$WHEELS"
"$PYTHON" -m pip download setuptools wheel packaging -d "$WHEELS"
echo "==> Materialize sdists → wheels (zeroconf и др., без Cython с PyPI на терминале)"
"$PYTHON" "${ROOT}/scripts/materialize_wheelhouse_sdists.py" \
--wheels "$WHEELS" \
--python "$PYTHON"
"$PYTHON" "${ROOT}/scripts/verify_release_deps.py" \
--req "$REQ" \
--python "$PYTHON" \
--verify-closure \
--write-manifest \
--build-arch "$BUILD_ARCH" \
--build-platform "$BUILD_PLATFORM"
}
verify_wheelhouse() {
echo "==> Verify vendor/wheels (обязательно перед упаковкой)"
"$PYTHON" "${ROOT}/scripts/verify_release_deps.py" \
--req "$REQ" \
--python "$PYTHON" \
--verify-closure
}
verify_static_assets() {
echo "==> Verify static UI assets (offline, no CDN in HTML/CSS)"
"$PYTHON" "${ROOT}/scripts/verify_static_offline_assets.py"
}
zip_wheelhouse_summary() {
local archive="$1"
local whl_in_zip whl_bytes_in_zip
whl_in_zip="$(unzip -l "$archive" 2>/dev/null | grep -c 'vendor/wheels/.*\.\(whl\|tar\.gz\)$' || echo 0)"
whl_bytes_in_zip="$(unzip -l "$archive" 2>/dev/null | grep 'vendor/wheels/.*\.\(whl\|tar\.gz\)$' | awk '{s+=$1} END {print s+0}')"
echo " vendor/wheels в ZIP: ${whl_in_zip} файлов, ~$(( whl_bytes_in_zip / 1024 / 1024 )) MB (несжатые .whl)"
}
build_zip() {
if [[ -z "$VERSION" ]]; then
echo "Usage: $0 <version>" >&2
echo "Example: $0 2.0.5" >&2
exit 1
fi
local out_dir="${ROOT}/dist"
local archive="${out_dir}/wesp-${VERSION}-${BUILD_TAG}.zip"
local staging="${out_dir}/.staging-${VERSION}-${BUILD_TAG}"
local whl_count whl_disk_mb
whl_count="$(wheelhouse_file_count)"
whl_disk_mb="$(du -sk "$WHEELS" 2>/dev/null | awk '{print int($1/1024)}')"
if [[ "$whl_count" -lt 1 ]]; then
echo "ERROR: vendor/wheels пуст — нельзя собрать OTA без зависимостей" >&2
exit 1
fi
echo "==> Pack $(basename "$archive") (wheelhouse на диске: ${whl_count} pkg, ~${whl_disk_mb} MB)"
rm -rf "$staging"
mkdir -p "$staging" "$out_dir"
rsync -a \
--exclude='.git/' \
--exclude='.venv/' \
--exclude='wes_mac/' \
--exclude='test/' \
--exclude='__pycache__/' \
--exclude='.pytest_cache/' \
--exclude='*.pyc' \
--exclude='.secret/' \
--exclude='backups/' \
--exclude='temp_updates/' \
--exclude='dist/' \
--exclude='data/*.db' \
--exclude='data/*.db-shm' \
--exclude='data/*.db-wal' \
--exclude='data/logs/' \
--exclude='data/update_state.json' \
--exclude='data/.pending_restart.json' \
--exclude='data/wesp_install_state.json' \
--exclude='data/wesp_security_settings.json' \
--exclude='data/wesp_network_settings.json' \
--exclude='data/wesp_network_diagnostics.json' \
--exclude='data/sync_client_state.json' \
--exclude='.DS_Store' \
--exclude='.cursor/' \
"$ROOT/" "$staging/wesp/"
if [[ ! -d "$staging/wesp/vendor/wheels" ]] || [[ -z "$(find "$staging/wesp/vendor/wheels" -type f -name '*.whl' 2>/dev/null | head -1)" ]]; then
echo "ERROR: vendor/wheels не попал в staging — прервано" >&2
exit 1
fi
mkdir -p "$staging/wesp/data/logs"
touch "$staging/wesp/data/logs/.gitkeep"
echo "{\"version\": \"${VERSION}\"}" > "$staging/wesp/data/config.json"
rm -f "$archive"
(cd "$staging" && zip -rq "$archive" wesp)
rm -rf "$staging"
local size files
size="$(du -sh "$archive" | awk '{print $1}')"
files="$(unzip -l "$archive" | tail -1 | awk '{print $2}')"
echo ""
echo "════════════════════════════════════════"
echo "OTA package: $(basename "$archive")"
echo " Архив: ${size}, ${files} files"
zip_wheelhouse_summary "$archive"
echo " Платформа: ${BUILD_TAG} → свой Gitea-реpo для этих терминалов"
echo " Tag: v${VERSION} or ${VERSION}"
echo "════════════════════════════════════════"
}
if [[ "$SKIP_PREPARE" -eq 0 ]]; then
prepare_wheelhouse
else
echo "==> Skip pip download (--skip-prepare; wheels должны быть с этой же машины/arch)"
if [[ "$(wheelhouse_file_count)" -lt 1 ]]; then
echo "ERROR: vendor/wheels пуст — уберите --skip-prepare" >&2
exit 1
fi
fi
if [[ "$WHEELHOUSE_ONLY" -eq 1 ]]; then
echo "Done (wheelhouse only)."
exit 0
fi
verify_wheelhouse
verify_static_assets
build_zip