Skip to content

Commit 2a83b19

Browse files
jyjeanneJeremy Jeanne
andauthored
Improve Gradle 9 compatibility (#658)
Co-authored-by: Jeremy Jeanne <jeremy.jeanne@4dconcept.fr> Signed-off-by: Jeremy Jeanne <jeremy.jeanne@4dconcept.fr>
1 parent cdec7b9 commit 2a83b19

File tree

2 files changed

+172
-82
lines changed

2 files changed

+172
-82
lines changed

build.gradle

Lines changed: 171 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,101 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
dependencies {
6+
classpath 'net.sf.saxon:Saxon-HE:10.6'
7+
}
8+
}
9+
110
plugins {
211
id 'io.github.jyjeanne.dita-ot-gradle' version '2.3.2'
3-
id 'com.github.eerohele.saxon-gradle' version '0.9.0-beta4'
12+
// Removed: 'com.github.eerohele.saxon-gradle' - not Configuration Cache compatible
13+
// Replaced with: inline XsltTransformTask class below
414
}
515

6-
// Specify Saxon version per https://github.com/eerohele/saxon-gradle/blob/master/README.md
16+
import org.gradle.api.DefaultTask
17+
import org.gradle.api.file.RegularFileProperty
18+
import org.gradle.api.provider.MapProperty
19+
import org.gradle.api.tasks.*
20+
import net.sf.saxon.s9api.Processor
21+
import net.sf.saxon.s9api.QName
22+
import net.sf.saxon.s9api.XdmAtomicValue
23+
import javax.xml.transform.stream.StreamSource
24+
25+
/**
26+
* Gradle 9 compatible XSLT transformation task using Saxon-HE.
27+
* Replaces eerohele/saxon-gradle which is not Configuration Cache compatible.
28+
*/
29+
@CacheableTask
30+
abstract class XsltTransformTask extends DefaultTask {
31+
32+
@InputFile
33+
@PathSensitive(PathSensitivity.RELATIVE)
34+
abstract RegularFileProperty getInputFile()
35+
36+
@InputFile
37+
@PathSensitive(PathSensitivity.RELATIVE)
38+
abstract RegularFileProperty getStylesheetFile()
39+
40+
@OutputFile
41+
abstract RegularFileProperty getOutputFile()
42+
43+
@Input
44+
@Optional
45+
abstract MapProperty<String, String> getParameters()
46+
47+
@TaskAction
48+
void transform() {
49+
def inputPath = inputFile.get().asFile
50+
def stylesheetPath = stylesheetFile.get().asFile
51+
def outputPath = outputFile.get().asFile
52+
53+
try {
54+
outputPath.parentFile?.mkdirs()
55+
56+
def processor = new Processor(false)
57+
def compiler = processor.newXsltCompiler()
58+
def executable = compiler.compile(new StreamSource(stylesheetPath))
59+
def transformer = executable.load30()
60+
61+
def params = parameters.getOrElse([:])
62+
if (!params.isEmpty()) {
63+
params.each { name, value ->
64+
transformer.setStylesheetParameters(
65+
Collections.singletonMap(new QName(name), new XdmAtomicValue(value))
66+
)
67+
}
68+
}
769

8-
repositories {
9-
mavenCentral()
10-
}
70+
transformer.transform(new StreamSource(inputPath), processor.newSerializer(outputPath))
71+
logger.lifecycle("Generated: ${outputPath.name}")
72+
} catch (Exception e) {
73+
throw new GradleException("XSLT transformation failed: ${inputPath.name} -> ${outputPath.name}\n" +
74+
"Stylesheet: ${stylesheetPath.name}\n" +
75+
"Cause: ${e.message}", e)
76+
}
77+
}
1178

12-
configurations {
13-
saxon
14-
}
79+
// DSL methods for backward compatibility with saxon-gradle syntax
80+
// Using layout API for Configuration Cache compatibility
81+
void input(Object path) {
82+
inputFile.set(project.layout.projectDirectory.file(path.toString()))
83+
}
84+
85+
void output(Object path) {
86+
outputFile.set(project.layout.projectDirectory.file(path.toString()))
87+
}
1588

16-
dependencies {
17-
// Use Saxon-HE 10.6 like DITA-OT, instead of the version that comes with `saxon-gradle`
18-
saxon 'net.sf.saxon:Saxon-HE:10.6'
89+
void stylesheet(Object path) {
90+
stylesheetFile.set(project.layout.projectDirectory.file(path.toString()))
91+
}
92+
93+
void parameters(Map<String, String> params) {
94+
parameters.putAll(params)
95+
}
1996
}
2097

2198
import com.github.jyjeanne.DitaOtTask
22-
import com.github.eerohele.SaxonXsltTask
23-
import org.gradle.process.ExecOperations
2499

25100
def getPropertyOrDefault(String name, def defaultValue) {
26101
providers.gradleProperty(name).getOrElse(defaultValue)
@@ -33,29 +108,40 @@ String ditaHome = getPropertyOrDefault('ditaHome', layout.projectDirectory.asFil
33108
String ditaHomeSrc = getPropertyOrDefault('ditaHomeSrc', ditaHome)
34109
String configDir = "${ditaHomeSrc}/config"
35110
String ditavalFile = "${projectDirPath}/platform.ditaval"
36-
Boolean toolkitBuild = file("${projectDirPath}/../lib/dost.jar").exists()
111+
112+
// Defer file existence check for Configuration Cache compatibility
113+
Boolean toolkitBuild = providers.provider {
114+
file("${projectDirPath}/../lib/dost.jar").exists()
115+
}.get()
116+
37117
String samplesDir = toolkitBuild ? "${ditaHome}/docsrc/samples" : "${projectDirPath}/samples"
38118
String outputDir = getPropertyOrDefault('outputDir', toolkitBuild ? "${ditaHome}/doc" : "${projectDirPath}/out")
39119

40120
String toURI(String path) {
41121
file(path).toURI().toString()
42122
}
43123

44-
task messages(type: SaxonXsltTask) {
124+
task messages(type: XsltTransformTask) {
125+
group = 'generation'
126+
description = 'Generate error messages documentation from DITA-OT config.'
45127
input "${configDir}/messages.xml"
46128
output "${projectDirPath}/topics/error-messages.xml"
47129
stylesheet "${projectDirPath}/resources/messages.xsl"
48130
}
49131

50-
task params(type: SaxonXsltTask) {
132+
task params(type: XsltTransformTask) {
133+
group = 'generation'
134+
description = 'Generate parameters documentation from DITA-OT plugins config.'
51135
input "${configDir}/plugins.xml"
52136
output "${projectDirPath}/parameters/all-parameters.dita"
53137
stylesheet "${projectDirPath}/resources/params.xsl"
54138
parameters('output-dir.url': toURI('parameters'))
55139
outputs.dir "${projectDirPath}/parameters"
56140
}
57141

58-
task extensionPoints(type: SaxonXsltTask) {
142+
task extensionPoints(type: XsltTransformTask) {
143+
group = 'generation'
144+
description = 'Generate extension points documentation from DITA-OT plugins config.'
59145
input "${configDir}/plugins.xml"
60146
output "${projectDirPath}/extension-points/all-extension-points.dita"
61147
stylesheet "${projectDirPath}/resources/extension-points.xsl"
@@ -64,17 +150,16 @@ task extensionPoints(type: SaxonXsltTask) {
64150
}
65151

66152
task generatePlatformFilter {
153+
group = 'generation'
154+
description = 'Generate platform-specific DITAVAL filter file.'
67155
def outputFile = layout.projectDirectory.file(ditavalFile)
68156
outputs.file(outputFile)
69157

70158
doLast {
71-
// Use Gradle's built-in OS detection instead of Ant
72-
def platformName = 'unix' // default
73-
if (org.gradle.internal.os.OperatingSystem.current().isWindows()) {
74-
platformName = 'windows'
75-
} else if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
76-
platformName = 'mac'
77-
}
159+
// Use System properties for OS detection (public API)
160+
def osName = System.getProperty('os.name').toLowerCase()
161+
def platformName = osName.contains('win') ? 'windows' :
162+
osName.contains('mac') ? 'mac' : 'unix'
78163

79164
// Generate the ditaval file using modern Gradle file operations
80165
outputFile.asFile.text = """<?xml version="1.0" encoding="UTF-8"?>
@@ -86,69 +171,75 @@ task generatePlatformFilter {
86171
}
87172
}
88173

89-
task generatePropertiesTemplate(type: SaxonXsltTask) {
174+
task generatePropertiesTemplate(type: XsltTransformTask) {
175+
group = 'generation'
176+
description = 'Generate properties template file from DITA-OT plugins config.'
90177
input "${configDir}/plugins.xml"
91178
output "${samplesDir}/properties/template.properties"
92179
stylesheet "${projectDirPath}/resources/properties-file.xsl"
93180
}
94181

95182
task autoGenerate(dependsOn: [messages, params, extensionPoints, generatePlatformFilter, generatePropertiesTemplate]) {
183+
group = 'generation'
96184
description = 'Run tasks that generate content from resource files and the build environment.'
97185
}
98186

99187
task pdf(type: DitaOtTask, dependsOn: autoGenerate) {
188+
group = 'documentation'
189+
description = 'Build PDF documentation.'
100190
// Set DITA-OT directory: pass as parameter -PditaHome or fall back to parent when run in core repo.
101191
ditaOt file(findProperty('ditaHome') ?: ditaHome)
102192
input "${projectDirPath}/userguide-book.ditamap"
103193
output outputDir
104194
transtype 'pdf'
105195
filter "${projectDirPath}/resources/pdf.ditaval"
106196

107-
properties {
108-
property(name: 'args.chapter.layout', value: 'BASIC')
109-
property(name: 'args.gen.task.lbl', value: 'YES')
110-
property(name: 'include.rellinks', value: '#default external')
111-
property(name: 'outputFile.base', value: 'userguide')
112-
property(name: 'theme', value: "${projectDirPath}/samples/themes/dita-ot-docs-theme.yaml")
113-
}
197+
// Use ditaProperties MapProperty directly for v2.3.0 compatibility
198+
ditaProperties.put('args.chapter.layout', 'BASIC')
199+
ditaProperties.put('args.gen.task.lbl', 'YES')
200+
ditaProperties.put('include.rellinks', '#default external')
201+
ditaProperties.put('outputFile.base', 'userguide')
202+
ditaProperties.put('theme', "${projectDirPath}/samples/themes/dita-ot-docs-theme.yaml")
114203
}
115204

116205
task html(type: DitaOtTask, dependsOn: autoGenerate) {
206+
group = 'documentation'
207+
description = 'Build HTML5 documentation.'
117208
// Set DITA-OT directory: pass as parameter -PditaHome or fall back to parent when run in core repo.
118209
ditaOt file(findProperty('ditaHome') ?: ditaHome)
119210
input "${projectDirPath}/userguide.ditamap"
120211
output outputDir
121212
transtype 'html5'
122213
filter "${projectDirPath}/resources/html.ditaval"
123214

124-
properties {
125-
property(name: 'args.copycss', value: 'yes')
126-
property(name: 'args.css', value: 'dita-ot-doc.css')
127-
property(name: 'args.csspath', value: 'css')
128-
property(name: 'args.cssroot', value: "${projectDirPath}/resources/")
129-
property(name: 'args.gen.task.lbl', value: 'YES')
130-
property(name: 'args.hdr', value: "${projectDirPath}/resources/header.xml")
131-
property(name: 'args.rellinks', value: 'noparent')
132-
property(name: 'html5.toc.generate', value: 'no')
133-
property(name: 'nav-toc', value: 'partial')
134-
}
215+
// Use ditaProperties MapProperty directly for v2.3.0 compatibility
216+
ditaProperties.put('args.copycss', 'yes')
217+
ditaProperties.put('args.css', 'dita-ot-doc.css')
218+
ditaProperties.put('args.csspath', 'css')
219+
ditaProperties.put('args.cssroot', "${projectDirPath}/resources/")
220+
ditaProperties.put('args.gen.task.lbl', 'YES')
221+
ditaProperties.put('args.hdr', "${projectDirPath}/resources/header.xml")
222+
ditaProperties.put('args.rellinks', 'noparent')
223+
ditaProperties.put('html5.toc.generate', 'no')
224+
ditaProperties.put('nav-toc', 'partial')
135225
}
136226

137227
task htmlhelp(type: DitaOtTask, dependsOn: autoGenerate) {
228+
group = 'documentation'
229+
description = 'Build HTML Help (.chm) documentation.'
138230
// Set DITA-OT directory: pass as parameter -PditaHome or fall back to parent when run in core repo.
139231
ditaOt file(findProperty('ditaHome') ?: ditaHome)
140232
input "${projectDirPath}/userguide.ditamap"
141233
output outputDir
142234
transtype 'htmlhelp'
143235
filter ditavalFile
144236

145-
properties {
146-
property(name: 'args.copycss', value: 'yes')
147-
property(name: 'args.css', value: 'dita-ot-doc.css')
148-
property(name: 'args.csspath', value: 'css')
149-
property(name: 'args.cssroot', value: "${projectDirPath}/resources/")
150-
property(name: 'args.gen.task.lbl', value: 'YES')
151-
}
237+
// Use ditaProperties MapProperty directly for v2.3.0 compatibility
238+
ditaProperties.put('args.copycss', 'yes')
239+
ditaProperties.put('args.css', 'dita-ot-doc.css')
240+
ditaProperties.put('args.csspath', 'css')
241+
ditaProperties.put('args.cssroot', "${projectDirPath}/resources/")
242+
ditaProperties.put('args.gen.task.lbl', 'YES')
152243

153244
doLast {
154245
// Move .chm files using modern Gradle file operations
@@ -165,67 +256,66 @@ task htmlhelp(type: DitaOtTask, dependsOn: autoGenerate) {
165256
}
166257
}
167258

168-
task cleanUp {
259+
task cleanOutput {
260+
group = 'build'
261+
description = 'Delete the output directory.'
169262
doLast {
170263
delete outputDir
171264
}
172265
}
173266

174-
// Get git commit hash at configuration time for tasks that need it
175-
def getGitCommitHash() {
176-
try {
177-
def result = new ByteArrayOutputStream()
178-
exec {
179-
workingDir = layout.projectDirectory.asFile
180-
commandLine 'git', 'rev-parse', 'HEAD'
181-
standardOutput = result
182-
ignoreExitValue = true
183-
}
184-
return result.toString().trim()
185-
} catch (Exception e) {
186-
logger.warn("Could not get git commit hash: ${e.message}")
187-
return 'unknown'
188-
}
189-
}
190-
191-
// Store git commit for use by tasks
192-
def gitCommitHash = getGitCommitHash()
267+
// Get git commit hash using Gradle 9 compatible Provider API
268+
// Uses providers.exec() instead of deprecated project.exec()
269+
def gitCommitHash = providers.exec {
270+
commandLine 'git', 'rev-parse', 'HEAD'
271+
ignoreExitValue = true
272+
}.standardOutput.asText.map { it.trim() }.getOrElse('unknown')
193273

194274
task gitMetadata {
275+
group = 'build'
276+
description = 'Log git commit metadata.'
195277
// This task just logs the git commit for reference
196278
doLast {
197-
logger.info("Git commit: ${gitCommitHash}")
279+
logger.lifecycle("Git commit: ${gitCommitHash}")
198280
}
199281

200282
// Mark outputs to help with up-to-date checking
201283
outputs.upToDateWhen { false } // Always run since git commit changes frequently
202284
}
203285

204286
task site(type: DitaOtTask) {
287+
group = 'documentation'
288+
description = 'Build website documentation.'
205289
dependsOn 'messages', 'params', 'extensionPoints', 'gitMetadata'
206290

207291
// Set DITA-OT directory: pass as parameter -PditaHome or fall back to parent when run in core repo.
208292
ditaOt file(findProperty('ditaHome') ?: ditaHome)
209293
input file("${projectDirPath}/site.ditamap")
210-
output getPropertyOrDefault('outputDir', "${buildDir}/site")
294+
output getPropertyOrDefault('outputDir', layout.buildDirectory.dir("site").get().asFile.path)
211295
filter "${projectDirPath}/resources/site.ditaval"
212296

213297
transtype 'org.dita-ot.html'
214298

215299
// Evaluate the noCommitMeta flag at configuration time
216300
def includeCommitMeta = !providers.gradleProperty('noCommitMeta').map { Boolean.parseBoolean(it) }.getOrElse(false)
217301

218-
properties {
219-
property(name: 'args.gen.task.lbl', value: 'YES')
220-
property(name: 'args.rellinks', value: 'noparent')
221-
if (includeCommitMeta) {
222-
// Use the git commit hash obtained at configuration time
223-
property(name: 'commit', value: gitCommitHash)
224-
}
302+
// Use ditaProperties MapProperty directly for v2.3.0 compatibility
303+
ditaProperties.put('args.gen.task.lbl', 'YES')
304+
ditaProperties.put('args.rellinks', 'noparent')
305+
if (includeCommitMeta) {
306+
// Use the git commit hash obtained at configuration time
307+
ditaProperties.put('commit', gitCommitHash)
225308
}
226309
}
227310

228-
task all(dependsOn: [pdf, html, htmlhelp])
229-
task dist(dependsOn: [pdf, html])
311+
task all(dependsOn: [pdf, html, htmlhelp]) {
312+
group = 'documentation'
313+
description = 'Build all documentation formats (PDF, HTML, HTMLHelp).'
314+
}
315+
316+
task dist(dependsOn: [pdf, html]) {
317+
group = 'documentation'
318+
description = 'Build distribution documentation (PDF and HTML).'
319+
}
230320

231321
defaultTasks 'dist'

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

0 commit comments

Comments
 (0)