Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ import org.gradle.api.logging.Logging
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.withType
import org.jetbrains.dokka.gradle.DokkaBasePlugin
import org.jetbrains.dokka.gradle.DokkaExtension
import org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform
import org.jetbrains.dokka.gradle.internal.InternalDokkaGradlePluginApi
import org.jetbrains.dokka.gradle.internal.PluginId
import org.jetbrains.dokka.gradle.internal.PluginIds
import org.jetbrains.dokka.gradle.internal.artifactType
import java.io.File
import javax.inject.Inject
Expand All @@ -41,16 +40,6 @@ abstract class AndroidAdapter @Inject constructor(
override fun apply(project: Project) {
logger.info("applied ${this::class} to ${project.path}")

project.plugins.withType<DokkaBasePlugin>().configureEach {
project.pluginManager.apply {
withPlugin(PluginId.AndroidBase) { configure(project) }
withPlugin(PluginId.AndroidApplication) { configure(project) }
withPlugin(PluginId.AndroidLibrary) { configure(project) }
}
}
}

protected fun configure(project: Project) {
val dokkaExtension = project.extensions.getByType<DokkaExtension>()

val androidExt = AndroidExtensionWrapper(project) ?: return
Expand Down Expand Up @@ -79,7 +68,19 @@ abstract class AndroidAdapter @Inject constructor(
}

@InternalDokkaGradlePluginApi
companion object
companion object {

/**
* Apply [AndroidAdapter] a single time to [project], regardless of how many AGP plugins are applied.
*/
internal fun applyTo(project: Project) {
PluginIds.android.forEach { pluginId ->
project.pluginManager.withPlugin(pluginId) {
project.pluginManager.apply(AndroidAdapter::class)
}
}
}
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.withType
import org.jetbrains.dokka.gradle.DokkaExtension
import org.jetbrains.dokka.gradle.engine.parameters.DokkaSourceSetSpec
import org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform
import org.jetbrains.dokka.gradle.internal.InternalDokkaGradlePluginApi
import org.jetbrains.dokka.gradle.internal.PluginId
import org.jetbrains.dokka.gradle.internal.PluginIds
import org.jetbrains.dokka.gradle.internal.or
import org.jetbrains.dokka.gradle.internal.uppercaseFirstChar
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
Expand All @@ -45,16 +46,13 @@ abstract class JavaAdapter @Inject constructor(

val dokkaExtension = project.extensions.getByType<DokkaExtension>()

// wait for the Java plugin to be applied
project.plugins.withType<JavaBasePlugin>().configureEach {
val java = project.extensions.getByType<JavaPluginExtension>()
val sourceSets = project.extensions.getByType<SourceSetContainer>()
val java = project.extensions.getByType<JavaPluginExtension>()
val sourceSets = project.extensions.getByType<SourceSetContainer>()

detectJavaToolchainVersion(dokkaExtension, java)
detectJavaToolchainVersion(dokkaExtension, java)

val isConflictingPluginPresent = isConflictingPluginPresent(project)
registerDokkaSourceSets(dokkaExtension, sourceSets, isConflictingPluginPresent)
}
val isConflictingPluginPresent = isConflictingPluginPresent(project)
registerDokkaSourceSets(dokkaExtension, sourceSets, isConflictingPluginPresent)
}

/** Fetch the toolchain, and use the language version as Dokka's jdkVersion */
Expand Down Expand Up @@ -118,16 +116,11 @@ abstract class JavaAdapter @Inject constructor(
): Provider<Boolean> {

val projectHasKotlinPlugin = providers.provider {
project.pluginManager.hasPlugin(PluginId.KotlinAndroid)
|| project.pluginManager.hasPlugin(PluginId.KotlinJs)
|| project.pluginManager.hasPlugin(PluginId.KotlinJvm)
|| project.pluginManager.hasPlugin(PluginId.KotlinMultiplatform)
PluginIds.kotlin.any { project.pluginManager.hasPlugin(it) }
}

val projectHasAndroidPlugin = providers.provider {
project.pluginManager.hasPlugin(PluginId.AndroidBase)
|| project.pluginManager.hasPlugin(PluginId.AndroidApplication)
|| project.pluginManager.hasPlugin(PluginId.AndroidLibrary)
PluginIds.android.any { project.pluginManager.hasPlugin(it) }
}

return projectHasKotlinPlugin or projectHasAndroidPlugin
Expand All @@ -147,5 +140,11 @@ abstract class JavaAdapter @Inject constructor(
fun SourceSet.isPublished(): Boolean =
name != TEST_SOURCE_SET_NAME
&& name.startsWith(MAIN_SOURCE_SET_NAME)

internal fun applyTo(project: Project) {
project.plugins.withType<JavaBasePlugin>().all {
project.pluginManager.apply(type = JavaAdapter::class)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ package org.jetbrains.dokka.gradle.adapters

import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.Variant
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.*
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.logging.Logger
Expand All @@ -22,6 +19,7 @@ import org.gradle.kotlin.dsl.*
import org.jetbrains.dokka.gradle.DokkaBasePlugin
import org.jetbrains.dokka.gradle.DokkaExtension
import org.jetbrains.dokka.gradle.adapters.KotlinAdapter.Companion.currentKotlinToolingVersion
import org.jetbrains.dokka.gradle.adapters.KotlinAdapter.Companion.logKgpClassNotFoundWarning
import org.jetbrains.dokka.gradle.engine.parameters.DokkaSourceSetSpec
import org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform
import org.jetbrains.dokka.gradle.engine.parameters.SourceSetIdSpec
Expand All @@ -33,12 +31,9 @@ import org.jetbrains.kotlin.commonizer.stdlib
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataCompilation
Expand All @@ -62,17 +57,6 @@ abstract class KotlinAdapter @Inject constructor(
override fun apply(project: Project) {
logger.info("Applying $dkaName to ${project.path}")

project.plugins.withType<DokkaBasePlugin>().configureEach {
project.pluginManager.apply {
withPlugin(PluginId.KotlinAndroid) { exec(project) }
withPlugin(PluginId.KotlinJs) { exec(project) }
withPlugin(PluginId.KotlinJvm) { exec(project) }
withPlugin(PluginId.KotlinMultiplatform) { exec(project) }
}
}
}

private fun exec(project: Project) {
val kotlinExtension = project.findKotlinExtension()
if (kotlinExtension == null) {
logger.info("Skipping applying $dkaName in ${project.path} - could not find KotlinProjectExtension")
Expand Down Expand Up @@ -210,6 +194,109 @@ abstract class KotlinAdapter @Inject constructor(
val kgpVersion = getKotlinPluginVersion(logger)
KotlinToolingVersion(kgpVersion)
}

/**
* Applies [KotlinAdapter] to the current project when any plugin of type [KotlinBasePlugin]
* is applied.
*
* [KotlinBasePlugin] is the parent type for the Kotlin/JVM, Kotlin/Multiplatform, Kotlin/JS plugins,
* as well as AGP's kotlin-built-in plugin.
*/
internal fun applyTo(project: Project) {
findKotlinBasePlugins(project)?.all {
project.pluginManager.apply(KotlinAdapter::class)
}
}

/**
* Tries fetching all plugins with type [KotlinBasePlugin],
* returning `null` if the class is not available in the current classloader.
*
* (The class might not be available if the current project is a Java or Android project,
* or the buildscripts have an inconsistent classpath https://github.com/gradle/gradle/issues/27218)
*/
private fun findKotlinBasePlugins(project: Project): DomainObjectCollection<KotlinBasePlugin>? {
return try {
project.plugins.withType<KotlinBasePlugin>()
} catch (ex: Throwable) {
when (ex) {
is ClassNotFoundException,
is NoClassDefFoundError -> {
logKgpClassNotFoundWarning(
project,
kotlinBasePluginNotFoundException = ex,
)
null
}

else -> throw ex
}
}
}

/**
* Check all plugins to see if they are a subtype of [KotlinBasePlugin].
* If any are, log a warning.
*
* Also, log an info message with the stacktrace of [kotlinBasePluginNotFoundException].
*
* ##### Motivation
*
* If the buildscript classpath is inconsistent, it might not be possible for DGP
* to react to KGP because the [KotlinBasePlugin] class can't be loaded.
* If so, DGP will be lenient and not cause errors,
* but it must display a prominent warning to help users find the problem.
*
* @param[kotlinBasePluginNotFoundException] The exception thrown when [KotlinBasePlugin] is not available.
*/
private fun logKgpClassNotFoundWarning(
project: Project,
kotlinBasePluginNotFoundException: Throwable,
) {
// hide the stacktrace at `--info` log level, to avoid flooding the log
logger.info(
"Dokka Gradle Plugin could not load KotlinBasePlugin in ${project.displayName}",
kotlinBasePluginNotFoundException,
)

/**
* Keep track of which projects have been warned by [logKgpClassNotFoundWarning],
* otherwise it'll log the same warning multiple times for the same project, which is annoying.
*
* The warning can be logged multiple times if a project has both
* `org.jetbrains.dokka` and `org.jetbrains.dokka-javadoc` applied.
*/
fun checkIfAlreadyWarned(): Boolean {
val key = "DOKKA INTERNAL - projectsWithKgpClassNotFoundWarningApplied"
if (project.extra.has(key)) {
return true
} else {
project.extra.set(key, true)
return false
}
}

PluginIds.kotlin.forEach { pluginId ->
project.pluginManager.withPlugin(pluginId) {
if (checkIfAlreadyWarned()) return@withPlugin
logger.warn(
"""
|warning: Dokka could not load KotlinBasePlugin in ${project.displayName}, even though plugin $pluginId is applied.
|The most common cause is a Gradle limitation: the plugins applied to subprojects should be consistent.
|Please try the following:
|1. Apply the Dokka and Kotlin plugins to the root project using the `plugins {}` DSL.
| (If the root project does not need the plugins, use 'apply false')
|2. Remove the Dokka and Kotlin plugins versions in the subprojects.
|For more information see:
| - https://docs.gradle.org/current/userguide/plugins_intermediate.html#sec:plugins_apply
| - https://github.com/gradle/gradle/issues/25616
| - https://github.com/gradle/gradle/issues/35117
|Please report any feedback or problems https://kotl.in/dokka-issues
|""".trimMargin()
)
}
}
}
}
}

Expand Down Expand Up @@ -298,10 +385,10 @@ private class KotlinCompilationDetailsBuilder(
): Provider<Set<AndroidVariantInfo>> {
val androidVariants = objects.setProperty(AndroidVariantInfo::class)

project.pluginManager.apply {
withPlugin(PluginId.AndroidBase) { collectAndroidVariants(project, androidVariants) }
withPlugin(PluginId.AndroidApplication) { collectAndroidVariants(project, androidVariants) }
withPlugin(PluginId.AndroidLibrary) { collectAndroidVariants(project, androidVariants) }
PluginIds.android.forEach { pluginId ->
project.pluginManager.withPlugin(pluginId) {
collectAndroidVariants(project, androidVariants)
}
}

return androidVariants
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ abstract class DokkaFormatPlugin(
target.pluginManager.apply(DokkaBasePlugin::class)

// apply the plugin that will autoconfigure Dokka to use the sources of a Kotlin project
target.pluginManager.apply(type = KotlinAdapter::class)
target.pluginManager.apply(type = JavaAdapter::class)
target.pluginManager.apply(type = AndroidAdapter::class)
KotlinAdapter.applyTo(target)
AndroidAdapter.applyTo(target)
JavaAdapter.applyTo(target)

target.plugins.withType<DokkaBasePlugin>().configureEach {
val dokkaExtension = target.extensions.getByType(DokkaExtension::class)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package org.jetbrains.dokka.gradle.internal

/**
* Gradle Plugin IDs.
*/
internal object PluginIds {

val kotlin: Set<String> = setOf(
"org.jetbrains.kotlin.android",
"org.jetbrains.kotlin.js",
"org.jetbrains.kotlin.jvm",
"org.jetbrains.kotlin.multiplatform",
)

val android: Set<String> = setOf(
"com.android.base",
"com.android.application",
"com.android.library",
"com.android.test",
"com.android.dynamic-feature",
)
}
Loading
Loading