Skip to content

Commit fdaff4e

Browse files
committed
feat(java): drive the analyzer through the codeanalyzer-java wheel and drop the bundled jar and JDK download
The Java backend now gets both the analyzer and the JVM it runs on from the codeanalyzer-java PyPI wheel, pinned at 3.0.2 behind a new optional `java` extra. 3.0.2 reads its primordial scope from `jrt:/` in the running JVM, so nothing needs `JAVA_HOME` or a `jmods/` directory any more: * `JCodeanalyzer._get_codeanalyzer_exec` returns `codeanalyzer_java.command()`. The import is lazy, so `import cldk` and `import cldk.analysis.java` work without the extra; running the backend without it raises CodeanalyzerExecutionException naming the distribution and `pip install "cldk[java]"`. * Deleted `cldk/analysis/java/codeanalyzer/_jdk.py` (`ensure_jdk`, the pinned Temurin download, the ~200 MB per-project JDK cache), the checked-in `codeanalyzer-2.4.1.jar` and its directory, the `[tool.hatch.build]` force-include, the root `.gitignore` `*.jar` rule and the `CLDK_CODEANALYZER_JAVA_JAR` seam the e2e grew while the tree's jar was stale. * release.yml no longer downloads the pinned jar from the codeanalyzer-java GitHub release and no longer verifies a jar is bundled in the wheel and sdist. This retires the mechanism #284, #336 and #337 patched: the wheel pin is now the single source of the analyzer version, and nothing is fetched at build time. * Extras take the thin-base shape 2.0 is heading for: `neo4j`, `java`, and `all = ["cldk[java]", "cldk[neo4j]"]`. codeanalyzer-python and codeanalyzer-typescript stay hard dependencies until #340. * Fixtures regenerated at 3.0.2 with the command lines the v2 README records; the only content delta against the 3.0.1 pair is `analyzer.version` (verified by recursive parsed-JSON compare: one differing leaf per file). Verified: the wheel path with `JAVA_HOME` unset and no JDK on PATH returns the identical daytrader8 `-a 4` call-graph edge set the 3.0.1 jar returned on the provisioned Temurin -- 1862 edges, 1378 `declared+rta` / 375 `rta` / 109 `declared`, symmetric difference 0 after normalising the app name. A wheel built from this tree contains no `.jar`, and neither does the sdist. Closes #339
1 parent 122eccf commit fdaff4e

21 files changed

