Implementing a new Toolchain
Although this might be a rare case, it is documented here both to explain how the current toolchains are implemented and for the potential case where someone might want to implement a new toolchain.
Architecture
A fully implemented toolchain consists of
-
Toolchain
-
Engine
-
Launcher
-
One of more formatters
The toolchain is the interface that is associated with the asciidoc.toolchains DSL part.
It is complemented by an implementation that is in an internal.toolchains package.
A toolchain interface at minimum extends the AsciidoctorToolchain interface.
An engine performs the actual work of running conversions from Asciidoc to other formats.
For AsciidoctorJ it knows how to create the instance of Asciidoctor, load the GEM paths etc. and also groups files together in make useful batches for conversion.
Engines are the abstraction layer between Gradle and the conversion technology.
A launcher is what is used by an AsciidoctorTask to run an engine.
The launcher will typically use a worker if there are classpaths involved.
Formatters are the part that has the actual logic to perform a conversion from Asciidoc to another format. In normal Asciidoctor lingo this is just a wrapper around a backend. However, for some other toolchains the concept of a backend does not exist. Downdoc is one just example. A toolchain needs at least one formatter.
Toolchains may also have extensions with them. Extensions are not a requirement for building a toolchain.
Project setup
[versions]
asciidoctorGradle = "5.1.0"
[libraries]
asciidoctorCore = { module = "org.asciidoctor:asciidoctor5-core-plugin", version.ref = "asciidoctorGradle"}
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
api(libs.asciidoctorCore)
}
Create a toolchain
TBC
Registering tasks
Tasks are only registered when a formatter is referenced in a publication. This is done because it is the only point where everything is tied together. The formatter, however, is the only piece in the puzzle that will know the correct task(s) to register. This is because it will know which toolchain it is attached to. It will also be passed to the publication that wants to use it. When registering the task(s), the output formatter will then be responsible for configuring those tasks as well