From 7c35239d246e063c2e0cfbae6ab063e777202f67 Mon Sep 17 00:00:00 2001 From: Peter Amiri Date: Wed, 20 May 2026 07:28:51 -0700 Subject: [PATCH] chore(scoop): remove stale draft manifests; bucket repo is authoritative The Scoop draft generator at tools/distribution-drafts/scoop/ produced two .json manifests intended to be copied into wheels-dev/scoop-wheels at bucket setup time. After the inline-JDK rework in scoop-wheels@3f22250 (May 18), the bucket grew its own self-hosted autoupdate workflow and diverged from this draft on every meaningful axis: - inline JDK as 5th URL vs. external `depends: java/openjdk21` - real auto-bumped hashes vs. placeholder zeros - self-hosted autoupdate workflow vs. Scoop built-in `autoupdate` block - JAVA_HOME fallback + direct `java -jar` invocation in wrapper (scoop-wheels#6) vs. `call lucli.bat` here The parent README originally framed this directory as a "useful diff signal during release reviews" -- in practice nobody acted on the divergence between May 18 and today (two snapshot releases later), and the stale drafts only added a misleading second source-of-truth. wheels#2765 surfaced the gap when a user hit a wrapper bug that had already been quietly fixed-then-undone in the divergence. Delete the scoop subdirectory and trim the two scoop rows + the keep-or-remove paragraph from the parent README. Bucket is now the unambiguous home; structural changes happen there directly. No CI consumed these files -- release.yml only references linux-packages/apt-repo/yum-repo from this tree. scoop-wheels#6 (the wrapper fix) and scoop-wheels#7 (tracking) remain valid in the bucket repo. Closes wheels#2765 Signed-off-by: Peter Amiri --- tools/distribution-drafts/README.md | 14 +- tools/distribution-drafts/scoop/README.md | 141 -------- .../scoop/build-manifests.py | 330 ------------------ tools/distribution-drafts/scoop/validate.py | 228 ------------ .../distribution-drafts/scoop/wheels-be.json | 173 --------- tools/distribution-drafts/scoop/wheels.json | 174 --------- 6 files changed, 8 insertions(+), 1052 deletions(-) delete mode 100644 tools/distribution-drafts/scoop/README.md delete mode 100644 tools/distribution-drafts/scoop/build-manifests.py delete mode 100644 tools/distribution-drafts/scoop/validate.py delete mode 100644 tools/distribution-drafts/scoop/wheels-be.json delete mode 100644 tools/distribution-drafts/scoop/wheels.json 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 5242d41314..0000000000 --- a/tools/distribution-drafts/scoop/build-manifests.py +++ /dev/null @@ -1,330 +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', - " )", - ")", - "", - f'call "%~dp0lucli-{LUCLI_VERSION}.bat" %*', - "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 9b49955aa6..0000000000 --- a/tools/distribution-drafts/scoop/wheels-be.json +++ /dev/null @@ -1,173 +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(':: `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('call \"%~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('call \"%~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 0b180f1348..0000000000 --- a/tools/distribution-drafts/scoop/wheels.json +++ /dev/null @@ -1,174 +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(':: `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('call \"%~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('call \"%~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" - ] - } - } - } -}