diff --git a/CHANGELOG.md b/CHANGELOG.md index 56aedbc016..7a5f6c8bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ All historical references to "CFWheels" in this changelog have been preserved fo ### Fixed -- The Scoop `wheels.cmd` wrapper (both `wheels` and `wheels-be` channels) now dispatches LuCLI via `"%JAVA_HOME%\bin\java.exe" -client -jar "%~dp0lucli-.bat" %*` instead of `call "%~dp0lucli-.bat" %*`. The `lucli-.bat` artifact is a bat-jar concatenation (small bat preamble + raw JAR ZIP bytes, ~915 KB), and cmd.exe pre-parses the entire file looking for labels before running it — on at least Windows 11 10.0.26200.8457 that pre-parse trips on a byte sequence in the JAR tail and aborts with `The filename, directory name, or volume label syntax is incorrect.` before LuCLI ever executes. Invoking java directly bypasses the bat-file pre-parser; java reads the JAR via stream and skips the bat preamble. The wrapper now also resolves `JAVA_HOME` from the openjdk21 dependency declared via `depends: java/openjdk21` (preferring `%SCOOP%\apps\openjdk21\current`, falling back to the sibling-app layout `%~dp0..\..\openjdk21\current`) and fails fast with an actionable install hint when neither is found. The same fix is applied to the `:deploy_dispatch` branch added by #2691. The published bucket needs republishing for existing installs to pick up the fix on their next `scoop update`. Closes #2765 +- The Scoop `wheels.cmd` wrapper (both `wheels` and `wheels-be` channels) was failing on Windows 11 build 10.0.26200.8457 with `The filename, directory name, or volume label syntax is incorrect.` before LuCLI could run, due to two compounding bugs: (1) `call "%~dp0lucli-.bat" %*` made cmd.exe pre-parse the entire bat-jar concatenation (~915 KB of bat preamble + `:JAR_BOUNDARY` + raw JAR ZIP bytes) looking for labels, and the pre-parser tripped on byte sequences in the ZIP tail; (2) `JAVA_HOME=%~dp0share\jdk` pointed at a location Scoop's extraction didn't reliably produce — on at least one machine the inlined OpenJDK 21 zip landed at `%~dp0jdk-21.0.2` (the ZIP's root layout, as if `extract_to=share/jdk` were ignored) instead. The fix landed directly in the canonical bucket via wheels-dev/scoop-wheels#6: the wrapper now dispatches LuCLI via `"%JAVA_HOME%\bin\java.exe" -client -jar "%~dp0lucli-.bat" %*` (java reads the JAR via stream and skips the bat preamble, bypassing cmd's pre-parser entirely), and a one-line fallback `if not exist "%JAVA_HOME%\bin\java.exe" set "JAVA_HOME=%~dp0jdk-21.0.2"` handles the broken-extraction case. As part of the same cleanup, the stale Scoop manifest drafts at `tools/distribution-drafts/scoop/` (`build-manifests.py`, `validate.py`, `wheels.json`, `wheels-be.json`, and the local README), plus the regression spec at `vendor/wheels/tests/specs/cli/ScoopWrapperSpec.cfc` that pinned against those drafts, are removed — the live bucket has had its own self-hosted autoupdate workflow and an inline-JDK layout since scoop-wheels@3f22250 and the in-repo drafts had silently diverged on every meaningful axis (inline JDK vs. `depends:`, real hashes vs. placeholder zeros, autoupdate strategy, wrapper template). `tools/distribution-drafts/README.md` is updated to note that the scoop bucket is now canonical and no longer mirrored here. Closes #2765 (#2767) - Release artifacts (`wheels-core`, `wheels-cli`, `wheels-base-template`, `wheels-starter-app`) now ship `*.zip.sha512` / `*.zip.md5` checksum sidecars (was `*.sha512` / `*.md5`) so the scoop-wheels `autoupdate` config — which expects the `.zip.sha512` shape via `$url.sha512` substitution — no longer 404s on every non-module artifact. `wheels-module` already used the correct shape; this brings the other four artifacts and both release workflows (`release.yml`, `release-candidate.yml`, plus the `snapshot.yml` reusable-workflow chain) into line. Closes the Windows install regression reported in #2758 + scoop-wheels#2 (#2761) - Docs: Windows install steps in `start-here/installing.mdx` and `command-line-tools/installation.mdx` now call out `scoop bucket add java` as a prerequisite. Scoop's `depends:` declaration does not auto-add the dependency bucket on the user's behalf, so users hit `Couldn't find manifest for 'openjdk21' from 'java' bucket` before they could proceed (#2761) - `$viteResolveAssets()` on Adobe CF 2023/2025 returned empty `preloads` and `styles` arrays when the manifest included transitive imports with CSS chunks. Root cause: Adobe CF copies arrays by value when they are passed directly from a struct literal — `$viteWalkImports(preloads = local.rv.preloads, styles = local.rv.styles, ...)` handed the walker independent copies on Adobe CF, so every `ArrayAppend(arguments.preloads, ...)` inside the recursion wrote to garbage and `local.rv` came back empty. Lucee and BoxLang share the array references, so the bug was Adobe-only. Fix: pass the parent `rv` struct and mutate `arguments.rv.preloads` / `arguments.rv.styles` — struct references are shared on every engine (Cross-Engine Invariant #6). Affects every helper that walks transitive imports: `viteScriptTag`, `viteStyleTag`, `vitePreloadTag`, and `$viteHtmlHead`. Existing viteSpec assertions on transitive-import walk, diamond-dependency dedup, and cyclic-import termination serve as the regression catch (#2756) diff --git a/tools/distribution-drafts/README.md b/tools/distribution-drafts/README.md index d29ecdd50f..8867c0764d 100644 --- a/tools/distribution-drafts/README.md +++ b/tools/distribution-drafts/README.md @@ -11,14 +11,16 @@ When merged, the contents of this directory should be copied into: | `homebrew/wheels-be.rb` | `wheels-dev/homebrew-wheels` | `Formula/wheels-be.rb` (new file) | | `homebrew/bleeding-edge-update.yml` | `wheels-dev/homebrew-wheels` | `.github/workflows/bleeding-edge-update.yml` (new file) | | `homebrew/auto-update-channel-patch.md` | (informational) | applied as a small patch to the existing `auto-update.yml` | -| `scoop/wheels.json` | `wheels-dev/scoop-wheels` (new repo) | `bucket/wheels.json` | -| `scoop/wheels-be.json` | `wheels-dev/scoop-wheels` | `bucket/wheels-be.json` | | `winget/manifests/*.yaml` | `microsoft/winget-pkgs` (PR) | `manifests/w/WheelsFramework/Wheels//` | | `snapshots-repo/README.md` | `wheels-dev/wheels-snapshots` (✅ pushed) | `README.md` | | `snapshots-repo/cleanup-old-snapshots.yml` | `wheels-dev/wheels-snapshots` (✅ pushed) | `.github/workflows/cleanup-old-snapshots.yml` | | `linux-packages/*` | reference + Phase 2 plan for `apt.wheels.dev` / `yum.wheels.dev` | (CF Pages) | -After Tuesday's GA, this directory can either stay (as canonical source-of-truth -for what each tap looks like) or be removed (the taps become authoritative). -Leaning toward keeping it — drift between the in-repo template and the actual -tap is a useful diff signal during release reviews. +## Scoop bucket is authoritative, not drafted here + +The Scoop manifests previously drafted in `scoop/` were removed (wheels#2765). +The live `wheels-dev/scoop-wheels` bucket has its own self-hosted autoupdate +workflow and is the unambiguous source of truth — keeping a drafted copy here +just produced silent drift (the in-repo drafts grew out of sync with the +bucket's inline-JDK rework and no one noticed for two releases). Edit the +bucket repo directly; this repo no longer mirrors it. diff --git a/tools/distribution-drafts/scoop/README.md b/tools/distribution-drafts/scoop/README.md deleted file mode 100644 index e6913cf32a..0000000000 --- a/tools/distribution-drafts/scoop/README.md +++ /dev/null @@ -1,141 +0,0 @@ -# Scoop bucket — `wheels-dev/scoop-wheels` - -Drafts of the two manifests that will live in the public Scoop bucket. Both are -machine-generated by [`build-manifests.py`](build-manifests.py) — edit the -generator, not the JSON, then run `python3 build-manifests.py` to regenerate. - -| Manifest | Channel | Tracks | -|---|---|---| -| [`wheels.json`](wheels.json) | stable | `wheels-dev/wheels` GA tags | -| [`wheels-be.json`](wheels-be.json) | bleeding-edge | `wheels-dev/wheels-snapshots` pre-releases | - -Once the public bucket repo exists, both files land at `bucket/wheels.json` and -`bucket/wheels-be.json` (the canonical Scoop bucket layout). - -## What the manifest does - -Each install lands four payloads under Scoop's per-version app dir (`$dir`): - -| Asset | Source | Where | -|---|---|---| -| `wheels-module-.zip` | wheels release | `$dir\share\module\` | -| `wheels-core-.zip` | wheels release (top-level `wheels/` stripped via `extract_dir`) | `$dir\share\framework\wheels\` | -| `lucli-0.3.7.bat` | cybersonic/LuCLI release | `$dir\` | -| `sqlite-jdbc-3.49.1.0.jar` | Maven Central | `$dir\` | - -The `pre_install` PowerShell block emits a generated `$dir\wheels.cmd` wrapper. -That wrapper is what Scoop's `bin` directive shims onto PATH as `wheels`. We use -`pre_install` (not `post_install`) because Scoop's install order is -`pre_install` → `bin` shim creation → `post_install` — writing `wheels.cmd` in -`post_install` would fail the shim step with `Can't shim 'wheels.cmd': File -doesn't exist.` and abort the install before the wrapper is ever created. - -The wrapper, on every invocation: - -1. Intercepts `--version` / `-v` / `--help` / `-h` before LuCLI sees them - (picocli would otherwise short-circuit and skip our channel-aware banner). -2. Compares `share\module\.module-version` against - `~/.wheels/modules/wheels/.module-version` and re-syncs both `module` and - `framework/wheels` into `~/.wheels` if they differ (first install OR an - upgrade where Scoop swapped the `current` junction). -3. Drops `sqlite-jdbc-3.49.1.0.jar` into every `~/.wheels/express/*/lib/ext/` - directory that doesn't already have it. Self-heals the Lucee bundle - classpath after LuCLI's first-run extraction. -4. Execs `lucli-0.3.7.bat` with the original args. - -The behavior mirrors `Formula/wheels-be.rb` in `wheels-dev/homebrew-wheels` — -same install layout (`share/module`, `share/framework/wheels`, `share/lib`), -same channel-tagged version banner, same first-run-or-upgrade sync logic. - -## Mutual exclusion (without explicit conflicts_with) - -Both manifests declare `bin: [["wheels.cmd", "wheels"]]` — they create the same -PATH shim. Scoop refuses to install both, surfacing a clear error: - -``` -ERROR Failed to install 'wheels-be'. -ERROR shim 'wheels' is in use by 'wheels'. -``` - -Switching channels: - -```powershell -scoop uninstall wheels && scoop install wheels-be -scoop uninstall wheels-be && scoop install wheels -``` - -## How autoupdate keeps the manifests fresh - -Both manifests use Scoop's `checkver` / `autoupdate` blocks so the bucket -self-updates without an opens-PR-per-release workflow on our side. - -| Channel | `checkver` source | Update cadence | -|---|---|---| -| stable | GitHub releases on `wheels-dev/wheels` | Every GA tag | -| bleeding-edge | GitHub releases API on `wheels-dev/wheels-snapshots` (regex matches `v-snapshot.`) | Every develop merge | - -Hashes for `wheels-module-*.zip` and `wheels-core-*.zip` are fetched from the -`.sha512` sidecar files we already publish. Hashes for LuCLI and sqlite-jdbc -are hardcoded — those versions are pinned and won't change in autoupdate -(LuCLI bumps are infrequent and we cut a manual manifest bump; sqlite-jdbc is -immutable on Maven Central). - -The Scoop bucket-updater bot runs hourly across community buckets, so a new -snapshot is install-able within ~1 hour of GitHub release publication. - -## Maintainer setup (one-time) - -1. **Create the public repo.** `gh repo create wheels-dev/scoop-wheels --public --description "Scoop bucket for the Wheels CFML MVC framework"`. Make it - discoverable: add `scoop`, `scoop-bucket`, `wheels`, `cfml` topics. -2. **Push the manifests** under `bucket/`: - ```bash - git clone git@github.com:wheels-dev/scoop-wheels.git - mkdir scoop-wheels/bucket - cp tools/distribution-drafts/scoop/wheels.json scoop-wheels/bucket/ - cp tools/distribution-drafts/scoop/wheels-be.json scoop-wheels/bucket/ - ``` -3. **Add a stub README.md** at the repo root linking back to `wheels-dev/wheels` - and explaining the channel split. -4. **Pre-GA**: leave `wheels.json` with its zero-filled sha512 placeholders. - Scoop's autoupdate will rewrite them when the v4.0.0 GA tag publishes the - `wheels-module-4.0.0.zip.sha512` and `wheels-core-4.0.0.zip.sha512` - sidecars. (Until then, `scoop install wheels` will fail with a hash - mismatch by design — `wheels-be` works immediately.) -5. **Submit the bucket to the Scoop registry** (optional but recommended): - open a PR to `ScoopInstaller/Scoop-Directory` adding `wheels-dev/scoop-wheels` - under the appropriate category. Drives discoverability via `scoop search`. - -## Testing locally without a Windows machine - -The generator emits the entire `wheels.cmd` wrapper as JSON-encoded PowerShell -statements. To pull out the literal CMD content and review it: - -```bash -python3 -c ' -import json, re -m = json.load(open("tools/distribution-drafts/scoop/wheels-be.json")) -for stmt in m["pre_install"]: - mm = re.match(r"\$lines\.Add\(\x27(.*)\x27\)", stmt) - if mm: - print(mm.group(1).replace("\x27\x27", "\x27"))' -``` - -On a Windows test machine: - -```powershell -# After step 1 from "Maintainer setup": -scoop bucket add wheels-test C:\path\to\local\scoop-wheels -scoop install wheels-test/wheels-be -wheels --version # expects: "Wheels Version: 4.0.0-snapshot. (bleeding-edge)" -wheels new myapp -cd myapp -wheels start -``` - -## Skipping Chocolatey - -We deliberately don't ship a Chocolatey package — see the [release-process -docs](../../../web/sites/guides/src/content/docs/v4-0-0-snapshot/contributing/release-process.mdx) -for the rationale (moderation queue latency vs. Scoop's hourly autoupdate). -Existing `wheels` 0.3.x submissions on chocolatey.org are left to bake; no new -versions are submitted. diff --git a/tools/distribution-drafts/scoop/build-manifests.py b/tools/distribution-drafts/scoop/build-manifests.py deleted file mode 100644 index 17bec65680..0000000000 --- a/tools/distribution-drafts/scoop/build-manifests.py +++ /dev/null @@ -1,377 +0,0 @@ -#!/usr/bin/env python3 -""" -Build wheels-be.json and wheels.json Scoop manifests. - -The CMD wrapper has so many escape characters (CMD's `^`, JSON's `\`, PowerShell's -single-quote escaping) that hand-editing is error-prone. This generator emits -both manifests from a single source of truth. - -Output is the sibling wheels.json and wheels-be.json files. Run after bumping -any pinned version constant (LuCLI, sqlite-jdbc, snapshot pin) - the diff -should be small and focused. - -Usage: - python3 build-manifests.py # rewrite both manifests in place - python3 build-manifests.py --check # exit non-zero if regen would change files (CI) -""" - -import json -import sys -from pathlib import Path - -HERE = Path(__file__).parent -OUT = HERE - -# Pinned hashes computed against actual published artifacts. -# These two are stable forever (Maven Central immutable + tagged LuCLI release). -LUCLI_VERSION = "0.3.7" -LUCLI_SHA512 = "75c948319b333d2e9d653d4986e766463f3f29062f62c364ccde2288e5f295bf65a857d54eda2e888cd5a80c2bd9fb727e016f4fca05fc42e56ee219225dd71b" - -SQLITE_JDBC_VERSION = "3.49.1.0" -SQLITE_JDBC_SHA512 = "90b3f6aed150f611fcb9454dfda5fbb9d7faad369937fa8718ac8813c45eb6f0430e6014b7b4c94b4b63e404ade68e83126571f94216de7bf6d2947f1c642803" - -# Verified current snapshot — autoupdate will rewrite these on each new snapshot tag -SNAPSHOT_VERSION = "4.0.0-snapshot.1789" -SNAPSHOT_MODULE_SHA512 = "73b37b01a82ef5abe36c4f02f1aa8870531ac2d6a867ff6482895b6d01dacb068a07af19ec51434ca2caf0b1f8de1437ed5919183f6f0077ef3cd5da7e074be9" -SNAPSHOT_CORE_SHA512 = "fa492a87fdf5ba4153ce24aa216fdda442c2bc39ed256a3348029cfeb74950e7bf8fbc533d7497869287bb9f843c191a9e3cf8703aa4a2fb50bde0db771141b7" - -# Stable not yet published — fill at GA cut. Use the placeholder so manifest is valid. -STABLE_VERSION_PLACEHOLDER = "4.0.0" -STABLE_HASH_PLACEHOLDER = "0" * 128 # 128 zeros = sha512 placeholder - - -def cmd_wrapper(channel: str) -> list[str]: - """The wheels.cmd wrapper. Lines are written verbatim into the .cmd file. - - Mirrors the brew wrapper: - - intercepts --version / -v / --help / -h before LuCLI sees them - - self-heals sqlite-jdbc into LuCLI's express//lib/ext on every run - - sets LUCLI_HOME and execs lucli-0.3.7.bat - """ - # ASCII art banner — `^` escapes CMD's pipe character - banner = [ - r" __ ___ _ ", - r" \ \ / / ^|__ ___ ___^| ^|___", - r" \ \ /\ / /^| '_ \ / _ \/ _ \ / __^|", - r" \ V V / ^| ^| ^| ^| __/ __/ \__ \ ", - r" \_/\_/ ^|_^| ^|_^|\___\___^|_^|___/", - ] - return [ - "@echo off", - "setlocal enabledelayedexpansion", - r'set "LUCLI_HOME=%USERPROFILE%\.wheels"', - r'set "MOD_VER_SRC=%~dp0share\module\.module-version"', - r'set "MOD_VER_DST=%LUCLI_HOME%\modules\wheels\.module-version"', - f'set "SQLITE_SRC=%~dp0sqlite-jdbc-{SQLITE_JDBC_VERSION}.jar"', - "", - 'if "%~1"=="--version" goto :show_version', - 'if "%~1"=="-v" goto :show_version', - 'if "%~1"=="--help" goto :show_help', - 'if "%~1"=="-h" goto :show_help', - "", - ":: First-time module sync -- copies module + framework into ~/.wheels if missing or version-mismatched.", - ':: Mirrors the brew wrapper\'s SRC->DST sync; needed because `wheels new` etc. mutate ~/.wheels but', - ":: scoop's install dir must stay pristine for `scoop uninstall` to work cleanly.", - r'set "WHEELS_MOD_DST=%LUCLI_HOME%\modules\wheels"', - r'set "WHEELS_FRAMEWORK_DST=%WHEELS_MOD_DST%\vendor\wheels"', - r'set "WHEELS_MOD_SRC=%~dp0share\module"', - r'set "WHEELS_FRAMEWORK_SRC=%~dp0share\framework\wheels"', - 'set "src_ver="', - 'set "dst_ver="', - 'if exist "%MOD_VER_SRC%" for /f "usebackq delims=" %%V in ("%MOD_VER_SRC%") do set "src_ver=%%V"', - 'if exist "%MOD_VER_DST%" for /f "usebackq delims=" %%V in ("%MOD_VER_DST%") do set "dst_ver=%%V"', - 'if not "!src_ver!"=="!dst_ver!" (', - ' if exist "%WHEELS_MOD_DST%" rmdir /S /Q "%WHEELS_MOD_DST%" >nul 2>&1', - ' mkdir "%WHEELS_FRAMEWORK_DST%" >nul 2>&1', - ' xcopy /E /I /Y /Q "%WHEELS_MOD_SRC%" "%WHEELS_MOD_DST%" >nul 2>&1', - ' xcopy /E /I /Y /Q "%WHEELS_FRAMEWORK_SRC%" "%WHEELS_FRAMEWORK_DST%" >nul 2>&1', - ")", - "", - ":: Drop sqlite-jdbc into LuCLI's extracted express lib/ext on every run (self-heal).", - ':: The express dir only exists after the first LuCLI run, so this is a no-op on the very', - ":: first invocation and self-heals on every run after.", - 'if exist "%SQLITE_SRC%" (', - r' for /d %%D in ("%LUCLI_HOME%\express\*") do (', - r' if exist "%%D\lib\ext" if not exist "%%D\lib\ext\sqlite-jdbc-' + SQLITE_JDBC_VERSION + '.jar" copy /Y "%SQLITE_SRC%" "%%D\\lib\\ext\\" >nul 2>&1', - " )", - ")", - "", - # JAVA_HOME resolver (issue #2765). The dispatch below invokes - # java.exe directly instead of `call "%~dp0lucli-.bat"`, - # because cmd.exe pre-parses bat files for labels/control flow - # and trips on bytes inside the lucli bat-jar's ZIP tail. On at - # least Windows 11 10.0.26200.8457 that pre-parse aborts the - # script with `The filename, directory name, or volume label - # syntax is incorrect.` before the bat ever runs. - ":: Resolve JAVA_HOME from the openjdk21 dependency declared via `depends: java/openjdk21`.", - ":: The wrapper invokes java.exe directly (not `call lucli-.bat`) to bypass cmd.exe's", - ":: bat-file pre-parser, which trips on bytes in the lucli bat-jar's ZIP tail and aborts", - ":: the script with ERROR_INVALID_NAME on at least Windows 11 10.0.26200.8457 (issue #2765).", - "if not defined JAVA_HOME (", - r' if defined SCOOP if exist "%SCOOP%\apps\openjdk21\current\bin\java.exe" set "JAVA_HOME=%SCOOP%\apps\openjdk21\current"', - ")", - "if not defined JAVA_HOME (", - r' for %%I in ("%~dp0..\..\openjdk21\current") do if exist "%%~fI\bin\java.exe" set "JAVA_HOME=%%~fI"', - ")", - "if not defined JAVA_HOME (", - ' echo Wheels CLI: cannot resolve JAVA_HOME. Install Java with: scoop install java/openjdk21 1>&2', - " exit /b 1", - ")", - "", - ":: `wheels deploy ...` arg rewrite (issue #2674). picocli absorbs --version", - ":: as a root-level flag even after a subcommand, so the documented Kamal form", - ":: `wheels deploy --version=v1.2.3` blows up before Module.cfc runs. Rewrite to", - ":: --release here; Module.cfc accepts both flags.", - 'if /I "%~1"=="deploy" goto :deploy_rewrite', - "", - r'"%JAVA_HOME%\bin\java.exe" -client -jar "%~dp0lucli-' + LUCLI_VERSION + r'.bat" %*', - "exit /b %ERRORLEVEL%", - "", - ":deploy_rewrite", - 'set "WHEELS_DEPLOY_ARGS=deploy"', - "shift", - ":deploy_arg_loop", - 'if "%~1"=="" goto :deploy_dispatch', - 'set "ARG=%~1"', - 'if "!ARG!"=="--version" (', - ' set "WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! --release"', - ') else if "!ARG:~0,10!"=="--version=" (', - ' set "WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! --release=!ARG:~10!"', - ") else (", - ' set "WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! %~1"', - ")", - "shift", - "goto :deploy_arg_loop", - ":deploy_dispatch", - r'"%JAVA_HOME%\bin\java.exe" -client -jar "%~dp0lucli-' + LUCLI_VERSION + r'.bat" !WHEELS_DEPLOY_ARGS!', - "exit /b %ERRORLEVEL%", - "", - ":show_version", - 'set "ver=unknown"', - 'if exist "%MOD_VER_DST%" for /f "usebackq delims=" %%V in ("%MOD_VER_DST%") do set "ver=%%V"', - 'if "!ver!"=="unknown" if exist "%MOD_VER_SRC%" for /f "usebackq delims=" %%V in ("%MOD_VER_SRC%") do set "ver=%%V"', - f"echo Wheels Version: !ver! ({channel})", - "echo.", - *(f"echo {line}" for line in banner), - "echo.", - "echo https://wheels.dev", - "exit /b 0", - "", - ":show_help", - 'set "ver=unknown"', - 'if exist "%MOD_VER_DST%" for /f "usebackq delims=" %%V in ("%MOD_VER_DST%") do set "ver=%%V"', - 'if "!ver!"=="unknown" if exist "%MOD_VER_SRC%" for /f "usebackq delims=" %%V in ("%MOD_VER_SRC%") do set "ver=%%V"', - f"echo Wheels CLI !ver! ({channel})", - "echo CFML MVC framework - code generation, migrations, testing, server management", - "echo.", - "echo Usage:", - "echo wheels ^ [options]", - "echo.", - "echo For full command reference: wheels ^ --help", - "echo More info: https://guides.wheels.dev", - "exit /b 0", - ] - - -def ps_quote_for_addcontent(line: str) -> str: - """Convert a literal CMD line into a PowerShell statement that appends it to wheels.cmd. - - Wraps the line in PowerShell single-quotes (doubling any embedded `'`). - """ - return "$lines.Add('" + line.replace("'", "''") + "')" - - -def build_pre_install(channel: str) -> list[str]: - """Generate the pre_install PowerShell array for the given channel. - - Emitted as `pre_install` rather than `post_install` because Scoop creates the - `bin` shim after pre_install but before post_install. The wheels.cmd launcher - must exist at shim-creation time, otherwise the install aborts with - `Can't shim 'wheels.cmd': File doesn't exist.` and no further hooks run. - """ - lines = cmd_wrapper(channel) - return [ - # Use the .NET List to avoid PowerShell's slow array-realloc pattern - "$lines = New-Object System.Collections.Generic.List[string]", - *[ps_quote_for_addcontent(l) for l in lines], - # ASCII encoding to keep CMD happy on non-UTF8 codepages - 'Set-Content -Path "$dir\\wheels.cmd" -Value $lines -Encoding ASCII', - ] - - -def manifest_be() -> dict: - """Bleeding-edge channel — tracks wheels-dev/wheels-snapshots.""" - base_release = f"https://github.com/wheels-dev/wheels-snapshots/releases/download/v{SNAPSHOT_VERSION}" - lucli_url = f"https://github.com/cybersonic/LuCLI/releases/download/v{LUCLI_VERSION}/lucli-{LUCLI_VERSION}.bat" - sqlite_url = f"https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/{SQLITE_JDBC_VERSION}/sqlite-jdbc-{SQLITE_JDBC_VERSION}.jar" - - return { - "version": SNAPSHOT_VERSION, - "description": "Wheels CFML MVC framework - bleeding-edge channel (develop snapshots).", - "homepage": "https://wheels.dev", - "license": "Apache-2.0", - "depends": "java/openjdk21", - "notes": [ - "Bleeding-edge channel: tracks every merge to develop on wheels-dev/wheels.", - "Conflicts with the stable 'wheels' package - install only one channel at a time.", - "Switch channels with: scoop uninstall wheels-be ; scoop install wheels", - "First run will sync the module and framework into ~/.wheels." - ], - "architecture": { - "64bit": { - "url": [ - f"{base_release}/wheels-module-{SNAPSHOT_VERSION}.zip", - f"{base_release}/wheels-core-{SNAPSHOT_VERSION}.zip", - lucli_url, - sqlite_url, - ], - "hash": [ - f"sha512:{SNAPSHOT_MODULE_SHA512}", - f"sha512:{SNAPSHOT_CORE_SHA512}", - f"sha512:{LUCLI_SHA512}", - f"sha512:{SQLITE_JDBC_SHA512}", - ], - "extract_dir": ["", "wheels", "", ""], - "extract_to": ["share/module", "share/framework/wheels", "", ""], - } - }, - "bin": [["wheels.cmd", "wheels"]], - "pre_install": build_pre_install("bleeding-edge"), - "checkver": { - "url": "https://api.github.com/repos/wheels-dev/wheels-snapshots/releases?per_page=1", - "jsonpath": "$[0].tag_name", - "regex": "v([\\d.]+-snapshot\\.\\d+)", - }, - "autoupdate": { - "architecture": { - "64bit": { - "url": [ - "https://github.com/wheels-dev/wheels-snapshots/releases/download/v$version/wheels-module-$version.zip", - "https://github.com/wheels-dev/wheels-snapshots/releases/download/v$version/wheels-core-$version.zip", - lucli_url, - sqlite_url, - ], - "hash": [ - {"url": "$url.sha512"}, - {"url": "$url.sha512"}, - f"sha512:{LUCLI_SHA512}", - f"sha512:{SQLITE_JDBC_SHA512}", - ], - } - } - }, - } - - -def manifest_stable() -> dict: - """Stable channel - tracks wheels-dev/wheels GA tags.""" - base_release = f"https://github.com/wheels-dev/wheels/releases/download/v{STABLE_VERSION_PLACEHOLDER}" - lucli_url = f"https://github.com/cybersonic/LuCLI/releases/download/v{LUCLI_VERSION}/lucli-{LUCLI_VERSION}.bat" - sqlite_url = f"https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/{SQLITE_JDBC_VERSION}/sqlite-jdbc-{SQLITE_JDBC_VERSION}.jar" - - return { - "##": "Stable channel - tracks wheels-dev/wheels GA tags. The two zero-filled hashes", - "##2": "below will be populated by Scoop's autoupdate after the first GA tag is", - "##3": "published. Pre-GA, the manifest is install-blocked by hash mismatch by design.", - "version": STABLE_VERSION_PLACEHOLDER, - "description": "Wheels CFML MVC framework - stable channel.", - "homepage": "https://wheels.dev", - "license": "Apache-2.0", - "depends": "java/openjdk21", - "notes": [ - "Stable channel: tracks GA releases of Wheels.", - "Conflicts with 'wheels-be' (bleeding-edge) - install only one channel at a time.", - "Switch channels with: scoop uninstall wheels ; scoop install wheels-be", - "First run will sync the module and framework into ~/.wheels." - ], - "architecture": { - "64bit": { - "url": [ - f"{base_release}/wheels-module-{STABLE_VERSION_PLACEHOLDER}.zip", - f"{base_release}/wheels-core-{STABLE_VERSION_PLACEHOLDER}.zip", - lucli_url, - sqlite_url, - ], - "hash": [ - f"sha512:{STABLE_HASH_PLACEHOLDER}", - f"sha512:{STABLE_HASH_PLACEHOLDER}", - f"sha512:{LUCLI_SHA512}", - f"sha512:{SQLITE_JDBC_SHA512}", - ], - "extract_dir": ["", "wheels", "", ""], - "extract_to": ["share/module", "share/framework/wheels", "", ""], - } - }, - "bin": [["wheels.cmd", "wheels"]], - "pre_install": build_pre_install("stable"), - "checkver": {"github": "https://github.com/wheels-dev/wheels"}, - "autoupdate": { - "architecture": { - "64bit": { - "url": [ - "https://github.com/wheels-dev/wheels/releases/download/v$version/wheels-module-$version.zip", - "https://github.com/wheels-dev/wheels/releases/download/v$version/wheels-core-$version.zip", - lucli_url, - sqlite_url, - ], - "hash": [ - {"url": "$url.sha512"}, - {"url": "$url.sha512"}, - f"sha512:{LUCLI_SHA512}", - f"sha512:{SQLITE_JDBC_SHA512}", - ], - } - } - }, - } - - -def serialize(data: dict) -> str: - return json.dumps(data, indent=4) + "\n" - - -def write_manifest(name: str, data: dict) -> bool: - """Write manifest to disk. Returns True if file changed.""" - out = OUT / name - new = serialize(data) - old = out.read_text() if out.exists() else "" - if old == new: - print(f"unchanged: {out.name}") - return False - out.write_text(new) - print(f"wrote: {out.name} ({out.stat().st_size} bytes)") - return True - - -def check_manifest(name: str, data: dict) -> bool: - """Return True if regen would change the file.""" - out = OUT / name - new = serialize(data) - old = out.read_text() if out.exists() else "" - if old == new: - return False - print(f"DRIFT: {out.name} would change. Run build-manifests.py without --check.") - return True - - -def main() -> None: - check_mode = "--check" in sys.argv - manifests = [ - ("wheels-be.json", manifest_be()), - ("wheels.json", manifest_stable()), - ] - if check_mode: - # Materialize the list before any() so every check_manifest() runs and emits - # its DRIFT log line. any() short-circuits on generators, which would skip - # the second manifest whenever the first one drifts. CI needs to see *all* - # drifting manifests in one run. The named binding also sidesteps ruff - # `any(comprehension)` warnings without obscuring intent. - results = [check_manifest(n, d) for n, d in manifests] - drift = any(results) - sys.exit(1 if drift else 0) - for n, d in manifests: - write_manifest(n, d) - - -if __name__ == "__main__": - main() diff --git a/tools/distribution-drafts/scoop/validate.py b/tools/distribution-drafts/scoop/validate.py deleted file mode 100644 index 3e231fb9ad..0000000000 --- a/tools/distribution-drafts/scoop/validate.py +++ /dev/null @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -""" -Static validation for the Scoop manifest drafts. Runs without a Windows -machine - catches the regressions that would otherwise only surface on a -real `scoop install` attempt. - -Checks: -- JSON parses -- Required Scoop fields exist (version, description, license, architecture) -- url / hash / extract_to / extract_dir arrays are same length per arch -- All URLs are reachable (HEAD request, redirects allowed) -- Embedded wheels.cmd contents look like valid CMD (balanced labels, no - unescaped pipes outside echo lines, no embedded NUL) -- The CMD wrapper references LUCLI_VERSION and SQLITE_JDBC_VERSION constants - that match the URL paths (catches "bumped the URL but not the wrapper") -- Mutual exclusion: both manifests use the same `bin` shim name - -Exit code 0 if everything passes, 1 otherwise. -""" - -from __future__ import annotations - -import json -import re -import sys -import urllib.request -import urllib.error -from pathlib import Path -from typing import Iterable - -HERE = Path(__file__).parent -REQUIRED_TOP_FIELDS = ("version", "description", "homepage", "license", "architecture", "bin") -ERRORS: list[str] = [] - - -def fail(msg: str) -> None: - ERRORS.append(msg) - print(f"FAIL: {msg}") - - -def warn(msg: str) -> None: - print(f"WARN: {msg}") - - -def info(msg: str) -> None: - print(f"ok: {msg}") - - -def extract_cmd_lines(manifest: dict) -> list[str]: - """Pull the literal CMD lines back out of the pre_install array.""" - cmd_lines: list[str] = [] - pattern = re.compile(r"^\$lines\.Add\('(.*)'\)$") - for stmt in manifest.get("pre_install", []): - m = pattern.match(stmt) - if m: - # PowerShell single-quote escape: '' -> ' - cmd_lines.append(m.group(1).replace("''", "'")) - return cmd_lines - - -def check_required_fields(name: str, m: dict) -> None: - for field in REQUIRED_TOP_FIELDS: - if field not in m: - fail(f"{name}: missing required top-level field '{field}'") - else: - info(f"{name}: has '{field}'") - - -def check_arch_arrays(name: str, m: dict) -> None: - arch = m.get("architecture", {}).get("64bit", {}) - urls = arch.get("url", []) - hashes = arch.get("hash", []) - extract_to = arch.get("extract_to", []) - extract_dir = arch.get("extract_dir", []) - - n = len(urls) - if n != len(hashes): - fail(f"{name}: url[{n}] vs hash[{len(hashes)}] length mismatch") - if extract_to and len(extract_to) != n: - fail(f"{name}: url[{n}] vs extract_to[{len(extract_to)}] length mismatch") - if extract_dir and len(extract_dir) != n: - fail(f"{name}: url[{n}] vs extract_dir[{len(extract_dir)}] length mismatch") - if n == len(hashes) == len(extract_to) == len(extract_dir): - info(f"{name}: arch arrays consistent ({n} entries)") - - -def check_url_reachable(url: str, name: str) -> None: - """HEAD the URL. Treat 200-399 as pass, anything else as fail.""" - req = urllib.request.Request(url, method="HEAD", headers={"User-Agent": "wheels-scoop-validator/1.0"}) - try: - with urllib.request.urlopen(req, timeout=15) as resp: - code = resp.getcode() - if 200 <= code < 400: - info(f"{name}: HEAD {url[:80]}... -> {code}") - else: - fail(f"{name}: HEAD {url} returned {code}") - except urllib.error.HTTPError as e: - # GitHub release URLs sometimes 302 to S3; HTTPError 302 is not an error here - if e.code in (301, 302, 307, 308): - info(f"{name}: HEAD {url[:80]}... -> {e.code} (redirect, ok)") - else: - fail(f"{name}: HEAD {url} returned {e.code}") - except (urllib.error.URLError, TimeoutError) as e: - fail(f"{name}: HEAD {url} unreachable: {e}") - - -def check_wrapper(name: str, m: dict) -> None: - cmd_lines = extract_cmd_lines(m) - if not cmd_lines: - fail(f"{name}: pre_install emits no CMD wrapper lines") - return - - joined = "\n".join(cmd_lines) - - # Labels must be defined (lines starting with ':') - referenced_labels = set(re.findall(r"goto :(\w+)", joined)) - defined_labels = set(re.findall(r"^:(\w+)\b", joined, re.MULTILINE)) - missing = referenced_labels - defined_labels - if missing: - fail(f"{name}: wrapper references undefined labels: {sorted(missing)}") - else: - info(f"{name}: wrapper labels resolve ({sorted(defined_labels)})") - - # Wrapper must reference the LuCLI version we pin - urls = m["architecture"]["64bit"]["url"] - lucli_url = next((u for u in urls if "LuCLI/releases" in u), None) - if lucli_url: - lucli_match = re.search(r"lucli-([\d.]+)\.bat", lucli_url) - if lucli_match: - ver = lucli_match.group(1) - if f"lucli-{ver}.bat" not in joined: - fail(f"{name}: wrapper does not call lucli-{ver}.bat (URL pins v{ver}); pin mismatch") - else: - info(f"{name}: wrapper calls lucli-{ver}.bat consistently with URL") - - # Wrapper must reference the sqlite-jdbc version we pin - sqlite_url = next((u for u in urls if "sqlite-jdbc" in u), None) - if sqlite_url: - sqlite_match = re.search(r"sqlite-jdbc-([\d.]+)\.jar", sqlite_url) - if sqlite_match: - ver = sqlite_match.group(1) - if f"sqlite-jdbc-{ver}.jar" not in joined: - fail(f"{name}: wrapper does not reference sqlite-jdbc-{ver}.jar (URL pins v{ver}); pin mismatch") - else: - info(f"{name}: wrapper references sqlite-jdbc-{ver}.jar consistently with URL") - - # No embedded NUL or non-ASCII garbage - if any(ord(c) > 127 for c in joined): - fail(f"{name}: wrapper contains non-ASCII characters (CMD codepage hazard)") - else: - info(f"{name}: wrapper is pure ASCII") - - -def check_bin_shim_collision(manifests: dict[str, dict]) -> None: - """Both manifests should declare the same shim name - that's how we enforce - mutual exclusion without an explicit conflicts_with field.""" - shims = {} - for name, m in manifests.items(): - for entry in m.get("bin", []): - if isinstance(entry, list) and len(entry) >= 2: - shims.setdefault(entry[1], []).append(name) - for shim, owners in shims.items(): - if len(owners) > 1: - info(f"shim '{shim}' declared by {owners} -> mutual exclusion enforced") - else: - warn(f"shim '{shim}' only declared by {owners[0]}; no mutual exclusion") - - -def check_channel_tag(name: str, m: dict, expected: str) -> None: - cmd_lines = extract_cmd_lines(m) - joined = "\n".join(cmd_lines) - if f"({expected})" not in joined: - fail(f"{name}: wrapper version banner missing channel tag '({expected})'") - else: - info(f"{name}: wrapper banner tags channel as '{expected}'") - - -def main() -> int: - online = "--offline" not in sys.argv - manifests: dict[str, dict] = {} - - for path in (HERE / "wheels.json", HERE / "wheels-be.json"): - try: - data = json.loads(path.read_text()) - except json.JSONDecodeError as e: - fail(f"{path.name}: invalid JSON: {e}") - continue - info(f"{path.name}: parses as JSON") - manifests[path.name] = data - check_required_fields(path.name, data) - check_arch_arrays(path.name, data) - check_wrapper(path.name, data) - - if "wheels-be.json" in manifests: - check_channel_tag("wheels-be.json", manifests["wheels-be.json"], "bleeding-edge") - if "wheels.json" in manifests: - check_channel_tag("wheels.json", manifests["wheels.json"], "stable") - - check_bin_shim_collision(manifests) - - if online: - print("\n--- HTTP HEAD checks (use --offline to skip) ---") - for name, m in manifests.items(): - # Skip URLs that we know are placeholder-paired (zero-hash stable - # pre-GA URLs would 404 on wheels-module-4.0.0.zip until GA) - stable_zero_hashes = { - "sha512:" + "0" * 128, - } - urls = m["architecture"]["64bit"]["url"] - hashes = m["architecture"]["64bit"]["hash"] - for u, h in zip(urls, hashes): - if h in stable_zero_hashes: - warn(f"{name}: skipping HEAD on {u[:60]}... (placeholder hash, pre-GA)") - continue - check_url_reachable(u, name) - - print() - if ERRORS: - print(f"VALIDATION FAILED ({len(ERRORS)} issues)") - for e in ERRORS: - print(f" - {e}") - return 1 - print("VALIDATION PASSED") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/distribution-drafts/scoop/wheels-be.json b/tools/distribution-drafts/scoop/wheels-be.json deleted file mode 100644 index 52ab6bfea2..0000000000 --- a/tools/distribution-drafts/scoop/wheels-be.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "version": "4.0.0-snapshot.1789", - "description": "Wheels CFML MVC framework - bleeding-edge channel (develop snapshots).", - "homepage": "https://wheels.dev", - "license": "Apache-2.0", - "depends": "java/openjdk21", - "notes": [ - "Bleeding-edge channel: tracks every merge to develop on wheels-dev/wheels.", - "Conflicts with the stable 'wheels' package - install only one channel at a time.", - "Switch channels with: scoop uninstall wheels-be ; scoop install wheels", - "First run will sync the module and framework into ~/.wheels." - ], - "architecture": { - "64bit": { - "url": [ - "https://github.com/wheels-dev/wheels-snapshots/releases/download/v4.0.0-snapshot.1789/wheels-module-4.0.0-snapshot.1789.zip", - "https://github.com/wheels-dev/wheels-snapshots/releases/download/v4.0.0-snapshot.1789/wheels-core-4.0.0-snapshot.1789.zip", - "https://github.com/cybersonic/LuCLI/releases/download/v0.3.7/lucli-0.3.7.bat", - "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.49.1.0/sqlite-jdbc-3.49.1.0.jar" - ], - "hash": [ - "sha512:73b37b01a82ef5abe36c4f02f1aa8870531ac2d6a867ff6482895b6d01dacb068a07af19ec51434ca2caf0b1f8de1437ed5919183f6f0077ef3cd5da7e074be9", - "sha512:fa492a87fdf5ba4153ce24aa216fdda442c2bc39ed256a3348029cfeb74950e7bf8fbc533d7497869287bb9f843c191a9e3cf8703aa4a2fb50bde0db771141b7", - "sha512:75c948319b333d2e9d653d4986e766463f3f29062f62c364ccde2288e5f295bf65a857d54eda2e888cd5a80c2bd9fb727e016f4fca05fc42e56ee219225dd71b", - "sha512:90b3f6aed150f611fcb9454dfda5fbb9d7faad369937fa8718ac8813c45eb6f0430e6014b7b4c94b4b63e404ade68e83126571f94216de7bf6d2947f1c642803" - ], - "extract_dir": [ - "", - "wheels", - "", - "" - ], - "extract_to": [ - "share/module", - "share/framework/wheels", - "", - "" - ] - } - }, - "bin": [ - [ - "wheels.cmd", - "wheels" - ] - ], - "pre_install": [ - "$lines = New-Object System.Collections.Generic.List[string]", - "$lines.Add('@echo off')", - "$lines.Add('setlocal enabledelayedexpansion')", - "$lines.Add('set \"LUCLI_HOME=%USERPROFILE%\\.wheels\"')", - "$lines.Add('set \"MOD_VER_SRC=%~dp0share\\module\\.module-version\"')", - "$lines.Add('set \"MOD_VER_DST=%LUCLI_HOME%\\modules\\wheels\\.module-version\"')", - "$lines.Add('set \"SQLITE_SRC=%~dp0sqlite-jdbc-3.49.1.0.jar\"')", - "$lines.Add('')", - "$lines.Add('if \"%~1\"==\"--version\" goto :show_version')", - "$lines.Add('if \"%~1\"==\"-v\" goto :show_version')", - "$lines.Add('if \"%~1\"==\"--help\" goto :show_help')", - "$lines.Add('if \"%~1\"==\"-h\" goto :show_help')", - "$lines.Add('')", - "$lines.Add(':: First-time module sync -- copies module + framework into ~/.wheels if missing or version-mismatched.')", - "$lines.Add(':: Mirrors the brew wrapper''s SRC->DST sync; needed because `wheels new` etc. mutate ~/.wheels but')", - "$lines.Add(':: scoop''s install dir must stay pristine for `scoop uninstall` to work cleanly.')", - "$lines.Add('set \"WHEELS_MOD_DST=%LUCLI_HOME%\\modules\\wheels\"')", - "$lines.Add('set \"WHEELS_FRAMEWORK_DST=%WHEELS_MOD_DST%\\vendor\\wheels\"')", - "$lines.Add('set \"WHEELS_MOD_SRC=%~dp0share\\module\"')", - "$lines.Add('set \"WHEELS_FRAMEWORK_SRC=%~dp0share\\framework\\wheels\"')", - "$lines.Add('set \"src_ver=\"')", - "$lines.Add('set \"dst_ver=\"')", - "$lines.Add('if exist \"%MOD_VER_SRC%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_SRC%\") do set \"src_ver=%%V\"')", - "$lines.Add('if exist \"%MOD_VER_DST%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_DST%\") do set \"dst_ver=%%V\"')", - "$lines.Add('if not \"!src_ver!\"==\"!dst_ver!\" (')", - "$lines.Add(' if exist \"%WHEELS_MOD_DST%\" rmdir /S /Q \"%WHEELS_MOD_DST%\" >nul 2>&1')", - "$lines.Add(' mkdir \"%WHEELS_FRAMEWORK_DST%\" >nul 2>&1')", - "$lines.Add(' xcopy /E /I /Y /Q \"%WHEELS_MOD_SRC%\" \"%WHEELS_MOD_DST%\" >nul 2>&1')", - "$lines.Add(' xcopy /E /I /Y /Q \"%WHEELS_FRAMEWORK_SRC%\" \"%WHEELS_FRAMEWORK_DST%\" >nul 2>&1')", - "$lines.Add(')')", - "$lines.Add('')", - "$lines.Add(':: Drop sqlite-jdbc into LuCLI''s extracted express lib/ext on every run (self-heal).')", - "$lines.Add(':: The express dir only exists after the first LuCLI run, so this is a no-op on the very')", - "$lines.Add(':: first invocation and self-heals on every run after.')", - "$lines.Add('if exist \"%SQLITE_SRC%\" (')", - "$lines.Add(' for /d %%D in (\"%LUCLI_HOME%\\express\\*\") do (')", - "$lines.Add(' if exist \"%%D\\lib\\ext\" if not exist \"%%D\\lib\\ext\\sqlite-jdbc-3.49.1.0.jar\" copy /Y \"%SQLITE_SRC%\" \"%%D\\lib\\ext\\\" >nul 2>&1')", - "$lines.Add(' )')", - "$lines.Add(')')", - "$lines.Add('')", - "$lines.Add(':: Resolve JAVA_HOME from the openjdk21 dependency declared via `depends: java/openjdk21`.')", - "$lines.Add(':: The wrapper invokes java.exe directly (not `call lucli-.bat`) to bypass cmd.exe''s')", - "$lines.Add(':: bat-file pre-parser, which trips on bytes in the lucli bat-jar''s ZIP tail and aborts')", - "$lines.Add(':: the script with ERROR_INVALID_NAME on at least Windows 11 10.0.26200.8457 (issue #2765).')", - "$lines.Add('if not defined JAVA_HOME (')", - "$lines.Add(' if defined SCOOP if exist \"%SCOOP%\\apps\\openjdk21\\current\\bin\\java.exe\" set \"JAVA_HOME=%SCOOP%\\apps\\openjdk21\\current\"')", - "$lines.Add(')')", - "$lines.Add('if not defined JAVA_HOME (')", - "$lines.Add(' for %%I in (\"%~dp0..\\..\\openjdk21\\current\") do if exist \"%%~fI\\bin\\java.exe\" set \"JAVA_HOME=%%~fI\"')", - "$lines.Add(')')", - "$lines.Add('if not defined JAVA_HOME (')", - "$lines.Add(' echo Wheels CLI: cannot resolve JAVA_HOME. Install Java with: scoop install java/openjdk21 1>&2')", - "$lines.Add(' exit /b 1')", - "$lines.Add(')')", - "$lines.Add('')", - "$lines.Add(':: `wheels deploy ...` arg rewrite (issue #2674). picocli absorbs --version')", - "$lines.Add(':: as a root-level flag even after a subcommand, so the documented Kamal form')", - "$lines.Add(':: `wheels deploy --version=v1.2.3` blows up before Module.cfc runs. Rewrite to')", - "$lines.Add(':: --release here; Module.cfc accepts both flags.')", - "$lines.Add('if /I \"%~1\"==\"deploy\" goto :deploy_rewrite')", - "$lines.Add('')", - "$lines.Add('\"%JAVA_HOME%\\bin\\java.exe\" -client -jar \"%~dp0lucli-0.3.7.bat\" %*')", - "$lines.Add('exit /b %ERRORLEVEL%')", - "$lines.Add('')", - "$lines.Add(':deploy_rewrite')", - "$lines.Add('set \"WHEELS_DEPLOY_ARGS=deploy\"')", - "$lines.Add('shift')", - "$lines.Add(':deploy_arg_loop')", - "$lines.Add('if \"%~1\"==\"\" goto :deploy_dispatch')", - "$lines.Add('set \"ARG=%~1\"')", - "$lines.Add('if \"!ARG!\"==\"--version\" (')", - "$lines.Add(' set \"WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! --release\"')", - "$lines.Add(') else if \"!ARG:~0,10!\"==\"--version=\" (')", - "$lines.Add(' set \"WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! --release=!ARG:~10!\"')", - "$lines.Add(') else (')", - "$lines.Add(' set \"WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! %~1\"')", - "$lines.Add(')')", - "$lines.Add('shift')", - "$lines.Add('goto :deploy_arg_loop')", - "$lines.Add(':deploy_dispatch')", - "$lines.Add('\"%JAVA_HOME%\\bin\\java.exe\" -client -jar \"%~dp0lucli-0.3.7.bat\" !WHEELS_DEPLOY_ARGS!')", - "$lines.Add('exit /b %ERRORLEVEL%')", - "$lines.Add('')", - "$lines.Add(':show_version')", - "$lines.Add('set \"ver=unknown\"')", - "$lines.Add('if exist \"%MOD_VER_DST%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_DST%\") do set \"ver=%%V\"')", - "$lines.Add('if \"!ver!\"==\"unknown\" if exist \"%MOD_VER_SRC%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_SRC%\") do set \"ver=%%V\"')", - "$lines.Add('echo Wheels Version: !ver! (bleeding-edge)')", - "$lines.Add('echo.')", - "$lines.Add('echo __ ___ _ ')", - "$lines.Add('echo \\ \\ / / ^|__ ___ ___^| ^|___')", - "$lines.Add('echo \\ \\ /\\ / /^| ''_ \\ / _ \\/ _ \\ / __^|')", - "$lines.Add('echo \\ V V / ^| ^| ^| ^| __/ __/ \\__ \\ ')", - "$lines.Add('echo \\_/\\_/ ^|_^| ^|_^|\\___\\___^|_^|___/')", - "$lines.Add('echo.')", - "$lines.Add('echo https://wheels.dev')", - "$lines.Add('exit /b 0')", - "$lines.Add('')", - "$lines.Add(':show_help')", - "$lines.Add('set \"ver=unknown\"')", - "$lines.Add('if exist \"%MOD_VER_DST%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_DST%\") do set \"ver=%%V\"')", - "$lines.Add('if \"!ver!\"==\"unknown\" if exist \"%MOD_VER_SRC%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_SRC%\") do set \"ver=%%V\"')", - "$lines.Add('echo Wheels CLI !ver! (bleeding-edge)')", - "$lines.Add('echo CFML MVC framework - code generation, migrations, testing, server management')", - "$lines.Add('echo.')", - "$lines.Add('echo Usage:')", - "$lines.Add('echo wheels ^ [options]')", - "$lines.Add('echo.')", - "$lines.Add('echo For full command reference: wheels ^ --help')", - "$lines.Add('echo More info: https://guides.wheels.dev')", - "$lines.Add('exit /b 0')", - "Set-Content -Path \"$dir\\wheels.cmd\" -Value $lines -Encoding ASCII" - ], - "checkver": { - "url": "https://api.github.com/repos/wheels-dev/wheels-snapshots/releases?per_page=1", - "jsonpath": "$[0].tag_name", - "regex": "v([\\d.]+-snapshot\\.\\d+)" - }, - "autoupdate": { - "architecture": { - "64bit": { - "url": [ - "https://github.com/wheels-dev/wheels-snapshots/releases/download/v$version/wheels-module-$version.zip", - "https://github.com/wheels-dev/wheels-snapshots/releases/download/v$version/wheels-core-$version.zip", - "https://github.com/cybersonic/LuCLI/releases/download/v0.3.7/lucli-0.3.7.bat", - "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.49.1.0/sqlite-jdbc-3.49.1.0.jar" - ], - "hash": [ - { - "url": "$url.sha512" - }, - { - "url": "$url.sha512" - }, - "sha512:75c948319b333d2e9d653d4986e766463f3f29062f62c364ccde2288e5f295bf65a857d54eda2e888cd5a80c2bd9fb727e016f4fca05fc42e56ee219225dd71b", - "sha512:90b3f6aed150f611fcb9454dfda5fbb9d7faad369937fa8718ac8813c45eb6f0430e6014b7b4c94b4b63e404ade68e83126571f94216de7bf6d2947f1c642803" - ] - } - } - } -} diff --git a/tools/distribution-drafts/scoop/wheels.json b/tools/distribution-drafts/scoop/wheels.json deleted file mode 100644 index bb611686a9..0000000000 --- a/tools/distribution-drafts/scoop/wheels.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "##": "Stable channel - tracks wheels-dev/wheels GA tags. The two zero-filled hashes", - "##2": "below will be populated by Scoop's autoupdate after the first GA tag is", - "##3": "published. Pre-GA, the manifest is install-blocked by hash mismatch by design.", - "version": "4.0.0", - "description": "Wheels CFML MVC framework - stable channel.", - "homepage": "https://wheels.dev", - "license": "Apache-2.0", - "depends": "java/openjdk21", - "notes": [ - "Stable channel: tracks GA releases of Wheels.", - "Conflicts with 'wheels-be' (bleeding-edge) - install only one channel at a time.", - "Switch channels with: scoop uninstall wheels ; scoop install wheels-be", - "First run will sync the module and framework into ~/.wheels." - ], - "architecture": { - "64bit": { - "url": [ - "https://github.com/wheels-dev/wheels/releases/download/v4.0.0/wheels-module-4.0.0.zip", - "https://github.com/wheels-dev/wheels/releases/download/v4.0.0/wheels-core-4.0.0.zip", - "https://github.com/cybersonic/LuCLI/releases/download/v0.3.7/lucli-0.3.7.bat", - "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.49.1.0/sqlite-jdbc-3.49.1.0.jar" - ], - "hash": [ - "sha512:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "sha512:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "sha512:75c948319b333d2e9d653d4986e766463f3f29062f62c364ccde2288e5f295bf65a857d54eda2e888cd5a80c2bd9fb727e016f4fca05fc42e56ee219225dd71b", - "sha512:90b3f6aed150f611fcb9454dfda5fbb9d7faad369937fa8718ac8813c45eb6f0430e6014b7b4c94b4b63e404ade68e83126571f94216de7bf6d2947f1c642803" - ], - "extract_dir": [ - "", - "wheels", - "", - "" - ], - "extract_to": [ - "share/module", - "share/framework/wheels", - "", - "" - ] - } - }, - "bin": [ - [ - "wheels.cmd", - "wheels" - ] - ], - "pre_install": [ - "$lines = New-Object System.Collections.Generic.List[string]", - "$lines.Add('@echo off')", - "$lines.Add('setlocal enabledelayedexpansion')", - "$lines.Add('set \"LUCLI_HOME=%USERPROFILE%\\.wheels\"')", - "$lines.Add('set \"MOD_VER_SRC=%~dp0share\\module\\.module-version\"')", - "$lines.Add('set \"MOD_VER_DST=%LUCLI_HOME%\\modules\\wheels\\.module-version\"')", - "$lines.Add('set \"SQLITE_SRC=%~dp0sqlite-jdbc-3.49.1.0.jar\"')", - "$lines.Add('')", - "$lines.Add('if \"%~1\"==\"--version\" goto :show_version')", - "$lines.Add('if \"%~1\"==\"-v\" goto :show_version')", - "$lines.Add('if \"%~1\"==\"--help\" goto :show_help')", - "$lines.Add('if \"%~1\"==\"-h\" goto :show_help')", - "$lines.Add('')", - "$lines.Add(':: First-time module sync -- copies module + framework into ~/.wheels if missing or version-mismatched.')", - "$lines.Add(':: Mirrors the brew wrapper''s SRC->DST sync; needed because `wheels new` etc. mutate ~/.wheels but')", - "$lines.Add(':: scoop''s install dir must stay pristine for `scoop uninstall` to work cleanly.')", - "$lines.Add('set \"WHEELS_MOD_DST=%LUCLI_HOME%\\modules\\wheels\"')", - "$lines.Add('set \"WHEELS_FRAMEWORK_DST=%WHEELS_MOD_DST%\\vendor\\wheels\"')", - "$lines.Add('set \"WHEELS_MOD_SRC=%~dp0share\\module\"')", - "$lines.Add('set \"WHEELS_FRAMEWORK_SRC=%~dp0share\\framework\\wheels\"')", - "$lines.Add('set \"src_ver=\"')", - "$lines.Add('set \"dst_ver=\"')", - "$lines.Add('if exist \"%MOD_VER_SRC%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_SRC%\") do set \"src_ver=%%V\"')", - "$lines.Add('if exist \"%MOD_VER_DST%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_DST%\") do set \"dst_ver=%%V\"')", - "$lines.Add('if not \"!src_ver!\"==\"!dst_ver!\" (')", - "$lines.Add(' if exist \"%WHEELS_MOD_DST%\" rmdir /S /Q \"%WHEELS_MOD_DST%\" >nul 2>&1')", - "$lines.Add(' mkdir \"%WHEELS_FRAMEWORK_DST%\" >nul 2>&1')", - "$lines.Add(' xcopy /E /I /Y /Q \"%WHEELS_MOD_SRC%\" \"%WHEELS_MOD_DST%\" >nul 2>&1')", - "$lines.Add(' xcopy /E /I /Y /Q \"%WHEELS_FRAMEWORK_SRC%\" \"%WHEELS_FRAMEWORK_DST%\" >nul 2>&1')", - "$lines.Add(')')", - "$lines.Add('')", - "$lines.Add(':: Drop sqlite-jdbc into LuCLI''s extracted express lib/ext on every run (self-heal).')", - "$lines.Add(':: The express dir only exists after the first LuCLI run, so this is a no-op on the very')", - "$lines.Add(':: first invocation and self-heals on every run after.')", - "$lines.Add('if exist \"%SQLITE_SRC%\" (')", - "$lines.Add(' for /d %%D in (\"%LUCLI_HOME%\\express\\*\") do (')", - "$lines.Add(' if exist \"%%D\\lib\\ext\" if not exist \"%%D\\lib\\ext\\sqlite-jdbc-3.49.1.0.jar\" copy /Y \"%SQLITE_SRC%\" \"%%D\\lib\\ext\\\" >nul 2>&1')", - "$lines.Add(' )')", - "$lines.Add(')')", - "$lines.Add('')", - "$lines.Add(':: Resolve JAVA_HOME from the openjdk21 dependency declared via `depends: java/openjdk21`.')", - "$lines.Add(':: The wrapper invokes java.exe directly (not `call lucli-.bat`) to bypass cmd.exe''s')", - "$lines.Add(':: bat-file pre-parser, which trips on bytes in the lucli bat-jar''s ZIP tail and aborts')", - "$lines.Add(':: the script with ERROR_INVALID_NAME on at least Windows 11 10.0.26200.8457 (issue #2765).')", - "$lines.Add('if not defined JAVA_HOME (')", - "$lines.Add(' if defined SCOOP if exist \"%SCOOP%\\apps\\openjdk21\\current\\bin\\java.exe\" set \"JAVA_HOME=%SCOOP%\\apps\\openjdk21\\current\"')", - "$lines.Add(')')", - "$lines.Add('if not defined JAVA_HOME (')", - "$lines.Add(' for %%I in (\"%~dp0..\\..\\openjdk21\\current\") do if exist \"%%~fI\\bin\\java.exe\" set \"JAVA_HOME=%%~fI\"')", - "$lines.Add(')')", - "$lines.Add('if not defined JAVA_HOME (')", - "$lines.Add(' echo Wheels CLI: cannot resolve JAVA_HOME. Install Java with: scoop install java/openjdk21 1>&2')", - "$lines.Add(' exit /b 1')", - "$lines.Add(')')", - "$lines.Add('')", - "$lines.Add(':: `wheels deploy ...` arg rewrite (issue #2674). picocli absorbs --version')", - "$lines.Add(':: as a root-level flag even after a subcommand, so the documented Kamal form')", - "$lines.Add(':: `wheels deploy --version=v1.2.3` blows up before Module.cfc runs. Rewrite to')", - "$lines.Add(':: --release here; Module.cfc accepts both flags.')", - "$lines.Add('if /I \"%~1\"==\"deploy\" goto :deploy_rewrite')", - "$lines.Add('')", - "$lines.Add('\"%JAVA_HOME%\\bin\\java.exe\" -client -jar \"%~dp0lucli-0.3.7.bat\" %*')", - "$lines.Add('exit /b %ERRORLEVEL%')", - "$lines.Add('')", - "$lines.Add(':deploy_rewrite')", - "$lines.Add('set \"WHEELS_DEPLOY_ARGS=deploy\"')", - "$lines.Add('shift')", - "$lines.Add(':deploy_arg_loop')", - "$lines.Add('if \"%~1\"==\"\" goto :deploy_dispatch')", - "$lines.Add('set \"ARG=%~1\"')", - "$lines.Add('if \"!ARG!\"==\"--version\" (')", - "$lines.Add(' set \"WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! --release\"')", - "$lines.Add(') else if \"!ARG:~0,10!\"==\"--version=\" (')", - "$lines.Add(' set \"WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! --release=!ARG:~10!\"')", - "$lines.Add(') else (')", - "$lines.Add(' set \"WHEELS_DEPLOY_ARGS=!WHEELS_DEPLOY_ARGS! %~1\"')", - "$lines.Add(')')", - "$lines.Add('shift')", - "$lines.Add('goto :deploy_arg_loop')", - "$lines.Add(':deploy_dispatch')", - "$lines.Add('\"%JAVA_HOME%\\bin\\java.exe\" -client -jar \"%~dp0lucli-0.3.7.bat\" !WHEELS_DEPLOY_ARGS!')", - "$lines.Add('exit /b %ERRORLEVEL%')", - "$lines.Add('')", - "$lines.Add(':show_version')", - "$lines.Add('set \"ver=unknown\"')", - "$lines.Add('if exist \"%MOD_VER_DST%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_DST%\") do set \"ver=%%V\"')", - "$lines.Add('if \"!ver!\"==\"unknown\" if exist \"%MOD_VER_SRC%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_SRC%\") do set \"ver=%%V\"')", - "$lines.Add('echo Wheels Version: !ver! (stable)')", - "$lines.Add('echo.')", - "$lines.Add('echo __ ___ _ ')", - "$lines.Add('echo \\ \\ / / ^|__ ___ ___^| ^|___')", - "$lines.Add('echo \\ \\ /\\ / /^| ''_ \\ / _ \\/ _ \\ / __^|')", - "$lines.Add('echo \\ V V / ^| ^| ^| ^| __/ __/ \\__ \\ ')", - "$lines.Add('echo \\_/\\_/ ^|_^| ^|_^|\\___\\___^|_^|___/')", - "$lines.Add('echo.')", - "$lines.Add('echo https://wheels.dev')", - "$lines.Add('exit /b 0')", - "$lines.Add('')", - "$lines.Add(':show_help')", - "$lines.Add('set \"ver=unknown\"')", - "$lines.Add('if exist \"%MOD_VER_DST%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_DST%\") do set \"ver=%%V\"')", - "$lines.Add('if \"!ver!\"==\"unknown\" if exist \"%MOD_VER_SRC%\" for /f \"usebackq delims=\" %%V in (\"%MOD_VER_SRC%\") do set \"ver=%%V\"')", - "$lines.Add('echo Wheels CLI !ver! (stable)')", - "$lines.Add('echo CFML MVC framework - code generation, migrations, testing, server management')", - "$lines.Add('echo.')", - "$lines.Add('echo Usage:')", - "$lines.Add('echo wheels ^ [options]')", - "$lines.Add('echo.')", - "$lines.Add('echo For full command reference: wheels ^ --help')", - "$lines.Add('echo More info: https://guides.wheels.dev')", - "$lines.Add('exit /b 0')", - "Set-Content -Path \"$dir\\wheels.cmd\" -Value $lines -Encoding ASCII" - ], - "checkver": { - "github": "https://github.com/wheels-dev/wheels" - }, - "autoupdate": { - "architecture": { - "64bit": { - "url": [ - "https://github.com/wheels-dev/wheels/releases/download/v$version/wheels-module-$version.zip", - "https://github.com/wheels-dev/wheels/releases/download/v$version/wheels-core-$version.zip", - "https://github.com/cybersonic/LuCLI/releases/download/v0.3.7/lucli-0.3.7.bat", - "https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.49.1.0/sqlite-jdbc-3.49.1.0.jar" - ], - "hash": [ - { - "url": "$url.sha512" - }, - { - "url": "$url.sha512" - }, - "sha512:75c948319b333d2e9d653d4986e766463f3f29062f62c364ccde2288e5f295bf65a857d54eda2e888cd5a80c2bd9fb727e016f4fca05fc42e56ee219225dd71b", - "sha512:90b3f6aed150f611fcb9454dfda5fbb9d7faad369937fa8718ac8813c45eb6f0430e6014b7b4c94b4b63e404ade68e83126571f94216de7bf6d2947f1c642803" - ] - } - } - } -} diff --git a/vendor/wheels/tests/specs/cli/ScoopWrapperSpec.cfc b/vendor/wheels/tests/specs/cli/ScoopWrapperSpec.cfc deleted file mode 100644 index c04a530caf..0000000000 --- a/vendor/wheels/tests/specs/cli/ScoopWrapperSpec.cfc +++ /dev/null @@ -1,154 +0,0 @@ -component extends="wheels.WheelsTest" { - - // Regression: the Scoop-installed wheels.cmd shipped on at least one - // real Windows 11 build (10.0.26200.8457) failed on every invocation - // with two compounding bugs, both reported in issue ##2765. - // - // Bug 1 -- the wrapper set `JAVA_HOME=%~dp0share\jdk`, a path Scoop - // never produces. A Scoop install only populates `share\module` and - // `share\framework`; no `share\jdk`. The brew formula resolves - // JAVA_HOME from openjdk@21's opt_prefix (a real path), but the Scoop - // wrapper was written assuming a parallel layout that doesn't exist - // in a Scoop install. That dead assignment was already removed from - // the in-repo template before this fix, but the published bucket - // carried it. - // - // Bug 2 -- the wrapper invoked lucli with - // `call "%~dp0lucli-.bat"`. The lucli-.bat artifact is a - // bat-jar concatenation (small bat preamble + `:JAR_BOUNDARY` + raw - // JAR ZIP bytes, ~915 KB). cmd.exe pre-parses the entire bat file - // for labels/control flow before running it, and on this Windows - // build the pre-parse trips on a byte sequence in the JAR tail with - // `The filename, directory name, or volume label syntax is - // incorrect.` The bat never executes. Bypassing the bat preamble by - // invoking java directly -- - // `"%JAVA_HOME%\bin\java.exe" -client -jar "%~dp0lucli-.bat" %*` - // -- works because java reads the JAR via stream and skips the bat - // preamble in front of the ZIP central directory. - // - // This spec pins both bucket manifests AND the source-of-truth - // build-manifests.py against both regressions, plus the implied - // JAVA_HOME resolver that the direct-java dispatch needs. - - function run() { - - describe("Scoop wrapper (build-manifests.py output)", () => { - - // expandPath("/wheels") resolves to vendor/wheels via the - // configured Lucee mapping; the repo root is two levels above. - var repoRoot = expandPath("/wheels/../.."); - var beManifest = repoRoot & "/tools/distribution-drafts/scoop/wheels-be.json"; - var stableManifest = repoRoot & "/tools/distribution-drafts/scoop/wheels.json"; - var script = repoRoot & "/tools/distribution-drafts/scoop/build-manifests.py"; - - var manifestTargets = [ - {path: beManifest, label: "wheels-be.json (bleeding-edge channel)"}, - {path: stableManifest, label: "wheels.json (stable channel)"} - ]; - - for (var target in manifestTargets) { - // IIFE to capture loop variable for closure binding. - (function(t) { - describe(t.label, () => { - - it("does not dispatch lucli via `call ""%~dp0lucli-.bat""`", () => { - expect(fileExists(t.path)).toBeTrue("Missing file: " & t.path); - var src = fileRead(t.path); - // Both the normal dispatch and the deploy - // arg-rewrite dispatch are subject to the - // cmd.exe bat-jar parser regression. Either - // `call` line is a re-introduction of bug 2. - var hasBatCall = findNoCase("call \""%~dp0lucli-", src) > 0; - expect(hasBatCall).toBeFalse( - t.label & " must not dispatch lucli via `call ""%~dp0lucli-.bat""`. " - & "cmd.exe pre-parses the bat-jar tail and aborts before lucli runs on at " - & "least Windows 11 10.0.26200.8457. Invoke java directly instead. " - & "See issue ##2765." - ); - }); - - it("dispatches lucli via direct `java.exe -client -jar`", () => { - var src = fileRead(t.path); - // Substring match on the JSON-encoded form of - // the wrapper line. The raw CMD line is - // `"%JAVA_HOME%\bin\java.exe" -client -jar "%~dp0lucli-.bat" %*`; - // after PS single-quote wrap and JSON quote - // escape, the file contains the run below. - var hasDirectJava = findNoCase( - "\""%JAVA_HOME%\\bin\\java.exe\"" -client -jar \""%~dp0lucli-", - src - ) > 0; - expect(hasDirectJava).toBeTrue( - t.label & " must invoke lucli via " - & """%JAVA_HOME%\bin\java.exe"" -client -jar ""%~dp0lucli-.bat"" " - & "to bypass cmd.exe's bat-file pre-parser. See issue ##2765." - ); - }); - - it("does not set JAVA_HOME to %~dp0share\jdk", () => { - var src = fileRead(t.path); - // Bug 1: a Scoop install never populates - // share\jdk -- share holds only module and - // framework subdirs. - var hasBrokenJavaHome = findNoCase( - "JAVA_HOME=%~dp0share\\jdk", - src - ) > 0; - expect(hasBrokenJavaHome).toBeFalse( - t.label & " must not set JAVA_HOME=%~dp0share\jdk -- Scoop installs " - & "populate share/module and share/framework only. Resolve JAVA_HOME " - & "from the openjdk21 dependency declared via `depends: java/openjdk21`. " - & "See issue ##2765." - ); - }); - - it("resolves JAVA_HOME from the openjdk21 dependency", () => { - var src = fileRead(t.path); - // The direct-java dispatch above requires - // JAVA_HOME to be set. Scoop installs the - // openjdk21 dependency under - // `%SCOOP%\apps\openjdk21\current` (or the - // sibling `%~dp0..\..\openjdk21\current`). - // Match `openjdk21` inside a `$lines.Add(...)` - // call rather than the bare top-level - // `depends: java/openjdk21` field -- only the - // wrapper-template emission counts. - var hasOpenjdk21InWrapper = reFindNoCase( - "\$lines\.Add\([^)]*openjdk21", - src - ) > 0; - expect(hasOpenjdk21InWrapper).toBeTrue( - t.label & " must resolve JAVA_HOME from Scoop's openjdk21 install " - & "(declared via `depends: java/openjdk21`) inside the wrapper " - & "template, not just as a top-level dependency. Without it, the " - & "direct-java dispatch fails when JAVA_HOME isn't already set. " - & "See issue ##2765." - ); - }); - - }); - })(target); - } - - describe("build-manifests.py (source of truth)", () => { - - it("emits the direct-java dispatch line", () => { - expect(fileExists(script)).toBeTrue("Missing file: " & script); - var src = fileRead(script); - // Source-script + JSON drift would silently - // re-introduce the regression on the next regen. Pin - // both ends. - var hasJavaHomeRef = findNoCase("%JAVA_HOME%", src) > 0; - expect(hasJavaHomeRef).toBeTrue( - "build-manifests.py must reference %JAVA_HOME% in the wrapper template; " - & "otherwise a regen wipes the fix from both JSONs. See issue ##2765." - ); - }); - - }); - - }); - - } - -} diff --git a/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/installation.mdx b/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/installation.mdx index ca429714cb..12ce78beb9 100644 --- a/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/installation.mdx +++ b/web/sites/guides/src/content/docs/v4-0-0/command-line-tools/installation.mdx @@ -123,9 +123,6 @@ Wheels ships on Windows through [Scoop](https://scoop.sh) — a portable, sandbo # the Scoop installer, which is why this works from a totally fresh shell. scoop install git -# The java bucket provides the openjdk21 dependency declared by both packages. -# Scoop's `depends:` does not auto-add the dependency bucket. -scoop bucket add java scoop bucket add wheels https://github.com/wheels-dev/scoop-wheels # Pick a channel: @@ -135,7 +132,7 @@ scoop install wheels-be # bleeding-edge - tracks every develop merge wheels --version ``` -Both packages install OpenJDK 21 as a Scoop dependency (`java/openjdk21`) — the `java` bucket added above is required. The `wheels.cmd` wrapper resolves `JAVA_HOME` from the installed dependency automatically, so no manual setup is needed. Both expose the same `wheels` PATH shim, so Scoop refuses to install both at once. To switch channels: +Both packages bundle OpenJDK 21 inline — no separate `java` bucket, no `JAVA_HOME` setup. Both expose the same `wheels` PATH shim, so Scoop refuses to install both at once. To switch channels: ```powershell scoop uninstall wheels && scoop install wheels-be diff --git a/web/sites/guides/src/content/docs/v4-0-0/start-here/installing.mdx b/web/sites/guides/src/content/docs/v4-0-0/start-here/installing.mdx index 6058981e5f..0d7d99f1ee 100644 --- a/web/sites/guides/src/content/docs/v4-0-0/start-here/installing.mdx +++ b/web/sites/guides/src/content/docs/v4-0-0/start-here/installing.mdx @@ -137,14 +137,13 @@ The legacy `wheels` package on chocolatey.org is the CommandBox-based v1.x relea 3. Add the Wheels bucket and install a channel: ```powershell title="PowerShell" - scoop bucket add java scoop bucket add wheels https://github.com/wheels-dev/scoop-wheels scoop install wheels # stable - tracks v4.0.0 GA tags # OR: scoop install wheels-be # bleeding-edge - tracks every develop merge ``` - Both packages install OpenJDK 21 as a Scoop dependency (`java/openjdk21`) from the `java` bucket added above — no manual `JAVA_HOME` setup needed; the wrapper resolves it automatically. Both expose the same `wheels` shim on PATH, so Scoop refuses to install both at once. See [Release Channels](/v4-0-0/start-here/release-channels/) for the comparison. + Both packages inline OpenJDK 21 — no separate `java` bucket or `JAVA_HOME` setup required. Both expose the same `wheels` shim on PATH, so Scoop refuses to install both at once. See [Release Channels](/v4-0-0/start-here/release-channels/) for the comparison. 4. Verify: diff --git a/web/sites/guides/src/content/docs/v4-0-1-snapshot/command-line-tools/installation.mdx b/web/sites/guides/src/content/docs/v4-0-1-snapshot/command-line-tools/installation.mdx index 2bce428996..13fa6f6bda 100644 --- a/web/sites/guides/src/content/docs/v4-0-1-snapshot/command-line-tools/installation.mdx +++ b/web/sites/guides/src/content/docs/v4-0-1-snapshot/command-line-tools/installation.mdx @@ -123,9 +123,6 @@ Wheels ships on Windows through [Scoop](https://scoop.sh) — a portable, sandbo # the Scoop installer, which is why this works from a totally fresh shell. scoop install git -# The java bucket provides the openjdk21 dependency declared by both packages. -# Scoop's `depends:` does not auto-add the dependency bucket. -scoop bucket add java scoop bucket add wheels https://github.com/wheels-dev/scoop-wheels # Pick a channel: @@ -135,7 +132,7 @@ scoop install wheels-be # bleeding-edge - tracks every develop merge wheels --version ``` -Both packages install OpenJDK 21 as a Scoop dependency (`java/openjdk21`) — the `java` bucket added above is required. The `wheels.cmd` wrapper resolves `JAVA_HOME` from the installed dependency automatically, so no manual setup is needed. Both expose the same `wheels` PATH shim, so Scoop refuses to install both at once. To switch channels: +Both packages bundle OpenJDK 21 inline — no separate `java` bucket, no `JAVA_HOME` setup. Both expose the same `wheels` PATH shim, so Scoop refuses to install both at once. To switch channels: ```powershell scoop uninstall wheels && scoop install wheels-be diff --git a/web/sites/guides/src/content/docs/v4-0-1-snapshot/start-here/installing.mdx b/web/sites/guides/src/content/docs/v4-0-1-snapshot/start-here/installing.mdx index c3bd46682b..a0cdec0617 100644 --- a/web/sites/guides/src/content/docs/v4-0-1-snapshot/start-here/installing.mdx +++ b/web/sites/guides/src/content/docs/v4-0-1-snapshot/start-here/installing.mdx @@ -137,14 +137,13 @@ The legacy `wheels` package on chocolatey.org is the CommandBox-based v1.x relea 3. Add the Wheels bucket and install a channel: ```powershell title="PowerShell" - scoop bucket add java scoop bucket add wheels https://github.com/wheels-dev/scoop-wheels scoop install wheels # stable - tracks v4.0.0 GA tags # OR: scoop install wheels-be # bleeding-edge - tracks every develop merge ``` - Both packages install OpenJDK 21 as a Scoop dependency (`java/openjdk21`) from the `java` bucket added above — no manual `JAVA_HOME` setup needed; the wrapper resolves it automatically. Both expose the same `wheels` shim on PATH, so Scoop refuses to install both at once. See [Release Channels](/v4-0-1-snapshot/start-here/release-channels/) for the comparison. + Both packages inline OpenJDK 21 — no separate `java` bucket or `JAVA_HOME` setup required. Both expose the same `wheels` shim on PATH, so Scoop refuses to install both at once. See [Release Channels](/v4-0-1-snapshot/start-here/release-channels/) for the comparison. 4. Verify: