Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -334,16 +334,19 @@ jobs:
- uses: actions/download-artifact@v4
with:
name: codegraph-csharp-${{ matrix.rid }}
path: bin
# Where build.sh publishes it — never bin/, whose bin/codegraph-csharp
# is the committed wrapper the download would overwrite.
path: extractors/csharp/dist/${{ matrix.rid }}
# Nothing is installed on this runner for the extractor: the binary
# carries the runtime, Roslyn and the BCL. Run from the repo root with
# the RELATIVE --src the snapshot was made with (the typed path is the
# header's `root`).
- shell: bash
run: |
chmod +x "bin/${{ matrix.exe }}"
"bin/${{ matrix.exe }}" --version
"bin/${{ matrix.exe }}" --src fixtures/csharp/src --out out.jsonl --progress plain
bin="extractors/csharp/dist/${{ matrix.rid }}/${{ matrix.exe }}"
chmod +x "$bin"
"$bin" --version
"$bin" --src fixtures/csharp/src --out out.jsonl --progress plain
cmp out.jsonl fixtures/csharp/expected/model.jsonl
echo "byte-identical on ${{ matrix.os }}"

Expand Down
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ cd extractors/java && ./mvnw package # Maven Wrapper — `mvn` is NOT install
java -jar target/codegraph-java.jar --src <dir> --out model.jsonl
# the jar needs a JDK on PATH; non-interactive shells do not source sdkman:
# export JAVA_HOME="$HOME/.sdkman/candidates/java/25.0.4-tem"
./bin/codegraph-java --src <dir> --out model.jsonl # the jar, from the repo root, on the first Java 17+
# in JAVA_HOME, on PATH or under ~/.sdkman — no export needed
./build.sh --java --native # GraalVM binary for THIS platform only —
# native-image cannot cross-compile, so CI
# builds one RID per runner
Expand All @@ -185,6 +187,7 @@ cd extractors/csharp && dotnet test -c Release # needs the .NET 10 SDK (see ex
./build.sh --csharp --publish-all # linux-x64/arm64, osx-x64/arm64, win-x64 — all from this host
./test.sh --csharp # dotnet test + the published binary must reproduce the snapshot
extractors/csharp/dist/linux-x64/codegraph-csharp --src <dir> --out model.jsonl
./bin/codegraph-csharp --src <dir> --out model.jsonl # the same, for THIS host's RID
# runtime-only or SDK forms (dotnet <dll>, dotnet run): docs/csharp-extractor.md

./build.sh --ts --sea # ONE Node single-executable of the CLI + daemon + both frontends
Expand Down
32 changes: 32 additions & 0 deletions bin/codegraph-csharp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# The C# extractor as a program: `./bin/codegraph-csharp --src DIR --out model.jsonl`.
#
# Extensionless on purpose — the name IS the command. It runs the
# self-contained binary `build.sh --csharp` publishes for THIS host beside
# ITSELF (a git worktree or a moved checkout runs its own dist/); the binary
# carries its runtime, Roslyn and the BCL reference pack — no .NET installed.
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# The RID build.sh publishes by default (scripts/lib.sh host_rid).
case "$(uname -s)" in
Darwin) os="osx" ;;
MINGW*|MSYS*|CYGWIN*) os="win" ;;
*) os="linux" ;;
esac
case "$(uname -m)" in
arm64|aarch64) arch="arm64" ;;
*) arch="x64" ;;
esac
rid="$os-$arch"

bin="$here/../extractors/csharp/dist/$rid/codegraph-csharp"
[ -x "$bin" ] || bin="$bin.exe"

if [ ! -x "$bin" ]; then
printf 'codegraph-csharp: extractors/csharp/dist/%s/codegraph-csharp is missing\n' "$rid" >&2
printf 'Run `./build.sh --csharp` in %s and try again.\n' "$(cd "$here/.." && pwd)" >&2
exit 1
fi

