This is an automated email from the ASF dual-hosted git repository.
paulk-asert pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/groovy-website.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 08b9f3d add wire-car inspired example
08b9f3d is described below
commit 08b9f3d1e3e9cd2de55725f09e1af7e15d98f2ea
Author: Paul King <[email protected]>
AuthorDate: Tue May 26 20:08:36 2026 +1000
add wire-car inspired example
---
generator/build.gradle | 4 +++
.../src/main/groovy/generator/SiteGenerator.groovy | 39 +++++++++++++++++++---
site/src/site/pages/blog.groovy | 11 +++++-
3 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/generator/build.gradle b/generator/build.gradle
index d0a1a20..6768b51 100644
--- a/generator/build.gradle
+++ b/generator/build.gradle
@@ -41,6 +41,10 @@ dependencies {
//exclude(group: 'org.jruby', module: 'jruby-complete')
}
implementation "org.asciidoctor:asciidoctorj-diagram:$asciidoctorDiagram"
+ // asciidoctorj-diagram brings asciidoctorj-diagram-plantuml in at
+ // runtime scope (versioned per PlantUML release, e.g. 1.2023.13 for
+ // diagram 2.2.17), so [plantuml,…] blocks render without depending
+ // on an external plantuml CLI being installed on the build machine.
//compile "org.jruby:jruby-complete:9.1.17.0"
}
diff --git a/generator/src/main/groovy/generator/SiteGenerator.groovy
b/generator/src/main/groovy/generator/SiteGenerator.groovy
index fe5fd70..af644b9 100644
--- a/generator/src/main/groovy/generator/SiteGenerator.groovy
+++ b/generator/src/main/groovy/generator/SiteGenerator.groovy
@@ -30,7 +30,9 @@ import model.Page
import model.Section
import model.SectionItem
import model.SiteMap
+import org.asciidoctor.Attributes
import org.asciidoctor.Options
+import org.asciidoctor.SafeMode
import org.asciidoctor.ast.Document
import java.nio.file.FileSystems
@@ -272,12 +274,10 @@ class SiteGenerator {
Map<String, Document> blogList = [:]
Map<String, String> contents = [:]
Map<String, String> baseDirs = [:]
- def options = Options.builder().build()
+ Map<String, String> imageDirs = [:]
blogDir.eachFileRecurse { f ->
if (f.name.endsWith('.adoc')) {
def bn = f.name.substring(0, f.name.lastIndexOf('.adoc'))
- def doc = asciidoctor.loadFile(f, options)
- println "Rendering $bn"
def relativePath = []
def p = f.parentFile
while (p != blogDir) {
@@ -285,9 +285,35 @@ class SiteGenerator {
p = p.parentFile
}
String baseDir = relativePath ?
"blog${File.separator}${relativePath.join(File.separator)}" : 'blog'
+ // asciidoctor-diagram extensions fire during loadFile
+ // (parse) as well as during the later convert() call.
+ // Without imagesoutdir set here, generated images and
+ // their .cache sidecars land next to the .adoc source
+ // file. Setting it on the loadFile options keeps the
+ // source tree clean; the convert() call below also
+ // sets it (via the blog.groovy template) so the actual
+ // <img> reference resolves at output time.
+ def blogImgDir = new File(outputDir, baseDir + File.separator
+ 'img')
+ blogImgDir.mkdirs()
+ def attrs = Attributes.builder()
+ .attribute('imagesoutdir', blogImgDir.absolutePath)
+ .attribute('imagesdir', 'img')
+ .build()
+ // SafeMode.UNSAFE lets asciidoctor-diagram write to
+ // imagesoutdir even though it's outside the source-file
+ // jail. Without this, safe mode rejects the absolute
+ // path and recovers by writing the image + .cache file
+ // next to the .adoc source — polluting the source tree.
+ def options = Options.builder()
+ .safe(SafeMode.UNSAFE)
+ .attributes(attrs)
+ .build()
+ def doc = asciidoctor.loadFile(f, options)
+ println "Rendering $bn"
blogList[bn] = doc
contents[bn] = f.getText('utf-8')
baseDirs[bn] = baseDir
+ imageDirs[bn] = blogImgDir.absolutePath
}
}
Map<String, Set> keywords = [:]
@@ -307,7 +333,12 @@ class SiteGenerator {
}
blogList.keySet().each { bn ->
def sorted = related[bn].findAll { it.value as int > 1 }.sort {
it.value }.keySet().toList().reverse()
- render 'blog', bn, [notes: contents[bn], doc: blogList[bn],
related: sorted.collectEntries { [it, blogList[it].structuredDoctitle.combined]
}], baseDirs[bn]
+ render 'blog', bn, [
+ notes: contents[bn],
+ doc: blogList[bn],
+ related: sorted.collectEntries { [it,
blogList[it].structuredDoctitle.combined] },
+ imagesoutdir: imageDirs[bn]
+ ], baseDirs[bn]
}
render 'blogs', "index", [list: blogList], 'blog'
renderBlogFeed blogList, 'blog'
diff --git a/site/src/site/pages/blog.groovy b/site/src/site/pages/blog.groovy
index d66eaa1..ec88a54 100644
--- a/site/src/site/pages/blog.groovy
+++ b/site/src/site/pages/blog.groovy
@@ -6,6 +6,7 @@ modelTypes = {
String title
String notes
Map<String, String> related
+ String imagesoutdir
}
title = doc.structuredDoctitle.combined
@@ -26,7 +27,15 @@ layout 'layouts/main.groovy', true,
script { yieldUnescaped
"document.addEventListener('DOMContentLoaded',prettyPrint)" }
},
mainContent: contents {
- Map options = [attributes:[DOCS_BASEURL:DocUtils.DOCS_BASEURL]]
+ // imagesoutdir + imagesdir let asciidoctor-diagram write
+ // generated images (e.g. from [plantuml,…] blocks) into
+ // blog/img/ and emit relative `img/…` references that
+ // match the convention used for pre-rendered blog images.
+ Map options = [attributes:[
+ DOCS_BASEURL: DocUtils.DOCS_BASEURL,
+ imagesoutdir: imagesoutdir,
+ imagesdir : 'img'
+ ]]
def notesAsHTML = asciidocText(notes,options)
def matcher = notesAsHTML =~ /<h2 id="(.+?)">(.+?)<\/h2>/
def sections = [:]