Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a4795f1
Convert Kotlin website Writerside content to JSON, add it to database…
alexmmiller Jul 22, 2026
3b128c0
Kotlin docs sync and website processing end-to-end pipeline test
alexmmiller Jul 22, 2026
e5ff684
Config/assets for pipeline test
alexmmiller Jul 22, 2026
cd59353
Address PR review feedback and add blacklist-pruning verification
alexmmiller Jul 23, 2026
ae44822
Merge branch 'fix/ADFA-4514' into fix/ADFA-4737
alexmmiller Jul 27, 2026
5984357
Automate stdlib JSON doc generation in the e2e pipeline script
alexmmiller Jul 29, 2026
1f7edd4
Add repository-root CLAUDE.md
alexmmiller Aug 5, 2026
9b4ba07
Add Build Kotlin Docs workflow
alexmmiller Aug 5, 2026
421e529
Add Kotlin docs DB pipeline + Build Kotlin Docs GitHub Action (ADFA-4…
alexmmiller Aug 6, 2026
66da59d
Address Hal's PR #24 review feedback
Aug 10, 2026
1cf41d2
Merge remote-tracking branch 'origin/fix/ADFA-5039' into fix/ADFA-4739
Aug 13, 2026
26cb831
Fix find_include_warnings crashing on a non-UTF-8 file
Aug 13, 2026
26c6250
Compress Kotlin-website Content rows against a shared Brotli dictionary
davidschachterADFA Aug 15, 2026
09ca170
Add whole-database migration to shared-dictionary Brotli
davidschachterADFA Aug 15, 2026
97755b1
Make docdb-studio's Content reads/writes dictionary-aware
davidschachterADFA Aug 15, 2026
2827bfb
Parallelize the whole-database migration's read+compress phase
davidschachterADFA Aug 15, 2026
b203500
ADFA-5141: Pin page_size in populate_db.py's own VACUUM
davidschachterADFA Aug 16, 2026
b09331f
ADFA-5141: Fix the same WAL deadlock in populate_db.py's own VACUUM
davidschachterADFA Aug 17, 2026
b5084b5
ADFA-5141: Restore file permissions after the VACUUM INTO swap
davidschachterADFA Aug 17, 2026
7970cdd
ADFA-5141: Use a bound parameter for VACUUM INTO's target, close jour…
davidschachterADFA Aug 17, 2026
dda6410
ADFA-5141: Fix chmod ordering and unclosed connections, matching PR #25
davidschachterADFA Aug 18, 2026
801f5eb
Revert ADFA-5141 page_size pinning: declined, keeping this PR scoped …
davidschachterADFA Aug 18, 2026
358276d
ADFA-5171: Add a repair script for chunked rows misnumbered from -2
davidschachterADFA Aug 18, 2026
0599a37
Merge pull request #27 from appdevforall/fix/ADFA-5171-fragment-renum…
davidschachterADFA Aug 18, 2026
838ac44
ADFA-5153: Address review findings on the dictionary migration
davidschachterADFA Aug 21, 2026
4d4f37d
ADFA-5153: Route the last LIKE delete through fragment_chain, declare…
davidschachterADFA Aug 22, 2026
4b19f14
ADFA-5153: Add the dictionary re-mint tooling used on the 21-Aug data…
davidschachterADFA Aug 22, 2026
25d284f
ADFA-5153: Tell Windows users how to install the brotli CLI, and mean it
davidschachterADFA Aug 22, 2026
5a00e22
Merge pull request #26 from appdevforall/ADFA-5153-content-brotli-dic…
davidschachterADFA Aug 22, 2026
7499935
Fix 9 issues from the PR #24 database-insertion review
Aug 24, 2026
8ace4f4
Merge fix/ADFA-4737 into fix/ADFA-4739 (shared-Brotli-dictionary pipe…
Aug 24, 2026
80e234a
Merge fix/ADFA-5039 into fix/ADFA-4739 (md_to_json.py review fixes)
Aug 25, 2026
06a43f5
Make the Build Kotlin Docs pipeline actually runnable end-to-end
alexmmiller Aug 31, 2026
d9df0f0
Fix the 15 findings from Hal's PR #24 review, with regression tests
alexmmiller Sep 1, 2026
e6786a8
Merge origin/main into fix/ADFA-4739
alexmmiller Sep 2, 2026
46235fb
Fix the 14 findings from Hal's second PR #24 review
alexmmiller Sep 7, 2026
a59d777
Fix the five findings from the /code-review pass
alexmmiller Sep 7, 2026
0204dbc
Fix the findings from Hal's third PR #24 review
alexmmiller Sep 8, 2026
fa1848f
Fix the eight findings from the /code-review xhigh pass
alexmmiller Sep 8, 2026
63a2dea
Fix the eight findings from the second /code-review xhigh pass
alexmmiller Sep 8, 2026
966fb90
Fix the seven findings from the third /code-review xhigh pass
alexmmiller Sep 8, 2026
6b5345c
Fix the seven findings from the fourth /code-review xhigh pass
alexmmiller Sep 8, 2026
38caac4
Fix the seven findings from the fifth /code-review xhigh pass
alexmmiller Sep 9, 2026
99c9b2f
Fix the seven findings from the sixth /code-review xhigh pass
alexmmiller Sep 9, 2026
a9009a0
Merge branch 'main' into fix/ADFA-4739
alexmmiller Sep 18, 2026
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
378 changes: 378 additions & 0 deletions .github/workflows/build-kotlin-docs.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ __pycache__/
*$py.class
*.db
*.sqlite
run_e2e_pipeline_test.local.sh
grep_content_blobs.local.py
192 changes: 192 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# CLAUDE.md

Guidance for Claude (and anyone else) working in this repository.

## What this repository is

App Dev For All builds **Code on the Go**, an Android IDE aimed at users with no or limited
internet access
(code: [appdevforall/CodeOnTheGo](https://github.com/appdevforall/CodeOnTheGo)). To support that,
Java/Kotlin/Android API documentation is bundled into the app as a single SQLite file — the
**documentation database** — rather than fetched from the web.

The documentation database serves two distinct features in the IDE:

1. **Tooltips (Tier 1/2).** When a user selects a keyword/symbol in the code editor, a dialog
shows short (Tier 1) and detailed (Tier 2) tooltip text if the selection matches an entry in
the DB. This lookup happens elsewhere in the CodeOnTheGo Android code (not in this repo, and
not in `WebServer.kt` — see below).
2. **Content pages (Tier 3).** From a tooltip, the user can click through to a full documentation
page. Those pages (and other static content — HTML, images, PDFs) are served over HTTP by
**`WebServer.kt`**
([CodeOnTheGo/app/src/main/java/com/itsaky/androidide/localWebServer/WebServer.kt](https://github.com/appdevforall/CodeOnTheGo/blob/stage/app/src/main/java/com/itsaky/androidide/localWebServer/WebServer.kt)),
which runs inside the app and reads directly from the `Content` (and, as of recently,
`Templates`/`Bookshelf`/`BookCategories`) tables of the same database.

**This repository (`OfflineDocumentationTools`) is the collection of offline tools that build and
edit that database** — it contains no part of the production Android app itself.

> **Alex's standing caveat, worth repeating at the top of every session:** nothing in this
> repository is guaranteed to work against the *current* production database. The schema has moved
> forward (in the app / by hand) faster than the tooling in this repo has been updated. See
> "Schema: current vs. what this repo expects" below — that gap is the most important thing to
> understand before making changes here.

## Schema: current vs. what this repo expects

The schema below is what `~/documentation.db` (Alex's current production copy) actually contains,
as of 2026-08-05:

```sql
CREATE TABLE Languages (id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT NOT NULL UNIQUE);
CREATE TABLE ContentTypes (id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT NOT NULL UNIQUE, compression TEXT NOT NULL);
CREATE TABLE TooltipCategories (id INTEGER PRIMARY KEY, category TEXT NOT NULL);
CREATE TABLE TooltipButtonNumbers (id INTEGER UNIQUE); -- manually assigned display order
CREATE TABLE Content (
id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT NOT NULL, languageID INTEGER NOT NULL,
content BLOB NOT NULL, contentTypeID INTEGER NOT NULL, templateId INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY (languageID) REFERENCES Languages(id), FOREIGN KEY (contentTypeID) REFERENCES ContentTypes(id),
UNIQUE('path')
);
CREATE TABLE Tooltips (
id INTEGER PRIMARY KEY AUTOINCREMENT, categoryId INTEGER NOT NULL, tag TEXT NOT NULL,
summary TEXT NOT NULL, detail TEXT NOT NULL, UNIQUE (categoryId, tag),
FOREIGN KEY(categoryId) REFERENCES TooltipCategories(id)
);
CREATE TABLE TooltipButtons (
tooltipId INTEGER, buttonNumberId INTEGER, description TEXT, uri TEXT,
FOREIGN KEY(tooltipId) REFERENCES Tooltips(id), FOREIGN KEY(buttonNumberId) REFERENCES TooltipButtonNumbers(id)
);
CREATE TABLE LastChange (documentationSet TEXT, changeTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP, who TEXT);
CREATE TABLE Templates (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, content BLOB NOT NULL, UNIQUE('name'));
CREATE TABLE BookCategories (id INTEGER PRIMARY KEY AUTOINCREMENT, category STRING, description STRING DEFAULT '', UNIQUE('category'));
CREATE TABLE Bookshelf (contentID INTEGER NOT NULL, title STRING DEFAULT '', description STRING DEFAULT '',
bookCategoryID INTEGER, FOREIGN KEY (bookCategoryID) REFERENCES BookCategories(id), UNIQUE(title, bookCategoryId));
-- Triggers keep Bookshelf in sync when a .pdf row is added to/removed from Content.
CREATE TABLE PUCC_Students (...), PUCC_Classes (...), PUCC_Sections (...), PUCC_Professors (...),
PUCC_StudentAssignments (...), PUCC_ProfessorAssignments (...)
-- Unrelated to documentation tooling (confirmed by Alex) — ignore, leave as-is, do not
-- document or maintain further in this repo.
```

**`Templates`, `BookCategories`, and `Bookshelf` are not documentation cruft — `WebServer.kt`
actively depends on them.** Its `/pr/bs` endpoint builds a JSON "bookshelf" payload straight from
`Content` + `Bookshelf` + `BookCategories`, looks up a template named `'bookshelf'` in `Templates`,
and renders it with the Pebble template engine. More generally, any `Content` row with a non-zero
`templateId` gets its stored (decompressed) content run through the matching row in `Templates` as
a Pebble template before being served. This is a real, current feature of the shipped server, not
a placeholder.

**Nothing that currently builds or writes to the database in this repository knows about any of
that — and that's expected.** `Templates`/`Bookshelf`/`BookCategories` are populated by a separate
plugin system, not by anything in this repo: App Dev For All supports plugins that write into the
documentation database, including the bookshelf feature specifically —
[appdevforall/bookshelf-plugin](https://github.com/appdevforall/bookshelf-plugin). So the absence
of any `Templates`/`Bookshelf`/`BookCategories` handling here is not a gap to fill; it's out of
scope for this repo. (A repo-wide search for `templateId`, `Templates`, `Bookshelf`,
`BookCategories`, or `PUCC` turns up zero matches outside `WebServer.kt` itself, which is
consistent with that division of responsibility.) Concretely, relative to the schema above:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking — this claim is false as of the commit that adds it, and it's load-bearing.

The parenthetical asserts a repo-wide search for templateId "turns up zero matches outside WebServer.kt", and the surrounding sentence uses that to conclude the concern "is not a gap to fill; it's out of scope for this repo."

But this same commit adds populate_db.py, which references templateId at lines 87, 98, 145, 261, 266, 276 and 286 — including the actual insert:

INSERT INTO Content (path, languageID, content, contentTypeID, templateId) VALUES (...)

and insert_optimized_media.py, which filters on it at lines 214-215 and 256 (... WHERE ... AND templateId != 0). sync_kdoc_json_to_db.py:13 mentions it too.

So the grep this sentence invites the reader to trust returns numerous in-repo hits the moment this PR lands.

What makes this worth blocking rather than a doc nit: CLAUDE.md exists to orient future readers and agents, and this isn't a stale aside — the false premise is used to justify a scope boundary. An agent reading this will conclude the repo doesn't touch templateId and may "helpfully" strip it from exactly the INSERT that needs it.

Suggest either dropping the parenthetical or narrowing it to the Templates/Bookshelf/BookCategories/PUCC names, which I did not find outside WebServer.kt.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 66da59d - dropped templateId from the "zero matches outside WebServer.kt" list, keeping only Templates, Bookshelf, BookCategories, PUCC (the names that actually are absent), and added a clarifying note that populate_db.py/insert_optimized_media.py do read/write templateId directly since it's a plain column on Content they populate.


| Piece | What it thinks the schema is | Consequence |
| --- | --- | --- |
| `scripts/DocumentationDatabase.py` (used by `scripts/ingest.py`, and hence by `.github/workflows/publish-doc-db.yaml`) | `Content` / `Languages` / `ContentTypes` only, plus an optional `ide_tooltip_table`. Its constructor explicitly **raises `ValueError`** if it opens a DB containing any table outside that whitelist. | **This will refuse to open the current production `documentation.db` at all** — it will list `Tooltips`, `TooltipCategories`, `TooltipButtons`, `TooltipButtonNumbers`, `LastChange`, `Templates`, `BookCategories`, `Bookshelf`, and every `PUCC_*` table as "unexpected." This is the single biggest blocker to reusing this script as-is. |
| `docdb-studio/SCHEMA.md` / `AGENTS.md` (states the schema is "locked," no migrations) | `Content` (no `templateId`, no `UNIQUE(path)`), `Tooltips`, `TooltipButtons`, `TooltipCategories`, `TooltipButtonNumbers`, `LastChange` (with a *different* shape: `documentationSet`/`changeTime`/`who` — this part does match current), plus a legacy `ide_tooltip_table`. Missing `templateId`, `Templates`, `BookCategories`, `Bookshelf`, `PUCC_*`. | Closest of the three documented schemas to reality, but still out of date. `docdb_studio.py`'s own "never change the schema" policy is itself now stale, since the live schema has already changed underneath it. |
| `check-tools/README.md`'s embedded schema (and by extension the mental model behind `check-tools/db_health_checker.py`) | `Content` (no `templateId`, no `UNIQUE(path)`), `Tooltips`, `TooltipButtons`, `TooltipCategories`, `TooltipButtonNumbers`, and a *third* variant of `LastChange` (`now`/`who`). No `Templates`/`Bookshelf`/`BookCategories`/`PUCC_*`. | The health checker's required-table check still passes (it only checks that its known tables exist, not that no others do). Since `Templates`/`Bookshelf`/`BookCategories` are out of scope for this repo (see above), this is not being treated as something to fix right now. |

There also appear to be **two unrelated tooltip storage formats** in this repo's history, and it's
worth being deliberate about which one is current:

- The **normalized** format (`Tooltips` + `TooltipCategories` + `TooltipButtons` +
`TooltipButtonNumbers`) — this is what's in the live schema above, what `docdb-studio` edits,
what `check-tools/db_health_checker.py` validates, and what `scripts/TooltipManager.py`
dumps/rebuilds via CSV.
- A **legacy flat** format, a single `ide_tooltip_table(tooltipCategory, tooltipTag,
tooltipSummary, tooltipDetail, tooltipButtons)` table (button data packed as a JSON string in
one column) — written by `scripts/tooltips.py` (`TooltipDatabase`, driven by
`scripts/import_tooltips.py` from `SourceDocs/Tooltips/tooltips.xlsx`) and by
`scripts/load_android_data.py` (fed by pickle files that `scripts/android_tooltips.py` /
`scripts/java_tooltips.py` scrape from Android/Java HTML doc trees). **`ide_tooltip_table` does
not exist in the current production schema at all.**

**`ide_tooltip_table` is officially dead (confirmed by Alex).** That means the entire chain that
targets it — `scripts/tooltips.py`, `scripts/import_tooltips.py`, `scripts/android_tooltips.py`,
`scripts/java_tooltips.py`, `scripts/android_html_page.py`, and `scripts/load_android_data.py` — is
**deprecated legacy code**. It's left in the repo for reference/history, but none of it should be
extended or relied on, and none of it writes to a table the shipped app or `docdb-studio` actually
uses. Any future Android/Java tooltip work should target the normalized `Tooltips` /
`TooltipCategories` / `TooltipButtons` / `TooltipButtonNumbers` tables instead (the same ones
`docdb-studio` and `scripts/TooltipManager.py` already use for Kotlin tooltips).

## Repository tour

- **`docdb-studio/`** — a Flet (Flutter-for-Python) desktop GUI for browsing/editing `Tooltips` /
`TooltipCategories` / `TooltipButtons` and importing `Content`. Has its own `CLAUDE.md`,
`AGENTS.md`, `SCHEMA.md`, and a real pytest suite. Actively maintained (most recent commits in
the repo touch this tool), but per the table above, its documented schema is behind the live one.
That's an accepted state, not an active problem: schema evolution happens outside
`docdb-studio` (and outside this repo, e.g. via plugins — see below), and `docdb-studio` is
expected to catch up after the fact rather than lead. Its `AGENTS.md`/`SCHEMA.md` "never migrate
the schema" language should be read as "don't migrate it from in here," not as a claim that the
schema never changes.
- **`check-tools/`** — `db_health_checker.py` (schema/integrity/referential checks against the
*old* normalized schema) plus `download_database.py`, a working Google Drive downloader
authenticated via GCP Workload Identity Federation (no long-lived keys). Wired into
`.github/workflows/docdb-regression-test.yaml`, which runs it daily against the production DB on
Drive.
- **`scripts/`** — the original CLI toolbox. Live/current: `DocumentationDatabase.py` (Content
ingestion — see whitelist issue above), `ingest.py` (thin CLI over it, used by
`publish-doc-db.yaml`), `TooltipManager.py` (CSV ⇄ normalized-Tooltips round-trip),
`create_empty_database.py`, `list_database_documents.py`. **Deprecated/dead** (target the
removed `ide_tooltip_table` — see above, kept for reference only): `tooltips.py`,
`import_tooltips.py`, `android_tooltips.py`, `java_tooltips.py`, `android_html_page.py`,
`load_android_data.py`.
- **`scripts/myServer.py`** — a minimal Python `http.server` reference implementation that predates
`WebServer.kt`. It queries a differently-cased `Documentation.db`, doesn't implement Brotli
decompression (there's a literal `TODO: Replace this function with Brotli decompression`), and
knows nothing about compression-aware content types, templates, or fragmentation. **This is not
what ships in the app** — treat it as historical/reference only, not as documentation of current
server behavior. `WebServer.kt` is the real thing.
- **`Dokka-plugin-kdoc2json/`** — on `main`, this is just a `README.md` describing the intended
design plus a flowchart image; there is no code here yet. The actual implementation (the Dokka
`JsonRenderer`/`ModelMapper`/`LinkPostProcessor` plugin, its test suite, and the
`kotlin-stdlib-docs` build scripts) exists only on the unmerged branch **`fix/ADFA-4514`**. That
branch's diff against `main` also shows it removing recent `docdb-studio` work and all of
`scripts/pdfjs/` — almost certainly because the branch was cut before those were added and hasn't
been rebased, not because it intends to delete them. **Flagged: rebase `fix/ADFA-4514` onto

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking — this section describes a branch state that is already out of date.

The text says Dokka-plugin-kdoc2json/ on main is "just a README.md describing the intended design plus a flowchart image; there is no code here yet", that the implementation "exists only on the unmerged branch fix/ADFA-4514", and flags "rebase fix/ADFA-4514 onto current main before merging". Line 183 repeats the rebase item in the decisions log.

fix/ADFA-4514 is already merged — 4c6b8aef ("Merge pull request #18 from appdevforall/fix/ADFA-4514") is on main, and git ls-tree -r main shows JsonOutputPlugin.kt, JsonRenderer.kt, ModelMapper.kt, LinkPostProcessor.kt, the test suite and the kotlin-stdlib-docs build scripts all present on main today.

So a reader is told a whole plugin implementation is missing from main and that a rebase is still outstanding, when both are resolved.

I've marked this non-blocking because it's a point-in-time note that was presumably true when drafted, and unlike the templateId claim above nothing reasons from it. But it's the kind of staleness that a repo-orientation doc is specifically supposed to avoid, and it'll mislead the next agent that reads it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 66da59d - rewrote the Dokka-plugin-kdoc2json/ bullet to describe it as merged (fix/ADFA-4514, 4c6b8aef) with the actual files present on main, and removed the now-resolved rebase item from the decisions log (was line 183).

current `main` before merging**, to avoid actually deleting that work.
- **`ProcessDocs/`** — HTML-processing pipelines that predate the "build docs as JSON" goal:
`ProcessKotlinDocs/` (turns Kotlin's HTML doc export into a self-contained HTML set + table of
contents, used by `.github/workflows/automate-kotlin.yaml`), `ProcessAndroidDevSite/`, `AndroidDocs/`
(holds `android-tooltips.pkl`, the pickle consumed by the now-deprecated `load_android_data.py`),
`ProcessPDFs/`.
- **`SourceDocs/`** — raw inputs: `KotlinDocs/html`, `JavaDocs/html` + `java_keywords.html`,
`Tooltips/tooltips.xlsx`, `KotlinDocs/kotlin-spec.pdf`.
- **`DocumentationAnalysis/`, `DocAnalysis/`, `png_optimization/`, `androidxtooltips/`** — Jupyter
notebooks and one-off scripts for doc-set size analysis, image/PNG compression experiments, and a
one-time AndroidX tooltip import (ADFA-1419). Not part of the critical build path.
- **`.github/workflows/`** — three workflows: `automate-kotlin.yaml` (tag-triggered, builds the
Kotlin HTML doc bundle as a GitHub release asset), `publish-doc-db.yaml` (tag-triggered, runs the
`scripts/ingest.py` pipeline and releases the resulting `.sqlite`), `docdb-regression-test.yaml`
(daily cron, downloads the production DB from Google Drive via WIF and runs
`check-tools/main.py` against it). None of these have any Slack integration yet.

## Decisions log

Settled with Alex on 2026-08-05, folded into the sections above; recorded here so the reasoning
isn't lost:

- `ide_tooltip_table` and everything that targets it are dead. Treat as deprecated, not as a gap.
- `Templates`/`Bookshelf`/`BookCategories` are populated by App Dev For All's plugin system
(e.g. [bookshelf-plugin](https://github.com/appdevforall/bookshelf-plugin)), not by this repo.
Not a gap to fill here.
- `PUCC_*` tables are unrelated to documentation tooling. Ignore; leave as-is.
- `fix/ADFA-4514` needs a rebase onto `main` before merge — noted above.
- `docdb-studio`'s schema is expected to lag the live schema and catch up after the fact; that's
fine, no urgent update needed.
- `check-tools/db_health_checker.py` is not being extended with `Templates`/`Bookshelf` checks
right now — deliberately out of scope for the moment.

The one piece of this document that still describes an *active* problem rather than a settled
scope boundary is `scripts/DocumentationDatabase.py`'s hard failure on unrecognized tables (see the
table above) — that will need to be addressed before `scripts/ingest.py` /
`publish-doc-db.yaml` can run against a current-schema database.
95 changes: 95 additions & 0 deletions Dokka-plugin-kdoc2json/scripts/kotlin/build-stdlib-json-docs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# Builds the kotlin-stdlib/kotlin-test/kotlin-reflect API docs as JSON via the
# kdoc-to-json Dokka plugin, against a full kotlin/ (https://github.com/JetBrains/kotlin)
# repo checkout - freshly compiling and publishing the plugin from source
# first, so every run picks up whatever's currently in
# Dokka-plugin-kdoc2json/kdoc-to-json/src, not a jar left over from an
# earlier run.
#
# Only generates the JSON output (dokkaGenerateModuleJson), not the default
# HTML - JSON/latest/all-libs is the only thing this project's pipeline
# (sync_kdoc_json_to_db.py) consumes. Use build-kotlin-stdlib.sh directly,
# against libraries/tools/kotlin-stdlib-docs, if you also want the HTML
# comparison output that test_kotlin_stdlib.sh checks against.
#
# The target kotlin-stdlib-docs project's build.gradle.kts is swapped out
# for this directory's own (JSON-plugin-enabled) copy for the duration of
# the build, then restored automatically on exit - the kotlin checkout is
# left exactly as it was found, whether the build succeeds or fails.
#
# Only the final output path is written to stdout; every other message goes
# to stderr, so this composes as:
# STDLIB_ALL_LIBS="$(build-stdlib-json-docs.sh <kotlin-repo-root>)"
set -euo pipefail

log() { echo "$@" >&2; }

if [ $# -lt 1 ]; then
log "Usage: $0 <path-to-kotlin-repo-root> [output-dir]"
exit 1
fi

KOTLIN_ROOT="$(cd "$1" && pwd)"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_DIR="$(cd "$SCRIPT_DIR/../../kdoc-to-json" && pwd)"
STDLIB_DOCS_DIR="$KOTLIN_ROOT/libraries/tools/kotlin-stdlib-docs"
OUTPUT_ROOT="$(mkdir -p "${2:-$SCRIPT_DIR/build-output}" && cd "${2:-$SCRIPT_DIR/build-output}" && pwd)"
JSON_OUTPUT_DIR="$OUTPUT_ROOT/json"

if [ ! -f "$KOTLIN_ROOT/gradle.properties" ]; then
log "error: '$KOTLIN_ROOT' doesn't look like a kotlin repo checkout (missing gradle.properties)."
exit 1
fi
if [ ! -f "$STDLIB_DOCS_DIR/settings.gradle.kts" ] || [ ! -x "$STDLIB_DOCS_DIR/gradlew" ]; then
log "error: '$STDLIB_DOCS_DIR' doesn't look like a kotlin-stdlib-docs project (missing settings.gradle.kts or gradlew)."
exit 1
fi
if [ ! -x "$PLUGIN_DIR/gradlew" ]; then
log "error: kdoc-to-json plugin project not found at '$PLUGIN_DIR' (missing gradlew)."
exit 1
fi

# The JSON-plugin-enabled build.gradle.kts we're about to install reads
# dokka_version as a plain Gradle project property (-Pdokka_version=...)
# rather than through this repo's own version catalog, so it has to be
# supplied explicitly - pulled from the same catalog entry the rest of the
# kotlin repo's Dokka usage is pinned to, so it never drifts out of sync.
DOKKA_VERSION="$(grep -m1 '^dokka[[:space:]]*=' "$KOTLIN_ROOT/gradle/libs.versions.toml" | sed -E 's/^dokka[[:space:]]*=[[:space:]]*"([^"]*)".*/\1/')"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F11 · medium

Under set -euo pipefail (L49), this command substitution kills the script when grep matches nothing — so the friendly if [ -z "$DOKKA_VERSION" ] message at L107-110 is dead code and can never print.

A kotlin ref that renames the dokka catalog key fails "Step 4/5" with exit 1 and zero diagnostic output. Appending || true, or splitting the grep and sed into separate steps, restores the intended message.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d9df0f0 — || true on the substitution, so the if [ -z "$DOKKA_VERSION" ] message below is now reachable instead of the script dying with exit 1 and no output.

if [ -z "$DOKKA_VERSION" ]; then
log "error: couldn't find a 'dokka = \"...\"' entry in $KOTLIN_ROOT/gradle/libs.versions.toml"
exit 1
fi

log "==> [1/2] Building and publishing a fresh copy of the kdoc-to-json plugin..."
# Sent to stderr (fd 2), not left on stdout - a caller doing
# STDLIB_ALL_LIBS="$(build-stdlib-json-docs.sh ...)" must only capture the
# final path this script echoes, not gradlew's own build console output.
( cd "$PLUGIN_DIR" && ./gradlew clean publishToMavenLocal ) >&2

log "==> Installing kdoc-to-json-enabled build.gradle.kts into $STDLIB_DOCS_DIR"
ORIGINAL_BUILD_GRADLE="$(mktemp)"
cp "$STDLIB_DOCS_DIR/build.gradle.kts" "$ORIGINAL_BUILD_GRADLE"
restore_build_gradle() {
cp "$ORIGINAL_BUILD_GRADLE" "$STDLIB_DOCS_DIR/build.gradle.kts"
rm -f "$ORIGINAL_BUILD_GRADLE"
}
trap restore_build_gradle EXIT

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F12 · medium

trap ... EXIT doesn't fire on an untrapped fatal signal, which contradicts the header's promise at L15-18 that "the kotlin checkout is left exactly as it was found."

Ctrl-C during the multi-hour Gradle build leaves the swapped-in build.gradle.kts sitting in the developer's kotlin clone and orphans the mktemp original. trap restore_build_gradle EXIT INT TERM HUP covers it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d9df0f0 — trap restore_build_gradle EXIT INT TERM HUP, so the header's promise that the checkout is left exactly as found now holds for Ctrl-C during the Gradle build.

cp "$SCRIPT_DIR/build.gradle.kts" "$STDLIB_DOCS_DIR/build.gradle.kts"

log "==> [2/2] Generating JSON documentation via kdoc-to-json (dokka $DOKKA_VERSION)..."
# --refresh-dependencies forces Gradle to re-resolve the just-published
# SNAPSHOT jar from mavenLocal() rather than serving a same-GAV copy it
# cached from an earlier run of this same script.
( cd "$STDLIB_DOCS_DIR" && ./gradlew dokkaGenerateModuleJson \
"-PdocsBuildDir=$JSON_OUTPUT_DIR" \
"-Pdokka_version=$DOKKA_VERSION" \
--refresh-dependencies ) >&2

ALL_LIBS_DIR="$JSON_OUTPUT_DIR/latest/all-libs"
if [ ! -d "$ALL_LIBS_DIR" ]; then
log "error: expected output at '$ALL_LIBS_DIR' but it wasn't created."
exit 1
fi

log "==> Done."
echo "$ALL_LIBS_DIR"
Loading