exec "$bin" "$@"
50 changes: 50 additions & 0 deletions bin/codegraph-java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# The Java extractor as a program: `./bin/codegraph-java --src DIR --out model.jsonl`.
#
# Extensionless on purpose — the name IS the command. It runs the shaded jar
# `build.sh --java` produces beside ITSELF (a git worktree or a moved checkout
# runs its own target/), on the first Java at or above pom.xml's
# maven.compiler.release — a JRE will do, ECJ only needs its class library.
# Non-interactive shells never source sdkman, so its candidates are probed too.
set -euo pipefail
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
jar="$here/../extractors/java/target/codegraph-java.jar"

if [ ! -f "$jar" ]; then
printf 'codegraph-java: extractors/java/target/codegraph-java.jar is missing\n' >&2
printf 'Run `./build.sh --java` in %s and try again.\n' "$(cd "$here/.." && pwd)" >&2
exit 1
fi

want="$(sed -n 's:.*<maven\.compiler\.release>\([0-9][0-9]*\)</maven\.compiler\.release>.*:\1:p' \
"$here/../extractors/java/pom.xml" | head -1)"

# "1.8.0_392" -> 8, "17.0.2" -> 17, "21" -> 21 (a GA build prints no minor).
major() {
"$1" -version 2>&1 | sed -n '1s/.*version "\([^"]*\)".*/\1/p' | awk -F'[.+_-]' '{ print ($1 == 1 ? $2 : $1) }'
}

