Skip to content

Commit

Permalink
Add javadoc linking plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jpenilla committed Jan 28, 2024
1 parent 5ad4b62 commit fbe3b3f
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/main/kotlin/org/incendo/cloudbuildlogic/BasePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class BasePlugin : Plugin<Project> {
target.plugins.apply("net.kyori.indra.checkstyle")
target.plugins.apply(BaselineImmutables::class)
target.plugins.apply(IncludeImmutablesSources::class)
target.plugins.apply(JavadocLinksPlugin::class)

target.extensions.configure(IndraExtension::class) {
javaVersions {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.incendo.cloudbuildlogic

import org.gradle.api.DefaultTask
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.util.function.Function
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteIfExists
import kotlin.io.path.writeText

abstract class GenerateJavadocLinksFile : DefaultTask() {
@get:Input
abstract val overrides: MapProperty<String, String>

@get:OutputFile
abstract val linksFile: RegularFileProperty

@get:Internal
abstract val apiElements: SetProperty<ResolvedArtifactResult>

@get:InputFiles
@get:Optional
abstract val apiElementsFiles: ConfigurableFileCollection

@get:Input
abstract val defaultJavadocProvider: Property<String>

fun apiElements(configuration: NamedDomainObjectProvider<Configuration>) {
apiElements.set(configuration.map { it.incoming.artifacts })
apiElementsFiles.setFrom(configuration)
defaultJavadocProvider.convention("https://javadoc.io/doc/{group}/{name}/{version}")
}

@TaskAction
fun run() {
val file = linksFile.asFile.get().toPath()
file.deleteIfExists()
file.parent.createDirectories()
val output = StringBuilder()
for (resolvedArtifactResult in apiElements.sorted()) {
val id = resolvedArtifactResult.componentIdentifier() ?: continue

output.append("-link ")
val coordinates = coordinates(id)
var overridden = false
for ((c, o) in overrides.get()) {
if (coordinates.startsWith(c)) {
overridden = true
output.append(o.replaceVariables(id))
break
}
}
if (!overridden) {
output.append(defaultJavadocProvider.get().replaceVariables(id))
}
output.append('\n')
}
file.writeText(output.toString())
}

private fun String.replaceVariables(id: ModuleComponentIdentifier): String {
return replace("{group}", id.group)
.replace("{name}", id.module)
.replace("{version}", id.version)
}

private fun ResolvedArtifactResult.componentIdentifier(): ModuleComponentIdentifier? =
id.componentIdentifier as? ModuleComponentIdentifier

private fun coordinates(componentId: ModuleComponentIdentifier): String {
return StringBuilder()
.append(componentId.group)
.append(':')
.append(componentId.module)
.append(':')
.append(componentId.version)
.toString()
}

private fun Provider<Set<ResolvedArtifactResult>>.sorted(): List<ResolvedArtifactResult> = get().sortedWith(
Comparator.comparing<ResolvedArtifactResult, String> { it.id.componentIdentifier.displayName }
.thenComparing(Function { it.file.name })
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.incendo.cloudbuildlogic

import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Provider

abstract class JavadocLinksExtension {
abstract val overrides: MapProperty<String, String>

fun override(dep: ModuleDependency, link: String) {
val key = dep.group + ':' + dep.name + (dep.version?.let { ":$it" } ?: "")
overrides.put(key, link)
}

fun override(dep: Provider<out ModuleDependency>, link: String) {
override(dep.get(), link)
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/org/incendo/cloudbuildlogic/JavadocLinksPlugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.incendo.cloudbuildlogic

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.external.javadoc.StandardJavadocDocletOptions
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.register

abstract class JavadocLinksPlugin : Plugin<Project> {
override fun apply(target: Project) {
val ext = target.extensions.create("javadocLinks", JavadocLinksExtension::class)

target.plugins.withId("java") {
target.extensions.getByType(SourceSetContainer::class).configureEach {
if (apiElementsConfigurationName !in target.configurations.names) {
return@configureEach
}

val apiElementsCopy = target.configurations.register(apiElementsConfigurationName + "JavadocLinksCopy") {
extendsFrom(target.configurations.named(apiElementsConfigurationName).get())
isCanBeResolved = true
isCanBeConsumed = false
isCanBeDeclared = false
}

val linksFileTask = target.tasks.register<GenerateJavadocLinksFile>(name + "JavadocLinksFile") {
linksFile.convention(target.layout.buildDirectory.file(name))
overrides.convention(ext.overrides)
apiElements(apiElementsCopy)
}

target.tasks.maybeConfigure<Javadoc>(javadocTaskName) {
val opts = options as StandardJavadocDocletOptions
dependsOn(linksFileTask)
opts.linksFile(linksFileTask.get().linksFile.get().asFile)
}
}
}
}
}

0 comments on commit fbe3b3f

Please sign in to comment.