Lines changed: 174 additions & 370 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -65,56 +65,9 @@ jobs:
6565
git push --delete origin ${GITHUB_REF#refs/tags/}
6666
exit 1
6767
68-
- name: Inject the pinned Code Analyzer JAR
69-
run: |
70-
# The pin in pyproject.toml is authoritative: fetch exactly that release's
71-
# versioned jar (codeanalyzer-<pin>.jar). A pin without a matching asset fails
72-
# the step, and the gate below deletes the tag - never fall back to latest.
73-
PIN=$(grep -E '^codeanalyzer-java\s*=' pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
74-
test -n "$PIN"
75-
CODE_ANALYZER_URL=$(curl -sf "https://api.github.com/repos/codellm-devkit/codeanalyzer-java/releases/tags/v${PIN}" | jq -er --arg n "codeanalyzer-${PIN}.jar" '.assets[] | select(.name == $n) | .browser_download_url')
76-
echo "Downloading: $CODE_ANALYZER_URL"
77-
wget -q "$CODE_ANALYZER_URL"
78-
mkdir -p ${{ github.workspace }}/cldk/analysis/java/codeanalyzer/jar/
79-
rm -f ${{ github.workspace }}/cldk/analysis/java/codeanalyzer/jar/codeanalyzer-*.jar
80-
mv "codeanalyzer-${PIN}.jar" ${{ github.workspace }}/cldk/analysis/java/codeanalyzer/jar/
81-
8268
- name: Build Package
8369
run: uv build
8470

85-
- name: Verify the codeanalyzer JAR is bundled
86-
# Guard against the hatchling/.gitignore regression (issue #284): a jarless wheel
87-
# installs fine but fails at runtime with "codeanalyzer jar not found". Fail the
88-
# release here rather than publish a broken artifact to PyPI.
89-
#
90-
# The listing is captured before grepping: piping `tar tzf` (which decompresses the
91-
# whole 32MB sdist) straight into `grep -q` lets grep close the pipe on first match,
92-
# SIGPIPE-killing tar and — under `pipefail` — reporting a false "missing JAR".
93-
run: |
94-
set -euo pipefail
95-
PIN=$(grep -E '^codeanalyzer-java\s*=' pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
96-
jar_re='codeanalyzer/jar/codeanalyzer-[0-9][^/]*\.jar$'
97-
fail=0
98-
for f in dist/*.whl dist/*.tar.gz; do
99-
case "$f" in
100-
*.whl) listing=$(unzip -l "$f") ;;
101-
*.tar.gz) listing=$(tar tzf "$f") ;;
102-
esac
103-
# Exactly one jar, and it is the pinned one (issue #336: a stray second jar
104-
# from a mismatched download must fail the release, not ride along).
105-
jars=$(grep -oE "$jar_re" <<<"$listing" || true)
106-
if [ "$(wc -l <<<"$jars" | tr -d ' ')" = "1" ] && [ -n "$jars" ] && grep -qF "codeanalyzer-${PIN}.jar" <<<"$jars"; then
107-
echo " ✓ $f ($jars)"
108-
else
109-
echo "::error::$f must bundle exactly codeanalyzer-${PIN}.jar; found: ${jars:-none}"
110-
fail=1
111-
fi
112-
done
113-
if [ "$fail" -ne 0 ]; then
114-
echo "Refusing to publish a jarless release."; exit 1
115-
fi
116-
echo "codeanalyzer JAR present in wheel and sdist ✓"
117-
11871
- name: Extract release notes from CHANGELOG.md
11972
id: notes
12073
# Source the release body from the hand-written CHANGELOG.md section for this tag —

‎.gitignore‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
.mtj.tmp/
2626

2727
# Package Files #
28-
*.jar
2928
*.war
3029
*.nar
3130
*.ear

‎CHANGELOG.md‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,49 @@ plans `docs/design/plans/2026-09-06-leg-2.5a-typescript-schema-v2.md` and
6666
the fix ships.
6767

6868
### Changed (leg 2.5a)
69+
- **The Java analyzer comes from the `codeanalyzer-java` PyPI wheel, behind a new `java` extra**
70+
(`pip install "cldk[java]"`). `pyproject.toml` gains `[project.optional-dependencies] java =
71+
["codeanalyzer-java==3.0.2"]` and `[tool.backend-versions] codeanalyzer-java = "3.0.2"`, which is
72+
now the single source of the analyzer version. `JCodeanalyzer._get_codeanalyzer_exec` returns
73+
`codeanalyzer_java.command()` — the wheel's jar run on the JVM the wheel bundles (`jdk4py`,
74+
Temurin 21). The import is lazy, so `import cldk` and `import cldk.analysis.java` work without the
75+
extra; running the backend without it raises `CodeanalyzerExecutionException` naming the
76+
`codeanalyzer-java` distribution and the `pip install "cldk[java]"` line.
77+
**Why an extra:** the wheel carries a ~35 MB JVM that an install analyzing only Python or
78+
TypeScript never runs, and `jdk4py`'s PyPI classifier reads bare `GPLv2` (see below), which trips
79+
policy gates for consumers who never touch Java. This is the **first step of a thin-base,
80+
additive-extras split**, not the whole of it:
81+
82+
| Install | What you get |
83+
|---|---|
84+
| `pip install cldk` | the facades, the models, and the Python and TypeScript analyzers |
85+
| `pip install "cldk[neo4j]"` | the above plus the Neo4j driver for the read-only graph backends (no analyzer) |
86+
| `pip install "cldk[java]"` | the above plus the Java analyzer jar and its bundled JVM |
87+
| `pip install "cldk[all]"` | everything |
88+
89+
`codeanalyzer-python` and `codeanalyzer-typescript` are still installed **unconditionally**; #340
90+
moves them into extras of their own and grows `all` accordingly.
91+
**Licensing, stated plainly:** `jdk4py` ships OpenJDK under GPLv2 **with the Classpath Exception**
92+
(the ordinary OpenJDK terms; the exception is what permits Apache-2.0 code to run on it), but its
93+
PyPI classifier says plain GPLv2 and its metadata carries no license file, so license scanners
94+
keyed to classifiers will now see a GPLv2 row where the previous runtime JDK download was
95+
invisible to dependency tooling.
96+
- **The Java release plumbing is gone with the jar.** `.github/workflows/release.yml` no longer
97+
downloads the pinned jar from the `codeanalyzer-java` GitHub release and no longer verifies that a
98+
jar is bundled in the wheel and sdist — the mechanism issues #284, #336 and #337 patched. The
99+
analyzer arrives as a normal locked dependency; nothing is fetched at build time.
100+
101+
### Removed
102+
- **`cldk/analysis/java/codeanalyzer/jar/` and the checked-in `codeanalyzer-2.4.1.jar`**, the
103+
`[tool.hatch.build] artifacts` force-include that shipped it, and the root `.gitignore`'s `*.jar`
104+
rule. The `cldk` wheel and sdist no longer contain a `.jar` (~35 MB smaller).
105+
- **`cldk/analysis/java/codeanalyzer/_jdk.py`** (`ensure_jdk`, `JdkLoader`, the pinned Temurin
106+
`jdk-21.0.5+11`). codeanalyzer-java 3.0.x reads its primordial scope from `jrt:/` in the running
107+
JVM, so no `jmods/` is needed: **the SDK downloads no JDK (~200 MB per project cache), and reads
108+
or writes no `JAVA_HOME`** — a `JAVA_HOME` already in the environment is left exactly as it is.
109+
`pip install "cldk[java]"` now works on a machine with no Java at all. The `<cache>/java/jdk/`
110+
cache directory is simply unused; delete it by hand if you want the space back. The
111+
`CLDK_CODEANALYZER_JAVA_JAR` test/dev seam is removed with it — the wheel is the source of the jar.
69112
- **Pinned `codeanalyzer-typescript` 0.4.3 → 1.2.0** (`pyproject.toml` `dependencies` and
70113
`[tool.backend-versions]`). The analyzer emits canonical schema v2, and `cldk.models.typescript`
71114
is rewritten as an `extra="forbid"` mirror of it: `analysis.json` is the `TSAnalysis` envelope

‎CLAUDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ an optional read-only Neo4j backend — selected by the *type* of the `backend=`
1010

1111
| Language | Entry point | Local backend | Neo4j backend | Models |
1212
|----------|-------------|---------------|---------------|--------|
13-
| Java | `CLDK.java(...)` | `JCodeanalyzer` (codeanalyzer-java 3.0.1 JAR, subprocess, `-a 1..4`) | `JNeo4jBackend` (3.0.1 graph, probed at attach) | `cldk/models/java/` (schema v2 mirror) |
13+
| Java | `CLDK.java(...)` (needs the `cldk[java]` extra) | `JCodeanalyzer` (the `codeanalyzer-java` 3.0.2 wheel's jar on its bundled JVM, subprocess, `-a 1..4` — no jar in this repo, no JDK download) | `JNeo4jBackend` (3.0.1 graph, probed at attach) | `cldk/models/java/` (schema v2 mirror) |
1414
| Python | `CLDK.python(...)` | `PyCodeanalyzer` (in-process `codeanalyzer-python`) | `PyNeo4jBackend` | re-exported from `codeanalyzer-python` |
1515
| TypeScript (+ JavaScript modules) | `CLDK.typescript(...)` | `TSCodeanalyzer` (`codeanalyzer-typescript` 1.3.0 binary from the wheel, subprocess; `-a 1..4`, but `--emit neo4j` takes no `-a` and is always full depth) | `TSNeo4jBackend` (graphs emitted by ≥ 1.3.0; older refused at attach) | `cldk/models/typescript/` (schema v2 mirror) |
1616

‎cldk/analysis/java/codeanalyzer/__init__.py‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,4 @@
2020

2121
from .codeanalyzer import JCodeanalyzer
2222

23-
24-
"""
25-
Download the codeanalyzer.jar file from the latest release on the codeanalyzer repository.
26-
"""
27-
28-
2923
__all__ = ["JCodeanalyzer"]

‎cldk/analysis/java/codeanalyzer/_jdk.py‎

Lines changed: 0 additions & 183 deletions
This file was deleted.

0 commit comments

Comments
 (0)