# Search order is preference order: JAVA_HOME, PATH, sdkman's selected JDK,
# every sdkman candidate, then macOS's registry. The first one recent enough wins.
find_java() {
local candidate have
set -- "${JAVA_HOME:+$JAVA_HOME/bin/java}" "$(command -v java 2>/dev/null || true)" \
"$HOME/.sdkman/candidates/java/current/bin/java" "$HOME"/.sdkman/candidates/java/*/bin/java
if [ -x /usr/libexec/java_home ]; then
set -- "$@" "$(/usr/libexec/java_home -v "$want+" 2>/dev/null || true)/bin/java"
fi
for candidate in "$@"; do
[ -n "$candidate" ] && [ -x "$candidate" ] || continue
have="$(major "$candidate")"
if [ -n "$have" ] && [ "$have" -ge "$want" ] 2>/dev/null; then printf '%s' "$candidate"; return 0; fi
done
return 1
}

if ! java="$(find_java)"; then
printf 'codegraph-java: no Java %s+ in JAVA_HOME, on PATH or under ~/.sdkman — the jar needs one\n' "$want" >&2
printf 'sdkman: sdk install java 25.0.4-tem homebrew: brew install --cask temurin\n' >&2
exit 1
fi

exec "$java" -jar "$jar" "$@"
5 changes: 3 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
# TypeScript : pnpm -r build -> packages/*/dist (incl. the viz bundle
# `codegraph city --serve` looks for) and
# extractors/typescript/dist/cli.js (bin/codegraph-typescript)
# Java : ./mvnw package -> extractors/java/target/codegraph-java.jar
# Java : ./mvnw package -> extractors/java/target/codegraph-java.jar (bin/codegraph-java)
# --native -> extractors/java/dist/<rid>/codegraph-java
# (GraalVM native image; HOST platform only —
# native-image drives the host linker and
# cannot cross-compile, so the per-OS matrix
# is one CI job per runner, not one job)
# C# : dotnet publish -> extractors/csharp/dist/<rid>/codegraph-csharp
# (self-contained single file; --publish-all
# builds the five-RID matrix from this host)
# builds the five-RID matrix from this host;
# bin/codegraph-csharp runs the host's)
# Elixir mix escript.build -> extractors/elixir/dist/codegraph-elixir
# (an escript: Elixir embedded, needs Erlang/OTP
# on the machine that runs it — bin/codegraph-elixir)
Expand Down
3 changes: 3 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,9 @@ java -jar target/codegraph-java.jar # defaults: the current directory,
# into <current-dir>-codegraph.jsonl
```

From the repo root, `./bin/codegraph-java` runs the same jar with the same
flags, on the first Java 17+ in `JAVA_HOME`, on `PATH` or under `~/.sdkman`.

Spoon runs in noClasspath mode, so the sources need not compile and no
dependency jars are needed. What cannot be resolved becomes a stub with its
edges kept, so the picture is honest about its gaps. `--src` is repeatable:
Expand Down
3 changes: 3 additions & 0 deletions docs/csharp-extractor.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ xattr -d com.apple.quarantine codegraph-csharp
codegraph-csharp.exe --src path\to\src --out model.jsonl
```

From a clone, `./bin/codegraph-csharp` runs the binary published for the
host's platform, with the same flags.

No `libicu` is needed on Linux: the extractor is built with invariant
globalization, so it runs on a minimal container image.

Expand Down
3 changes: 3 additions & 0 deletions extractors/java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ Go or .NET extractor would use.
```bash
java -jar target/codegraph-java.jar --src src/main/java --out model.jsonl

# the same jar from the repo root, on the first Java 17+ in JAVA_HOME, on PATH or under ~/.sdkman
./bin/codegraph-java --src src/main/java --out model.jsonl

# both options default: extract the current directory into <current-dir>-codegraph.jsonl
java -jar target/codegraph-java.jar
```
Expand Down
22 changes: 16 additions & 6 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
# unit pnpm -r test (vitest + fast-check property suites)
# schemas pnpm run gen:schemas must be a NO-OP — schemas/ is a committed
# artifact and the cross-language contract; drift there is a bug
# java ./mvnw test, then the NATIVE binary (if build.sh made one)
# re-extracts fixtures/java/src and must reproduce the committed
# snapshot — the only test that sees the image's own code path: no
# java.home, no VM class library, the embedded ct.sym reference
# csharp dotnet test, then the PUBLISHED binary (if build.sh made one)
# java ./mvnw test, then the built JAR (bin/codegraph-java) and the
# NATIVE binary (each if build.sh made one) re-extract
# fixtures/java/src and must reproduce the committed snapshot — the
# native one is the only test that sees the image's own code path:
# no java.home, no VM class library, the embedded ct.sym reference
# csharp dotnet test, then the PUBLISHED binary (bin/codegraph-csharp, if build.sh made one)
# re-extracts fixtures/csharp/src and must reproduce the committed
# snapshot byte for byte — the only test that sees the single-file
# code path (embedded BCL, no Assembly.Location)
Expand Down Expand Up @@ -225,6 +226,15 @@ if wants_java && [ "$SKIP_JAVA" = "no" ]; then
phase "java extractor tests (./mvnw test)" \
sh -c "cd '$JAVA_DIR' && ./mvnw -B test"

# The shaded jar, not the test classpath, must reproduce the snapshot: it is
# what `./bin/codegraph-java` runs from a clone. Same `root` rewrite as below.
if [ -f "$JAVA_DIR/target/codegraph-java.jar" ]; then
phase "built java jar reproduces the snapshot" \
sh -c "cd '$ROOT' && out=\$(mktemp) && ./bin/codegraph-java --src fixtures/java/src --out \"\$out\" --progress none >/dev/null 2>&1 && head -1 \"\$out\" | grep -qE '\"root\":\"[^\"]*fixtures[^\"]*java[^\"]*src\"' && sed '1s|\"root\":\"[^\"]*\"|\"root\":\"fixtures/java/src\"|' \"\$out\" | cmp - fixtures/java/expected/model.jsonl; rc=\$?; rm -f \"\$out\"; exit \$rc"
else
warn "no jar at $JAVA_DIR/target/codegraph-java.jar — run ./build.sh --java for the smoke test"
fi

# The same acceptance check the C# binary gets, and for the same reason: a
# native image is a different runtime, not a repackaging. It has no java.home,
# so ECJ finds no platform library and falls back to the ct.sym reference the
Expand Down Expand Up @@ -263,7 +273,7 @@ if wants_csharp && [ "$SKIP_CSHARP" = "no" ]; then
[ -x "$bin" ] || bin="$bin.exe"
if [ -x "$bin" ]; then
phase "published csharp binary reproduces the snapshot" \
sh -c "cd '$ROOT' && out=\$(mktemp) && '$bin' --src fixtures/csharp/src --out \"\$out\" --progress none >/dev/null 2>&1 && cmp \"\$out\" fixtures/csharp/expected/model.jsonl; rc=\$?; rm -f \"\$out\"; exit \$rc"
sh -c "cd '$ROOT' && out=\$(mktemp) && ./bin/codegraph-csharp --src fixtures/csharp/src --out \"\$out\" --progress none >/dev/null 2>&1 && cmp \"\$out\" fixtures/csharp/expected/model.jsonl; rc=\$?; rm -f \"\$out\"; exit \$rc"
else
warn "no published binary at $CSHARP_DIR/dist/$(host_rid) — run ./build.sh --csharp for the smoke test"
fi
Expand Down
11 changes: 6 additions & 5 deletions website/content/docs/how-to/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,17 @@ for Elixir, Rust 1.94+ and libclang for Ruby, Rust 1.94+ for the metrics pass.
```bash
export JAVA_HOME="$HOME/.sdkman/candidates/java/25.0.4-tem"
export PATH="$JAVA_HOME/bin:$PATH"
(cd extractors/java && ./mvnw -B package) # → extractors/java/target/codegraph-java.jar; `mvn` is not needed
./build.sh --csharp # → extractors/csharp/dist/<rid>/codegraph-csharp
(cd extractors/java && ./mvnw -B package) # → bin/codegraph-java (the jar); `mvn` is not needed
./build.sh --csharp # → bin/codegraph-csharp
./build.sh --elixir # → bin/codegraph-elixir
./build.sh --ruby # → bin/codegraph-ruby (Rust 1.94+ and libclang to build)
./build.sh --metrics # → bin/codegraph-metrics (Rust 1.94+ to build)
```

`bin/codegraph-typescript` is already built by step 1. The jar runs as
`java -jar extractors/java/target/codegraph-java.jar`; every page of this
documentation writes `codegraph-java`, and the two take the same flags.
`bin/codegraph-typescript` is already built by step 1. `bin/codegraph-java`
runs the jar on the first Java 17+ in `JAVA_HOME`, on `PATH` or under
`~/.sdkman`; every page of this documentation writes `codegraph-java`, and
the two take the same flags.

## Using it at work

Expand Down
1 change: 1 addition & 0 deletions website/content/docs/reference/csharp-extractor.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ codegraph-csharp --src <dir> --out model.jsonl
./build.sh --csharp # publish the host's binary → extractors/csharp/dist/<rid>/codegraph-csharp
./build.sh --csharp --publish-all # linux-x64, linux-arm64, osx-x64, osx-arm64, win-x64 — all from one host
extractors/csharp/dist/osx-arm64/codegraph-csharp --src <dir> --out model.jsonl
./bin/codegraph-csharp --src <dir> --out model.jsonl # the same, for the host's platform
```

The binary needs nothing installed; building it needs the .NET 10 SDK (see `extractors/csharp/README.md`).
Expand Down
2 changes: 2 additions & 0 deletions website/content/docs/reference/java-extractor.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ cd extractors/java && ./mvnw -B package # `mvn` is not installed; use the wr
java -jar target/codegraph-java.jar --src <dir> --out model.jsonl
```

From the repo root, `./bin/codegraph-java` runs the same jar without the exports: it takes the first Java 17+ in `JAVA_HOME`, on `PATH` or under `~/.sdkman`.

## Synopsis

```
Expand Down
Loading