Docs: remove Go patch requirement; all features work with asset-only deploy

Commit 4b53dfe replaced the Go goldmark extension with JS text-node
linkification, making bare ifc:// URL rendering work entirely client-side.
No Forgejo rebuild is needed for any feature.

- Remove "Optional: Go patch" section from README.md
- Remove Go tests from Development section
- Update forgejo/README.md feature table, prerequisites, and deploying sections
- Remove "Applying the patch", "Configuration" (PREVIEW_SERVICE_URL), and
  "Upgrading Forgejo" (Go-specific steps) sections from forgejo/README.md
- Update forgejo/SETUP_LOCAL.md: bare URLs now work; remove Step 6 (app.ini)
- Delete forgejo/go.patch (dead code — ifc_url.go was removed in 4b53dfe)
- Add underscore caveat note wherever bare URL support is described

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bruno Postle 2026-05-17 11:28:38 +01:00
parent 8cbbf95333
commit 8facdaca34
5 changed files with 33 additions and 190 deletions

View file

@ -120,6 +120,6 @@
{"id":"ifcurl-vam","title":"Phase 6: Bonsai offer ifc:// URL when saving linked model reference","description":"When saving an IFCDOCUMENTREFERENCE in Bonsai, offer the option to write the location as an ifc:// URL rather than a relative path. When a relative path would traverse above the repository root, prompt the user to convert it to an ifc:// URL. Requires Phase 4 federation (ifcurl-bqt).","status":"deferred","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-23T05:49:16Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:15:13Z","defer_until":"2026-12-01T00:00:00Z","dependencies":[{"issue_id":"ifcurl-vam","depends_on_id":"ifcurl-bqt","type":"blocks","created_at":"2026-04-23T06:49:23Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-9k2","title":"Phase 5: IFC Viewer integration (equivalent of Phase 4)","description":"Add ifc:// OS protocol handler and 'Copy view URL' button to the IFC Viewer desktop application, equivalent to the Bonsai Phase 4 integration. Depends on Phase 4 being complete as a reference implementation.","status":"deferred","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-23T05:49:08Z","created_by":"Bruno Postle","updated_at":"2026-04-23T06:15:12Z","defer_until":"2026-12-01T00:00:00Z","dependencies":[{"issue_id":"ifcurl-9k2","depends_on_id":"ifcurl-0oj","type":"blocks","created_at":"2026-04-23T06:49:14Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"id":"ifcurl-prc","title":"Phase 3c: 3D diff view for IFC PR merges","description":"After a PR merge completes, surface a 'View merge in 3D' button using the Phase 3b viewer. Use @thatopen/components highlighter to colour added, removed, and modified elements differently, driven by comparing the merged IFC against either parent. Requires Phase 3b viewer (ifcurl-i1s) to be working.","status":"closed","priority":4,"issue_type":"feature","owner":"bruno@postle.net","created_at":"2026-04-23T05:48:30Z","created_by":"Bruno Postle","updated_at":"2026-04-26T17:15:07Z","closed_at":"2026-04-26T17:15:07Z","close_reason":"Rendered diff already implemented in footer.tmpl Case 3; static PNG via /render_diff endpoint, not interactive 3D","dependencies":[{"issue_id":"ifcurl-prc","depends_on_id":"ifcurl-i1s","type":"blocks","created_at":"2026-04-23T06:48:36Z","created_by":"Bruno Postle","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"_type":"memory","key":"ifcurl-service-names-are-ifcurl-api-service-and","value":"ifcurl service names are ifcurl-api.service and ifcurl-render.service (not ifcurl.service). Install path for Python package: /opt/ifcurl/lib/python3.14/site-packages/ifcurl/. Python binary: /opt/ifcurl/bin/python3."}
{"_type":"memory","key":"forgejo-build-and-deploy-procedure-go-build-c","value":"Forgejo build and deploy procedure: go build -C /home/bruno/src/forgejo -tags 'sqlite sqlite_unlock_notify' -ldflags \"-X 'forgejo.org/modules/setting.StaticRootPath=/usr/share/forgejo'\" -o /home/bruno/src/forgejo/forgejo . — then sudo cp forgejo /usr/bin/forgejo. StaticRootPath=/usr/share/forgejo. CustomPath=/var/lib/forgejo/custom. Custom templates go to /var/lib/forgejo/custom/templates/custom/ (e.g. footer.tmpl → /var/lib/forgejo/custom/templates/custom/footer.tmpl). Custom static files go to /var/lib/forgejo/custom/public/assets/ (NOT /etc/forgejo/public/assets/) and are served at /assets/*."}
{"_type":"memory","key":"ifcurl-service-names-are-ifcurl-api-service-and","value":"ifcurl service names are ifcurl-api.service and ifcurl-render.service (not ifcurl.service). Install path for Python package: /opt/ifcurl/lib/python3.14/site-packages/ifcurl/. Python binary: /opt/ifcurl/bin/python3."}
{"_type":"memory","key":"torawurl-in-viewer-url-js-must-support-github","value":"toRawUrl in viewer-url.js must support GitHub, GitLab, Forgejo/Gitea (codeberg.org, self-hosted), and localhost. Tests in forgejo/tests/viewer-url.test.js cover all four. The localhost check (http vs https) is based on host.startsWith('localhost'), so subdomain.localhost gets https."}

View file

@ -59,17 +59,12 @@ A self-contained WebGL IFC viewer (`viewer.html`) served as a Forgejo asset at `
## Forgejo integration
A set of JS assets and an optional Go patch for Forgejo. Most features work with
asset deployment only — no Forgejo rebuild required. See
[`forgejo/README.md`](forgejo/README.md) for full details, or
[`forgejo/SETUP_LOCAL.md`](forgejo/SETUP_LOCAL.md) for a self-contained local
setup on Windows using Docker.
A set of JS assets for Forgejo — all features work with asset deployment only,
no Forgejo rebuild required. See [`forgejo/README.md`](forgejo/README.md) for
full details, or [`forgejo/SETUP_LOCAL.md`](forgejo/SETUP_LOCAL.md) for a
self-contained local setup on Windows using Docker.
### Quick setup (no rebuild)
Deploy the assets and the preview service. All features work except bare
`ifc://...` text in markdown (use `[title](ifc://...)` link syntax instead, which
the viewer's Issue button produces automatically).
### Quick setup
```bash
# Deploy assets
@ -85,33 +80,15 @@ sudo cp forgejo/server-config/ifcurl-preview.service /etc/systemd/system/
sudo systemctl enable --now ifcurl-preview
```
### Optional: Go patch for bare URL rendering
### Bare `ifc://` URLs in markdown — underscore caveat
To also render bare `ifc://...` text in markdown (without `[title](...)` syntax),
apply the Go patch and rebuild Forgejo:
```bash
cp forgejo/modules/markup/markdown/ifc_url{,_test}.go /path/to/forgejo/modules/markup/markdown/
cd /path/to/forgejo && git apply /path/to/ifcurl/forgejo/go.patch
go build -tags 'sqlite sqlite_unlock_notify' \
-ldflags "-X 'forgejo.org/modules/setting.StaticRootPath=/usr/share/forgejo'" \
-o forgejo . && sudo cp forgejo /usr/bin/forgejo
```
Add to `/etc/forgejo/conf/app.ini`:
```ini
[ifcurl]
PREVIEW_SERVICE_URL = http://localhost:8000
; Optional: Forgejo API token for a read-only machine user.
; The preview service will use this token to fetch IFC files from private
; repositories on this Forgejo instance. The token is appended as a query
; parameter in the <img src> URL generated by the markdown extension, so it
; is visible in page source. Only set this on trusted private instances.
; SERVICE_TOKEN = <forgejo-api-token>
```
**Private repositories:** create a machine user with read access and set `SERVICE_TOKEN` to its API token. Alternatively, configure credentials in `~/.config/ifcurl/tokens.json` under the service user account.
Bare `ifc://` URLs in markdown (pasted without `[title](...)` syntax) are
linkified client-side by `ifcurl.js`. This works for most paths, but if the
file path or query parameters contain matched underscores (e.g. `_model_v2.ifc`),
Goldmark renders them as `<em>` tags and splits the URL — the bare form will
fail silently. Use the explicit link form `[label](ifc://...)` for any URL where
the path or parameters contain paired underscores. The viewer's **Issue** button
always generates this safe form automatically.
### Authentication in the viewer
@ -303,10 +280,6 @@ python -m pytest tests/
# JavaScript tests (Node 18+)
node --test tests/test_viewer_url.mjs
# Go tests (requires Forgejo source tree with patch applied)
cd /path/to/forgejo
go test ./modules/markup/markdown/ -run TestIfcURL -v
```
### Roadmap
@ -315,7 +288,7 @@ go test ./modules/markup/markdown/ -run TestIfcURL -v
|---|---|---|
| 1 — Python core | ✓ done | URL parsing, git fetch, render |
| 2 — Preview service | ✓ done | HTTP service with caching |
| 3 — Forgejo integration | ✓ done | Go patch, viewer, markdown extension |
| 3 — Forgejo integration | ✓ done | Viewer, JS markdown extension |
| 4 — Bonsai integration | planned | Protocol handler + "Copy view URL" |
| 5 — IFC Viewer integration | planned | Plugin for the open-source IFC Viewer |
| 6 — Federation | planned | `IFCDOCUMENTREFERENCE` cross-repo links |

View file

@ -11,18 +11,18 @@ split into two tiers by what infrastructure they require.
| Browser IFC viewer | `viewer.html` static asset | No |
| PR diff 3D render | `ifcurl.js` + ifcurl service + **Nginx proxy** | No |
| `[title](ifc://...)` links in markdown → inline preview | `ifcurl.js` + ifcurl service + **Nginx proxy** | No |
| Bare `ifc://...` text in markdown → inline preview | Go patch + `PREVIEW_SERVICE_URL` in app.ini | **Yes** |
| Bare `ifc://...` text in markdown → inline preview | `ifcurl.js` (JS text-node linkification) | No |
All features except bare-URL markdown rendering work with static asset deployment
only — no Forgejo rebuild required. `ifcurl.js` detects `<a href="ifc://...">` links
produced by Goldmark's standard link parser and replaces them with preview figures
at page load.
All features work with static asset deployment only — no Forgejo rebuild required.
`ifcurl.js` handles both `<a href="ifc://...">` links produced by Goldmark's
standard link parser and bare `ifc://...` text nodes, replacing both with preview
figures at page load.
The Go patch is needed **only** if you want bare `ifc://...` text in markdown
(without `[title](...)` syntax) to render as a preview. The Issue button in the
viewer emits `[title](ifc://...)` link syntax, so normal issue/PR workflows work
without the patch. Minimising the patch surface is deliberate — every line of Go
code must be re-verified against each Forgejo release.
**Bare URL caveat:** bare `ifc://` URLs where the path or query parameters
contain matched underscores (e.g. `_model_v2.ifc`) may be split by Goldmark's
emphasis parser before `ifcurl.js` can linkify them. Use the explicit
`[label](ifc://...)` form in those cases — the viewer's **Issue** button always
generates this safe form.
The PR diff feature requires a **reverse proxy** (e.g. Nginx) to expose the
ifcurl service at the same origin as Forgejo. This is because the diff image is
@ -37,10 +37,6 @@ deployments already sit behind Nginx for TLS termination; adding two
```
forgejo/
go.patch ← diff against Forgejo source (apply once)
modules/markup/markdown/
ifc_url.go ← new Go source file (copy into source tree)
ifc_url_test.go ← Go tests (copy into source tree)
custom/public/assets/
viewer.html ← browser IFC viewer (no rebuild needed)
viewer-url.js ← ifc:// URL parse/build/resolve logic (ES module)
@ -67,64 +63,9 @@ For a self-contained local deployment of Forgejo + ifcurl on Windows using Docke
- ifcurl API service + render service running (see [Running the preview service](#running-the-preview-service))
- Nginx (or equivalent) in front of Forgejo if PR diff images are wanted
- Forgejo source tree cloned and building cleanly (`go` 1.21+) — **only if**
markdown inline preview is wanted
The patch was written against the `v13.0` branch of Forgejo. Check which
Forgejo commit the patch was authored against with:
```bash
cd /path/to/forgejo
git log --oneline modules/markup/markdown/markdown.go | head -3
```
---
## Applying the patch
### 1. Copy new Go source files
```bash
cp forgejo/modules/markup/markdown/ifc_url.go /path/to/forgejo/modules/markup/markdown/
cp forgejo/modules/markup/markdown/ifc_url_test.go /path/to/forgejo/modules/markup/markdown/
```
### 2. Apply the diff to existing files
```bash
cd /path/to/forgejo
git apply /path/to/ifcurl/forgejo/go.patch
```
This adds one line to `modules/markup/markdown/markdown.go` and six lines to
`modules/setting/markup.go`. If the patch does not apply cleanly (e.g. after
a Forgejo upstream upgrade), the changes are small enough to apply by hand —
see `go.patch` for the exact hunks.
### 3. Run the Go tests
```bash
cd /path/to/forgejo
go test ./modules/markup/markdown/ -run TestIfcURL -v
```
All seven tests should pass before proceeding.
### 4. Build and deploy Forgejo
```bash
cd /path/to/forgejo
go build \
-tags 'sqlite sqlite_unlock_notify' \
-ldflags "-X 'forgejo.org/modules/setting.StaticRootPath=/usr/share/forgejo'" \
-o forgejo .
sudo cp forgejo /usr/bin/forgejo
sudo systemctl restart forgejo
```
Adjust build tags and `-ldflags` to match your existing Forgejo build
configuration.
No Forgejo source tree or Go toolchain is required — all features work with
static asset deployment.
---
@ -285,25 +226,6 @@ ifcurl serve --allowed-hosts localhost:3000
non-private remote hosts, which is unsafe if the service is reachable from
untrusted clients.
## Configuration
Add to `/etc/forgejo/conf/app.ini`:
```ini
[ifcurl]
PREVIEW_SERVICE_URL = http://localhost:8000
```
`PREVIEW_SERVICE_URL` is used **server-side** by Forgejo's markdown renderer to
fetch preview images when rendering ifc:// links in issue descriptions and
comments. It runs on the Forgejo server itself, so `localhost:8000` is the
right value.
If left empty, ifc:// links in markdown render as plain links with no preview
image.
---
## Nginx reverse-proxy for PR diff images
The PR diff viewer (Case 3 in `footer.tmpl`) injects `<img src="/render_diff?…">`
@ -427,13 +349,6 @@ identify `.ifc` files correctly.
## Upgrading Forgejo
After upgrading Forgejo upstream:
1. Re-apply `go.patch` (or apply the two hunks by hand if context has shifted).
2. Copy `ifc_url.go` and `ifc_url_test.go` back in — they are not modified by
upstream.
3. Run the Go tests to verify compatibility.
4. Rebuild and redeploy.
Custom assets and `footer.tmpl` do not require a rebuild and are unaffected by
Forgejo upgrades.
Custom assets (`viewer.html`, `ifcurl.js`, etc.) and `footer.tmpl` are
unaffected by Forgejo upstream upgrades — redeploy them after each asset
change and restart Forgejo once after updating `footer.tmpl`.

View file

@ -195,18 +195,6 @@ Open `http://localhost:3000` and complete the Forgejo setup wizard.
---
## Step 6 — Add ifcurl config to Forgejo
The setup wizard writes its own `app.ini` inside the container. After
completing the wizard, append the ifcurl setting and restart:
```bash
MSYS_NO_PATHCONV=1 docker exec forgejo sh -c 'printf "\n[ifcurl]\nPREVIEW_SERVICE_URL = http://ifcurl:8000\n" >> /data/gitea/conf/app.ini'
docker compose restart forgejo
```
---
## Verify the setup
Check that Forgejo is serving the ifcurl assets:
@ -228,7 +216,7 @@ You should see JavaScript, not a 404.
| PR diff 3D renders (green=added, red=removed) | Yes |
| `[label](ifc://...)` links in markdown → inline preview | Yes |
| CLI rendering (`ifcurl render "ifc://..."`) | Yes |
| Bare `ifc://...` text in markdown | No — needs Go patch + Forgejo rebuild |
| Bare `ifc://...` text in markdown | Yes (avoid paired underscores in paths — use `[label](ifc://...)` form) |
For normal workflows, use `[label](ifc://...)` link syntax — the viewer's
**Issue** button generates this format automatically.
@ -278,6 +266,5 @@ docker compose up -d
- The ifcurl service clones remote git repos as bare repos into the container's
cache on first use. Mutable refs (`@heads/`, `@HEAD`) trigger a `git fetch`
on each request; immutable refs (commit hashes, tags) use the cache as-is.
- The Go patch in the ifcurl repo was written against Forgejo v13.0. As of
this writing the latest release is v15.0.0. The patch is optional and only
needed for bare `ifc://` URL rendering in markdown.
- No Go patch or Forgejo rebuild is needed — all features including bare
`ifc://` URL rendering are handled client-side by `ifcurl.js`.

View file

@ -1,32 +0,0 @@
diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go
index 2b19e0f1c9..12be3e1c24 100644
--- a/modules/markup/markdown/markdown.go
+++ b/modules/markup/markdown/markdown.go
@@ -116,6 +116,7 @@ func SpecializedMarkdown() goldmark.Markdown {
math.NewExtension(
math.Enabled(setting.Markdown.EnableMath),
),
+ NewIfcURLExtension(),
),
goldmark.WithParserOptions(
parser.WithAttribute(),
diff --git a/modules/setting/markup.go b/modules/setting/markup.go
index 4ab9e7b2d1..862852381e 100644
--- a/modules/setting/markup.go
+++ b/modules/setting/markup.go
@@ -59,8 +59,15 @@ type MarkupSanitizerRule struct {
AllowDataURIImages bool
}
+// IfcURL holds configuration for the ifcurl preview service integration.
+var IfcURL = struct {
+ PreviewServiceURL string `ini:"PREVIEW_SERVICE_URL"`
+ ServiceToken string `ini:"SERVICE_TOKEN"`
+}{}
+
func loadMarkupFrom(rootCfg ConfigProvider) {
mustMapSetting(rootCfg, "markdown", &Markdown)
+ mustMapSetting(rootCfg, "ifcurl", &IfcURL)
MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(50000)
FilePreviewMaxLines = rootCfg.Section("markup").Key("FILEPREVIEW_MAX_LINES").MustInt(50)