Skip to content

fix(installer): bring install.ps1 to parity with install.sh — Windows launchers ignored lib/ via java -jar (#179) - #180

Merged
fupelaqu merged 1 commit into
mainfrom
fix/179
Jul 31, 2026
Merged

fix(installer): bring install.ps1 to parity with install.sh — Windows launchers ignored lib/ via java -jar (#179)#180
fupelaqu merged 1 commit into
mainfrom
fix/179

Conversation

@fupelaqu

Copy link
Copy Markdown
Contributor

Closes #179.

What was wrong

install.ps1 was not a port of the current installer — it was roughly the pre-bundle one. Two classes of problem:

Functional. Both generated launchers ran java -jar, which ignores the classpath entirely, so every extension jar in lib/ was invisible to the JVM and the cross-index JOIN engine was silently absent on Windows — the same silent-wrong-results failure class as #157. install.sh:1028 carries an explicit comment forbidding exactly this.

Missing surface. Grep counts, install.sh vs install.ps1 before this PR: -all bundle path 67 hits vs 0, licence extraction 8 vs 0, --add-opens 1 vs 0, --no-extensions 14 vs 0. So install.ps1 could not install the artifact the README's one-liner advertises.

What this does

Launchers now mirror install.sh: -cp "<jar>;<base>\lib\*" app.softnetwork.elastic.client.Cli, plus --add-opens=java.base/java.nio=ALL-UNNAMED and -Dio.netty.tryReflectionSetAccessible=true on Java 9+ (Arrow/DuckDB need them).

Ported: the bundle path (bundle listing owns its own version line, exact-version match, HEAD existence probe, fallback to plain), licence-bundle extraction (licenses/ + NOTICE, failure-tolerant), the bundle vs pure-Apache licence notice, -NoExtensions. Java floor for ES 6/7/8 raised 8 → 11 (the 0.20+ CLI bundles logback 1.5.x, Java-11 bytecode — it does not start on 8).

Bugs found while testing and fixing

  • Resolve-LatestVersion returned "2" instead of "0.20.2". With exactly one release version the pipeline yields a bare String, and [-1] on a string returns its last character. Pre-existing; only manifests when a listing has one release. @()-wrapped.
  • java -version parsed three different ways (installer, .ps1 launcher, Check-Prerequisites), none taking the first line only. With two matching lines the pipeline is an Object[] whose ToString() is "System.Object[]", no regex matches, and the version silently reads 0 — which would drop --add-opens with no message. Now one Get-JavaMajorVersion, Select-Object -First 1.
  • Multi-flag JAVA_OPTS reached the JVM as one argument; now split, with empty elements dropped (a leading space would emit an empty argv entry, which java reads as the main class name and refuses to start).
  • Every fallback yields an install with no JOIN engine and this script has no coursier resolution to populate lib/, so it now says so outright rather than leaving the user to rediscover install.ps1 has drifted behind install.sh: Windows launchers use java -jar (lib/ extensions ignored), no bundle/licence/AppCDS/--no-extensions support #179's own symptom.
  • java's exit status is now propagated from the .ps1 launcher (install.sh gets it from exec java); logback's -D is quoted in the .bat (the default target is under %USERPROFILE%, routinely containing a space); the 309 MB download sets $ProgressPreference = 'SilentlyContinue' (per-chunk Write-Progress makes a download this size look hung on 5.1); licence extraction skips path-traversal entries; licence status is repeated in the summary and written into VERSION.

Review caught two HIGH-severity bugs in my first batch attempt

Worth recording, because the batch file is the least testable part. My first version did:

if defined JVER (
    set JVER=%JVER:"=%
    for /f "tokens=1,2 delims=." %%a in ("%JVER%") do ...
)

cmd expands every %VAR% in a parenthesised block in one parse pass, before executing any line in it. Without enabledelayedexpansion the quote-strip was dead code and the inner FOR saw the still-quoted value, so JAVA_MAJOR became "11 and the next line was a cmd syntax error — dropping the very --add-opens flags this PR exists to add. Separately, if defined JAVA_MAJOR if %JAVA_MAJOR% GEQ 9 does not guard anything, because %JAVA_MAJOR% is expanded at parse time; when empty it degenerates to if GEQ 9, a parse error that aborts the whole script so the REPL never starts.

Both fixed: JAVA_MAJOR is initialised to 0, %%~v strips the quotes, the second FOR moved out of the block, and the if defined guard is gone. A per-iteration if not defined JVER also gives first-match-wins parity with install.sh's head -n 1.

Verification (PowerShell 7.4.5, local mirror of the artifact repo)

Check Result
AST parse clean, 0 errors
Default install resolves -all bundle 0.20.2, downloads, extracts 3 licences + NOTICE
-NoExtensions installs the plain jar, no licenses/, Apache-only notice, correct version
-ListVersions bundle line by default; plain line with -NoExtensions
Bundle-miss (-Version 0.19.0) warns, falls back to plain, warns that JOIN is absent
Launcher's java invocation starts the CLI and a real cross-index JOIN returns the correct 5 rows against live ES 8.18.3 (macOS : substituted for Windows ;)
Generated .bat structure JAVA_MAJOR=0 present, %%~v used, second FOR outside the block, no if defined JAVA_MAJOR if, LOGBACK_OPTS quoted

NOT verified — needs a Windows reviewer before merge

I have no Windows host, so these are reasoned-and-structurally-checked, not executed:

  1. cmd.exe running the generated bin\softclient4es.bat. Confirm JAVA_MAJOR is a bare integer and --add-opens actually reaches the JVM (temporary echo %EXTRA_OPTS%); run with java absent from PATH; run from a path containing a space (C:\Program Files\... and the default C:\Users\<name with space>\...); pass an argument containing spaces and one containing ".
  2. Windows PowerShell 5.1 (not just 7.x) for the whole installer: bundle resolution, HEAD probe through a corporate proxy, the 309 MB download (time it), licence extraction, both launchers.
  3. bin\softclient4es.ps1 under 5.1 with $env:JAVA_OPTS set (single flag, multi flag, leading space) and a double-quoted SQL identifier in -c (5.1's native argument quoting mangles embedded "; 7.3+ does not).
  4. irm … | iex (the README's Windows entry point) against the param() + exit paths — an exit inside iex terminates the host session.
  5. Java 8 (should now abort for ES 6/7/8 with the new floor) and ES 9 + Java 17.

Deliberately out of scope

AppCDS is not ported (install.sh:999-1018, 1050-1084) — a pure cold-start optimisation whose JDK-version gating is the fiddliest part; Windows works correctly without it. Also absent: the ELASTIC_* empty-env-unset loop, benign on Windows since setting an env var to "" deletes it there. Worth a follow-up issue for AppCDS if Windows cold start matters.

Please also confirm whether Windows is a supported R1 install target — if it is, the -jar defect this PR fixes was release-blocking for those users.

The Windows installer had drifted far behind install.sh. Most seriously, both
generated launchers ran `java -jar`, which ignores the classpath entirely, so
every extension jar in lib/ was invisible to the JVM and the cross-index JOIN
engine was silently absent on Windows -- the same silent-wrong-results failure
class as #157. install.sh:1028 carries an explicit comment forbidding -jar.

Launchers (.bat and .ps1) now mirror install.sh's invocation:
  -cp "<jar>;<base>\lib\*" app.softnetwork.elastic.client.Cli
plus --add-opens=java.base/java.nio=ALL-UNNAMED and
-Dio.netty.tryReflectionSetAccessible=true on Java 9+, which Arrow/DuckDB need.

Ported from install.sh: the -all bundle path (bundle listing owns its own
version line, exact-version match, HEAD existence probe, fallback to the plain
artifact), licence-bundle extraction (licenses/ + NOTICE, failure-tolerant),
the bundle vs pure-Apache licence notice, and -NoExtensions. The Java floor for
ES 6/7/8 goes 8 -> 11: the 0.20+ CLI bundles logback 1.5.x (Java-11 bytecode)
and does not start on 8.

Also fixed, found while testing:
- Resolve-LatestVersion applied [-1] to a pipeline result that is a bare String
  when only one release version exists, returning its last CHARACTER
  ("0.20.2" -> "2") and then failing the download. Pre-existing; @()-wrapped.
- The .ps1 launcher passed a multi-flag JAVA_OPTS to the JVM as ONE argument.
  Now split on whitespace, with empty elements dropped (a leading space would
  otherwise emit an empty argv entry, which java reads as the main class).
- Every fallback lands on the plain engine, and this script has no coursier
  resolution to populate lib/, so it now says outright that JOIN and
  materialized views are absent on that path instead of leaving the user to
  rediscover #179's symptom.
- java's exit status is now propagated from the .ps1 launcher (install.sh gets
  this from `exec java`); logback's -D is quoted in the .bat (the default
  target lives under %USERPROFILE%, routinely containing a space); the 309 MB
  download suppresses $ProgressPreference (per-chunk Write-Progress makes a
  download this size look hung on PowerShell 5.1); licence extraction skips
  path-traversal entries; the licence status is repeated in the summary and
  written into VERSION.

Verified on PowerShell 7.4.5 against a local mirror of the artifact repo:
AST parse clean; bundle install resolves 0.20.2, extracts 3 licences + NOTICE;
-NoExtensions installs the plain jar with no licences and the Apache-only
notice; -ListVersions lists the bundle line by default and the plain line with
-NoExtensions; a bundle-miss warns and falls back. The launcher's exact java
invocation (macOS ':' for Windows ';') starts the CLI and a real cross-index
JOIN returns the correct 5 rows against live ES 8.18.3.

NOT verifiable here (no Windows host): cmd.exe execution of the generated .bat
and Windows PowerShell 5.1. See the PR for the manual checklist.

Closed Issue #179

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@fupelaqu

Copy link
Copy Markdown
Contributor Author

The Windows verification checklist from this PR's description is now tracked as #181it is a merge blocker for this PR.

Everything in it is the part macOS + PowerShell 7.4.5 structurally cannot cover: cmd.exe executing the generated .bat (confirming JAVA_MAJOR is a bare integer and that --add-opens actually reaches the JVM), Windows PowerShell 5.1 for the whole installer, the irm | iex entry point against the param()/exit paths, and the raised Java floor.

@fupelaqu
fupelaqu marked this pull request as ready for review July 31, 2026 20:31
@fupelaqu
fupelaqu merged commit 2e02e45 into main Jul 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

install.ps1 has drifted behind install.sh: Windows launchers use java -jar (lib/ extensions ignored), no bundle/licence/AppCDS/--no-extensions support

1 participant