From f72813ed9c0bb8bbacdb5d0a7360e93a4062d74a Mon Sep 17 00:00:00 2001 From: cproudlock Date: Tue, 4 Aug 2026 07:56:39 -0400 Subject: [PATCH] feat(installer): bundle the database - MySQL 8.4 LTS, not 8.0 The bundled-database option could not actually be built. Stage 0 looks for mysql\mysql-8.0.x-winx64.msi, and Oracle no longer publishes a standalone server MSI for 8.0 - every 8.0.x returns 404. What remains for 8.0 is the MySQL Installer bundle, which is an installer-manager: 'msiexec /i INSTALLDIR=' would install THAT rather than a database, and stage 0 would then fail on a missing mysqld.exe. MySQL 8.0 also reached end of life in April 2026, so bundling it would have put an unsupported database on every new site. 8.4 LTS still ships the standalone MSI (129MB, which is what the '125MB' note in stage 0 was written against) and is supported into 2032. Defaults follow it: install root MySQL Server 8.4, service MySQL84. The operator console still looks for an 8.0 install path as a fallback, for sites already running one. Also bundles mysqlclient\ - mysql.exe and mysqldump.exe with the two OpenSSL DLLs they actually import, 20MB rather than the 51MB of debug and auth-plugin libraries the archive ships. Stage 2 stages it onto the server, so a site whose database is on ANOTHER host can still take the pre-upgrade backup that every upgrade depends on. That was the gap the preflight had started warning about. Bundle is now 221MB. --- deploy/windows/installer/README.md | 5 +- deploy/windows/installer/ShopDBFlask.iss | 4 +- deploy/windows/installer/build-installer.ps1 | 2 +- deploy/windows/installer/build-installer.sh | 4 +- deploy/windows/installer/bundle-lock.json | 366 ++++++++++-------- deploy/windows/installer/shopdb-admin.ps1 | 1 + deploy/windows/installer/shopdb-install.ps1 | 12 +- deploy/windows/installer/shopdb-preflight.ps1 | 2 +- docs/INSTALL-WINDOWS-IIS.md | 2 +- docs/INSTALL-WINDOWS.md | 2 +- 10 files changed, 216 insertions(+), 184 deletions(-) diff --git a/deploy/windows/installer/README.md b/deploy/windows/installer/README.md index 7dbf084..f40068c 100644 --- a/deploy/windows/installer/README.md +++ b/deploy/windows/installer/README.md @@ -53,7 +53,8 @@ bundle/wheels/ pip download -r requirements.txt --only-binary=:all bundle/python/ python-3.14.x-amd64.exe bundle/httpplatformhandler/ httpPlatformHandler_amd64.msi bundle/urlrewrite/ rewrite_amd64.msi (client-IP rule; see below) -bundle/mysql/ mysql-8.0.x-winx64.msi (bundled-database option only) +bundle/mysql/ mysql-8.4.x-winx64.msi (bundled-database option only) +bundle/mysqlclient/ mysql.exe, mysqldump.exe + libcrypto/libssl (backups) ``` Then compile on Windows: @@ -235,7 +236,7 @@ database is an upgrade, and treating it as fresh would drop tables. ## Testing notes -Verified end to end on Windows Server 2025 against both a bundled MySQL 8.0 and +Verified end to end on Windows Server 2025 against both a bundled MySQL 8.4 LTS and an existing MySQL 5.6: fresh install, upgrade, re-run idempotency, failure and rollback, uninstall, and both deployment methods including switching between them. diff --git a/deploy/windows/installer/ShopDBFlask.iss b/deploy/windows/installer/ShopDBFlask.iss index 7bbecd2..c83ab42 100644 --- a/deploy/windows/installer/ShopDBFlask.iss +++ b/deploy/windows/installer/ShopDBFlask.iss @@ -4,7 +4,7 @@ ; ; DESIGN NOTE - why this is a thin wrapper and not a reimplementation: ; every install action lives in shopdb-install.ps1, which is verified end to end -; on Windows Server 2025 against both a bundled MySQL 8.0 and an existing MySQL +; on Windows Server 2025 against both a bundled MySQL 8.4 LTS and an existing MySQL ; 5.6. Reimplementing any of it in Pascal Script would create a second code path ; that nobody tests. This file only collects operator input, runs the stages in ; order, and reports which one failed. @@ -402,7 +402,7 @@ begin 'choose the second option - installing a second server would collide on ' + 'port 3306.', True, False); - DbChoicePage.Add('Install the bundled MySQL 8.0 (new servers only)'); + DbChoicePage.Add('Install the bundled MySQL 8.4 LTS (new servers only)'); DbChoicePage.Add('Use a MySQL server this site already runs'); DbChoicePage.SelectedValueIndex := DB_EXISTING; diff --git a/deploy/windows/installer/build-installer.ps1 b/deploy/windows/installer/build-installer.ps1 index 080632f..8c098eb 100644 --- a/deploy/windows/installer/build-installer.ps1 +++ b/deploy/windows/installer/build-installer.ps1 @@ -286,7 +286,7 @@ refresh-bundle-lock.ps1, read the diff, and commit the new lock). # --- summary ---------------------------------------------------------------- Write-Host '' Say " Bundle staged at: $BundleRoot" 'White' -foreach ($d in @('app', 'wheels', 'python', 'httpplatformhandler', 'urlrewrite', 'mysql')) { +foreach ($d in @('app', 'wheels', 'python', 'httpplatformhandler', 'urlrewrite', 'mysqlclient', 'mysql')) { $p = Join-Path $BundleRoot $d if (Test-Path $p) { $mb = ((Get-ChildItem $p -Recurse -File | Measure-Object Length -Sum).Sum / 1MB) diff --git a/deploy/windows/installer/build-installer.sh b/deploy/windows/installer/build-installer.sh index 9062dc2..729a4da 100755 --- a/deploy/windows/installer/build-installer.sh +++ b/deploy/windows/installer/build-installer.sh @@ -82,7 +82,7 @@ done echo "" echo "Bundle staged at: $BUNDLE" -for d in app wheels python httpplatformhandler urlrewrite mysql; do +for d in app wheels python httpplatformhandler urlrewrite mysqlclient mysql; do if [ -d "$BUNDLE/$d" ]; then printf ' %-20s %s\n' "$d" "$(du -sh "$BUNDLE/$d" | cut -f1)" else @@ -125,7 +125,7 @@ else echo " python/ python-3.14.x-amd64.exe" echo " httpplatformhandler/ httpPlatformHandler_amd64.msi" echo " urlrewrite/ rewrite_amd64.msi (client-IP rule; see README)" - echo " mysql/ mysql-8.0.x-winx64.msi (bundled-database option only)" + echo " mysql/ mysql-8.4.x-winx64.msi (bundled-database option only)" echo "" echo " If the payload changed ON PURPOSE, regenerate and COMMIT the lock:" echo " pwsh ./refresh-bundle-lock.ps1 # review the diff" diff --git a/deploy/windows/installer/bundle-lock.json b/deploy/windows/installer/bundle-lock.json index d56fef7..cfde5a2 100644 --- a/deploy/windows/installer/bundle-lock.json +++ b/deploy/windows/installer/bundle-lock.json @@ -1,177 +1,16 @@ { "schema": 1, - "generated": "2026-08-03T15:45:11Z", + "generated": "2026-08-04T11:55:25Z", "pythontag": "cp314", "platform": "win_amd64", "note": "Exact third-party payload of the installer bundle. Regenerate with refresh-bundle-lock.ps1 and COMMIT the change as a reviewed dependency bump.", "payloads": { - "wheels": { - "required": true, - "files": { - "jinja2-3.1.6-py3-none-any.whl": { - "size": 134899, - "sha256": "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" - }, - "itsdangerous-2.2.0-py3-none-any.whl": { - "size": 16234, - "sha256": "c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef" - }, - "cffi-2.1.0-cp314-cp314-win_amd64.whl": { - "size": 187937, - "sha256": "1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb" - }, - "email_validator-2.3.0-py3-none-any.whl": { - "size": 35604, - "sha256": "80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4" - }, - "urllib3-2.7.0-py3-none-any.whl": { - "size": 131087, - "sha256": "9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897" - }, - "flask_jwt_extended-4.7.3-py2.py3-none-any.whl": { - "size": 22698, - "sha256": "905ac807b52b5409bc9244dbcca434968c13ca6f9d91bffe7d4cb71e0e6231cb" - }, - "flask_sqlalchemy-3.1.1-py3-none-any.whl": { - "size": 25125, - "sha256": "4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0" - }, - "pycparser-3.0-py3-none-any.whl": { - "size": 48172, - "sha256": "b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992" - }, - "requests-2.33.1-py3-none-any.whl": { - "size": 64947, - "sha256": "4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a" - }, - "blinker-1.9.0-py3-none-any.whl": { - "size": 8458, - "sha256": "ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc" - }, - "greenlet-3.5.0-cp314-cp314-win_amd64.whl": { - "size": 239835, - "sha256": "3bc59be3945ae9750b9e7d45067d01ae3fe90ea5f9ade99239dabdd6e28a5033" - }, - "marshmallow_sqlalchemy-1.5.0-py3-none-any.whl": { - "size": 16582, - "sha256": "3865232672f3dd38c4d5e4e85fdedce76904200742c3594948a2d11d0af93258" - }, - "alembic-1.18.4-py3-none-any.whl": { - "size": 263893, - "sha256": "a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a" - }, - "pyjwt-2.12.1-py3-none-any.whl": { - "size": 29726, - "sha256": "28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c" - }, - "mako-1.3.12-py3-none-any.whl": { - "size": 78521, - "sha256": "8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9" - }, - "waitress-3.0.2-py3-none-any.whl": { - "size": 56232, - "sha256": "c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e" - }, - "colorama-0.4.6-py2.py3-none-any.whl": { - "size": 25335, - "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - }, - "certifi-2026.4.22-py3-none-any.whl": { - "size": 135707, - "sha256": "3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a" - }, - "cachelib-0.13.0-py3-none-any.whl": { - "size": 20914, - "sha256": "8c8019e53b6302967d4e8329a504acf75e7bc46130291d30188a6e4e58162516" - }, - "pymysql-1.1.3-py3-none-any.whl": { - "size": 45356, - "sha256": "8164ba62c552f6105f3b11753352d0f16b90d1703ba67d81923d5a8a5d1c5289" - }, - "werkzeug-3.1.8-py3-none-any.whl": { - "size": 226459, - "sha256": "63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50" - }, - "idna-3.13-py3-none-any.whl": { - "size": 68629, - "sha256": "892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3" - }, - "python_dotenv-1.2.2-py3-none-any.whl": { - "size": 22101, - "sha256": "1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a" - }, - "flask_marshmallow-1.5.0-py3-none-any.whl": { - "size": 12161, - "sha256": "99951c77e5654111ed733811c6dc9310bfb4c3688c78a9e76f80b5ae0b2279a6" - }, - "markupsafe-3.0.3-cp314-cp314-win_amd64.whl": { - "size": 15341, - "sha256": "bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581" - }, - "flask_cors-6.0.2-py3-none-any.whl": { - "size": 13257, - "sha256": "e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a" - }, - "flask_caching-2.4.0-py3-none-any.whl": { - "size": 28727, - "sha256": "d15b8135f055c4f28f6f7dbcf8d36a3de4af1224def975ae6e0b43cbfa684486" - }, - "tzdata-2026.3-py2.py3-none-any.whl": { - "size": 348168, - "sha256": "dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931" - }, - "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl": { - "size": 159634, - "sha256": "92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f" - }, - "sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl": { - "size": 2144204, - "sha256": "77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5" - }, - "marshmallow-4.3.0-py3-none-any.whl": { - "size": 49148, - "sha256": "46c4fe6984707e3cbd485dfebbf0a59874f58d695aad05c1668d15e8c6e13b46" - }, - "dnspython-2.8.0-py3-none-any.whl": { - "size": 331094, - "sha256": "01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af" - }, - "typing_extensions-4.15.0-py3-none-any.whl": { - "size": 44614, - "sha256": "f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" - }, - "flask-3.1.3-py3-none-any.whl": { - "size": 103424, - "sha256": "f4bcbefc124291925f1a26446da31a5178f9483862233b23c0c96a20701f670c" - }, - "tabulate-0.10.0-py3-none-any.whl": { - "size": 39814, - "sha256": "f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3" - }, - "mysql_connector_python-9.7.0-cp314-cp314-win_amd64.whl": { - "size": 18197576, - "sha256": "5a5abbc152bc28cb2e64a04605ecd9941eff6b0dc5f9528cb84adb873e9a1e49" - }, - "Flask_Migrate-4.1.0-py3-none-any.whl": { - "size": 21237, - "sha256": "24d8051af161782e0743af1b04a152d007bad9772b2bca67b7ec1e8ceeb3910d" - }, - "cryptography-50.0.0-cp311-abi3-win_amd64.whl": { - "size": 3840395, - "sha256": "bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30" - }, - "click-8.3.3-py3-none-any.whl": { - "size": 110502, - "sha256": "a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613" - } - } - }, "python": { "required": true, "files": { "python-3.14.6-amd64.exe": { - "size": 30774112, - "sha256": "14b3e9a710a3fcf0bd9b55ab6b60412bd91227563f813fc49040cabc0209e0bd" + "sha256": "14b3e9a710a3fcf0bd9b55ab6b60412bd91227563f813fc49040cabc0209e0bd", + "size": 30774112 } } }, @@ -179,8 +18,169 @@ "required": false, "files": { "rewrite_amd64_en-US.msi": { - "size": 6078464, - "sha256": "37342ff2f585f263f34f48e9de59eb1051d61015a8e967dbde4075716230a32a" + "sha256": "37342ff2f585f263f34f48e9de59eb1051d61015a8e967dbde4075716230a32a", + "size": 6078464 + } + } + }, + "wheels": { + "required": true, + "files": { + "urllib3-2.7.0-py3-none-any.whl": { + "sha256": "9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", + "size": 131087 + }, + "sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl": { + "sha256": "77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5", + "size": 2144204 + }, + "cffi-2.1.0-cp314-cp314-win_amd64.whl": { + "sha256": "1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb", + "size": 187937 + }, + "pymysql-1.1.3-py3-none-any.whl": { + "sha256": "8164ba62c552f6105f3b11753352d0f16b90d1703ba67d81923d5a8a5d1c5289", + "size": 45356 + }, + "pyjwt-2.12.1-py3-none-any.whl": { + "sha256": "28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", + "size": 29726 + }, + "pycparser-3.0-py3-none-any.whl": { + "sha256": "b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", + "size": 48172 + }, + "flask_jwt_extended-4.7.3-py2.py3-none-any.whl": { + "sha256": "905ac807b52b5409bc9244dbcca434968c13ca6f9d91bffe7d4cb71e0e6231cb", + "size": 22698 + }, + "itsdangerous-2.2.0-py3-none-any.whl": { + "sha256": "c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", + "size": 16234 + }, + "certifi-2026.4.22-py3-none-any.whl": { + "sha256": "3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", + "size": 135707 + }, + "flask-3.1.3-py3-none-any.whl": { + "sha256": "f4bcbefc124291925f1a26446da31a5178f9483862233b23c0c96a20701f670c", + "size": 103424 + }, + "marshmallow-4.3.0-py3-none-any.whl": { + "sha256": "46c4fe6984707e3cbd485dfebbf0a59874f58d695aad05c1668d15e8c6e13b46", + "size": 49148 + }, + "markupsafe-3.0.3-cp314-cp314-win_amd64.whl": { + "sha256": "bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", + "size": 15341 + }, + "mysql_connector_python-9.7.0-cp314-cp314-win_amd64.whl": { + "sha256": "5a5abbc152bc28cb2e64a04605ecd9941eff6b0dc5f9528cb84adb873e9a1e49", + "size": 18197576 + }, + "jinja2-3.1.6-py3-none-any.whl": { + "sha256": "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", + "size": 134899 + }, + "waitress-3.0.2-py3-none-any.whl": { + "sha256": "c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", + "size": 56232 + }, + "colorama-0.4.6-py2.py3-none-any.whl": { + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "size": 25335 + }, + "cachelib-0.13.0-py3-none-any.whl": { + "sha256": "8c8019e53b6302967d4e8329a504acf75e7bc46130291d30188a6e4e58162516", + "size": 20914 + }, + "requests-2.33.1-py3-none-any.whl": { + "sha256": "4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", + "size": 64947 + }, + "email_validator-2.3.0-py3-none-any.whl": { + "sha256": "80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", + "size": 35604 + }, + "tabulate-0.10.0-py3-none-any.whl": { + "sha256": "f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", + "size": 39814 + }, + "flask_cors-6.0.2-py3-none-any.whl": { + "sha256": "e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", + "size": 13257 + }, + "flask_caching-2.4.0-py3-none-any.whl": { + "sha256": "d15b8135f055c4f28f6f7dbcf8d36a3de4af1224def975ae6e0b43cbfa684486", + "size": 28727 + }, + "typing_extensions-4.15.0-py3-none-any.whl": { + "sha256": "f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", + "size": 44614 + }, + "flask_marshmallow-1.5.0-py3-none-any.whl": { + "sha256": "99951c77e5654111ed733811c6dc9310bfb4c3688c78a9e76f80b5ae0b2279a6", + "size": 12161 + }, + "werkzeug-3.1.8-py3-none-any.whl": { + "sha256": "63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", + "size": 226459 + }, + "cryptography-50.0.0-cp311-abi3-win_amd64.whl": { + "sha256": "bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30", + "size": 3840395 + }, + "idna-3.13-py3-none-any.whl": { + "sha256": "892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", + "size": 68629 + }, + "blinker-1.9.0-py3-none-any.whl": { + "sha256": "ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", + "size": 8458 + }, + "dnspython-2.8.0-py3-none-any.whl": { + "sha256": "01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", + "size": 331094 + }, + "python_dotenv-1.2.2-py3-none-any.whl": { + "sha256": "1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", + "size": 22101 + }, + "Flask_Migrate-4.1.0-py3-none-any.whl": { + "sha256": "24d8051af161782e0743af1b04a152d007bad9772b2bca67b7ec1e8ceeb3910d", + "size": 21237 + }, + "mako-1.3.12-py3-none-any.whl": { + "sha256": "8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9", + "size": 78521 + }, + "flask_sqlalchemy-3.1.1-py3-none-any.whl": { + "sha256": "4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0", + "size": 25125 + }, + "click-8.3.3-py3-none-any.whl": { + "sha256": "a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", + "size": 110502 + }, + "marshmallow_sqlalchemy-1.5.0-py3-none-any.whl": { + "sha256": "3865232672f3dd38c4d5e4e85fdedce76904200742c3594948a2d11d0af93258", + "size": 16582 + }, + "greenlet-3.5.0-cp314-cp314-win_amd64.whl": { + "sha256": "3bc59be3945ae9750b9e7d45067d01ae3fe90ea5f9ade99239dabdd6e28a5033", + "size": 239835 + }, + "tzdata-2026.3-py2.py3-none-any.whl": { + "sha256": "dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", + "size": 348168 + }, + "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl": { + "sha256": "92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", + "size": 159634 + }, + "alembic-1.18.4-py3-none-any.whl": { + "sha256": "a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", + "size": 263893 } } }, @@ -188,8 +188,38 @@ "required": true, "files": { "httpPlatformHandler_amd64.msi": { - "size": 557056, - "sha256": "90f8d4905a0ab4f2c95223b3c79e2807a0b74507747d240e43c4302e8db4b5ef" + "sha256": "90f8d4905a0ab4f2c95223b3c79e2807a0b74507747d240e43c4302e8db4b5ef", + "size": 557056 + } + } + }, + "mysqlclient": { + "required": false, + "files": { + "libssl-3-x64.dll": { + "sha256": "e24fcd6c8ec31a14c97f520b5b960ed360c55ddf0935040eff297e511697633e", + "size": 788616 + }, + "mysqldump.exe": { + "sha256": "329410b7a8ae3d68d38e6f5b781610770854d3f11b975060e231dae62c20dc46", + "size": 7142528 + }, + "libcrypto-3-x64.dll": { + "sha256": "e84ec61fc1b07a3c899ae39c1dc3f38591cdd310c043a388e7ab40a6828aa297", + "size": 5187216 + }, + "mysql.exe": { + "sha256": "bd6880253c1853fc17b1e19129d6e5d9f9c86a2dccf2c7c9e6b878a10baa9770", + "size": 7177336 + } + } + }, + "mysql": { + "required": false, + "files": { + "mysql-8.4.6-winx64.msi": { + "sha256": "868885b2e221409f0170729bb30b2b2ce83440a1a4c735d19b3c225b51045762", + "size": 135081984 } } } diff --git a/deploy/windows/installer/shopdb-admin.ps1 b/deploy/windows/installer/shopdb-admin.ps1 index 4307aee..9d4ad38 100644 --- a/deploy/windows/installer/shopdb-admin.ps1 +++ b/deploy/windows/installer/shopdb-admin.ps1 @@ -195,6 +195,7 @@ function Get-DbParts { function Find-MysqlClient { $candidates = @( + 'C:\Program Files\MySQL\MySQL Server 8.4\bin\mysql.exe', 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe', 'C:\mysql56\bin\mysql.exe' ) + @(Get-ChildItem 'C:\Program Files\MySQL' -Filter mysql.exe -Recurse -EA SilentlyContinue | diff --git a/deploy/windows/installer/shopdb-install.ps1 b/deploy/windows/installer/shopdb-install.ps1 index feae3a8..6b444d1 100644 --- a/deploy/windows/installer/shopdb-install.ps1 +++ b/deploy/windows/installer/shopdb-install.ps1 @@ -49,7 +49,7 @@ [CmdletBinding()] param( - # Stage 0 installs the bundled MySQL 8.0 (greenfield sites only). It is NOT in + # Stage 0 installs the bundled MySQL 8.4 LTS (greenfield sites only). It is NOT in # 'all': a site with an existing MySQL must never have a second server dropped # on top of it, and that is the common case (docs/DEPLOY-WINDOWS-IIS.md: the # target box already runs the classic ASP shopdb against MySQL 5.6). Run it @@ -57,10 +57,10 @@ param( [ValidateSet('0','1','2','3','4','5','all','uninstall')] [string] $Stage = 'all', # Bundled-MySQL (stage 0) settings. The root and app passwords are GENERATED, # never supplied: see New-Secret. Root is shown once and not persisted. - [string] $MysqlRoot = 'C:\Program Files\MySQL\MySQL Server 8.0', + [string] $MysqlRoot = 'C:\Program Files\MySQL\MySQL Server 8.4', [string] $MysqlDataDir = 'C:\ProgramData\MySQL\data', [string] $MysqlIni = 'C:\ProgramData\MySQL\my.ini', - [string] $MysqlService = 'MySQL80', + [string] $MysqlService = 'MySQL84', [Parameter(Mandatory=$true)] [string] $BundleRoot, [string] $AppRoot = 'C:\shopdb-flask', [int] $SitePort = 8090, @@ -608,19 +608,19 @@ except Exception: } # ============================================================================= -# STAGE 0 - bundled MySQL 8.0 (greenfield sites only) +# STAGE 0 - bundled MySQL 8.4 LTS (greenfield sites only) # ============================================================================= # The MSI installs BINARIES ONLY: no service, no data directory, no config. The # full sequence is msiexec -> write my.ini -> --initialize-insecure -> --install # -> Start-Service -> bootstrap SQL. Every step below has bitten us once. function Invoke-Stage0 { - Write-Log 'STAGE 0: bundled MySQL 8.0' 'STEP' + Write-Log 'STAGE 0: bundled MySQL 8.4 LTS' 'STEP' $msi = Get-ChildItem (Join-Path $BundleRoot 'mysql') -Filter '*.msi' -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $msi) { Fail "no MySQL MSI in $BundleRoot\mysql" @' -Stage 0 installs the BUNDLED database. Add mysql\mysql-8.0.x-winx64.msi to the +Stage 0 installs the BUNDLED database. Add mysql\mysql-8.4.x-winx64.msi to the bundle, or skip stage 0 and use the site's existing server (the common case). '@ } diff --git a/deploy/windows/installer/shopdb-preflight.ps1 b/deploy/windows/installer/shopdb-preflight.ps1 index dfaaeee..5a8c24d 100644 --- a/deploy/windows/installer/shopdb-preflight.ps1 +++ b/deploy/windows/installer/shopdb-preflight.ps1 @@ -350,7 +350,7 @@ Invoke-Check 'MySQL' 'Service' { $svcs = @(Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^MySQL' -or $_.DisplayName -match 'MySQL' }) if ($svcs.Count -eq 0) { Add-Result 'MySQL' 'Service' 'INFO' 'no MySQL service found' ` - 'Bundled MySQL 8.0 is the appropriate choice on this box.' + 'Bundled MySQL 8.4 LTS is the appropriate choice on this box.' return } foreach ($s in $svcs) { diff --git a/docs/INSTALL-WINDOWS-IIS.md b/docs/INSTALL-WINDOWS-IIS.md index 9cb9031..09c404f 100644 --- a/docs/INSTALL-WINDOWS-IIS.md +++ b/docs/INSTALL-WINDOWS-IIS.md @@ -23,7 +23,7 @@ lives). Run PowerShell as Administrator. | --- | --- | | **Python 3.14** (64-bit) | `python --version` | | **IIS** with **HttpPlatformHandler** | https://www.iis.net/downloads/microsoft/httpplatformhandler (direct MSI: `download.microsoft.com/download/8/1/3/813AC4E6-9203-4F7A-8DD5-F3D54D10C5CD/httpPlatformHandler_amd64.msi`) | -| **MySQL 8.0** (standard for new installs) | reachable from the app host. 5.7+ is supported on an existing server; 5.6 needs the flags in step 1. CI and the container image both target 8.0. | +| **MySQL 8.4 LTS** (standard for new installs) | reachable from the app host. 8.0 reached end of life in April 2026 and no longer ships a standalone server MSI. 5.7+ still works on an existing server; 5.6 needs the flags in step 1. | | URL Rewrite (optional) | only for the real-client-IP rule; skip it and the app still runs | The app itself pulls in `waitress` and `tzdata` from `requirements.txt` (step 4). diff --git a/docs/INSTALL-WINDOWS.md b/docs/INSTALL-WINDOWS.md index 36d22b0..23d28a5 100644 --- a/docs/INSTALL-WINDOWS.md +++ b/docs/INSTALL-WINDOWS.md @@ -35,7 +35,7 @@ time. Two options. Pick before you start, because they ask different questions. -- **Use the bundled MySQL** - the installer puts MySQL 8.0 on this server and +- **Use the bundled MySQL** - the installer puts MySQL 8.4 LTS on this server and creates the database for you. Choose this when the server has no database today. Simplest option, nothing to arrange in advance. - **Use an existing MySQL** - the database already exists somewhere, and you have