aboutsummaryrefslogtreecommitdiff
path: root/runners/gradle-plugin/src
diff options
context:
space:
mode:
Diffstat (limited to 'runners/gradle-plugin/src')
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt118
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt190
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt2
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt15
4 files changed, 217 insertions, 108 deletions
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt
new file mode 100644
index 00000000..185a32fd
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt
@@ -0,0 +1,118 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.api.NamedDomainObjectCollection
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.UnknownDomainObjectException
+import org.gradle.api.file.FileCollection
+import org.gradle.api.plugins.JavaPluginConvention
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.compile.AbstractCompile
+import org.jetbrains.dokka.ReflectDsl
+import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
+import java.io.File
+import java.io.Serializable
+
+object ConfigurationExtractor {
+
+ fun extractFromSinglePlatform(project: Project): PlatformData? {
+ val target: KotlinTarget
+ try {
+ target = project.extensions.getByType(KotlinSingleTargetExtension::class.java).target
+ } catch(e: UnknownDomainObjectException) {
+ return null
+ } catch(e: NoClassDefFoundError) {
+ return null
+ } catch(e: ClassNotFoundException) {
+ return null
+ }
+
+ return try {
+ return PlatformData(null, getClasspath(target), getSourceSet(target), getPlatformName(target.platformType))
+ } catch(e: NoSuchMethodError){
+ null
+ }
+ }
+
+ fun extractFromMultiPlatform(project: Project): List<PlatformData>? {
+ val targets: NamedDomainObjectCollection<KotlinTarget>
+ try {
+ targets = project.extensions.getByType(KotlinMultiplatformExtension::class.java).targets
+ } catch(e: UnknownDomainObjectException) {
+ return null
+ } catch(e: ClassNotFoundException) {
+ return null
+ } catch(e: NoClassDefFoundError) {
+ return null
+ }
+
+ val commonTarget = targets.find { it.platformType == KotlinPlatformType.common }
+ val commonTargetCompilation = commonTarget?.compilations?.getByName("main")
+ val commonTargetSourceList = commonTargetCompilation?.allKotlinSourceSets?.flatMap { it.kotlin.sourceDirectories }
+ val commonTargetClasspath = commonTargetCompilation?.compileDependencyFiles?.files?.toList()
+
+ val platformTargets = targets.filter { it.platformType != KotlinPlatformType.common }
+
+ val config = platformTargets.map {
+ PlatformData(it.name, getClasspath(it) + commonTargetClasspath.orEmpty(),
+ getSourceSet(it) + commonTargetSourceList.orEmpty(), it.platformType.toString())
+ }
+ return config + PlatformData("common", commonTargetClasspath.orEmpty(), commonTargetSourceList.orEmpty(), "common")
+ }
+
+ fun extractFromKotlinTasks(kotlinTasks: List<Task>, project: Project): PlatformData? {
+ val allClasspath = mutableSetOf<File>()
+ var allClasspathFileCollection: FileCollection = project.files()
+ val allSourceRoots = mutableSetOf<File>()
+
+ kotlinTasks.forEach {
+ with(ReflectDsl) {
+ val taskSourceRoots: List<File> = it["sourceRootsContainer"]["sourceRoots"].v()
+ val abstractKotlinCompileClz = DokkaTask.getAbstractKotlinCompileFor(it)!!
+
+ val taskClasspath: Iterable<File> =
+ (it["getClasspath", AbstractCompile::class].takeIfIsFunc()?.invoke()
+ ?: it["compileClasspath", abstractKotlinCompileClz].takeIfIsProp()?.v()
+ ?: it["getClasspath", abstractKotlinCompileClz]())
+
+ if (taskClasspath is FileCollection) {
+ allClasspathFileCollection += taskClasspath
+ } else {
+ allClasspath += taskClasspath
+ }
+ allSourceRoots += taskSourceRoots.filter { it.exists() }
+ }
+ }
+
+ return PlatformData(null,
+ (allClasspathFileCollection + project.files(allClasspath)).toList(), allSourceRoots.toList(), ""
+ )
+ }
+
+ fun extractFromJavaPlugin(project: Project): PlatformData? =
+ project.convention.findPlugin(JavaPluginConvention::class.java)
+ ?.run { sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME)?.allSource?.srcDirs }
+ ?.let { PlatformData(null, emptyList(), it.toList(), "") }
+
+ private fun getSourceSet(target: KotlinTarget): List<File> =
+ getMainCompilation(target).allKotlinSourceSets.flatMap { it.kotlin.sourceDirectories }
+
+ private fun getClasspath(target: KotlinTarget): List<File> =
+ getMainCompilation(target).compileDependencyFiles.files.toList()
+
+ private fun getMainCompilation(target: KotlinTarget): KotlinCompilation<KotlinCommonOptions> =
+ target.compilations.getByName("main")
+
+ private fun getPlatformName(platform: KotlinPlatformType): String =
+ if (platform == KotlinPlatformType.androidJvm) "jvm" else platform.toString()
+
+ data class PlatformData(val name: String?,
+ val classpath: List<File>,
+ val sourceRoots: List<File>,
+ val platform: String) : Serializable
+} \ No newline at end of file
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt
index d4eee4b2..4a4518b9 100644
--- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt
@@ -3,14 +3,14 @@ package org.jetbrains.dokka.gradle
import com.google.gson.GsonBuilder
import groovy.lang.Closure
import org.gradle.api.DefaultTask
+import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileCollection
+import org.gradle.api.internal.plugins.DslObject
import org.gradle.api.plugins.JavaBasePlugin
-import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.*
-import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.dokka.DokkaBootstrap
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.DokkaConfiguration.SourceRoot
@@ -18,7 +18,6 @@ import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.ReflectDsl
import org.jetbrains.dokka.ReflectDsl.isNotInstance
import java.io.File
-import java.io.Serializable
import java.net.URLClassLoader
import java.util.concurrent.Callable
import java.util.function.BiConsumer
@@ -54,15 +53,6 @@ open class DokkaTask : DefaultTask() {
var dokkaRuntime: Configuration? = null
- @InputFiles
- var classpath: Iterable<File> = arrayListOf()
-
- @Input
- var sourceDirs: Iterable<File> = emptyList()
-
- @Input
- var sourceRoots: MutableList<SourceRoot> = arrayListOf()
-
@Input
var dokkaFatJar: Any = "org.jetbrains.dokka:dokka-fatjar:${DokkaVersion.version}"
@@ -76,22 +66,33 @@ open class DokkaTask : DefaultTask() {
@Input
var collectInheritedExtensionsFromLibraries: Boolean = false
- @get:Internal
- internal val kotlinCompileBasedClasspathAndSourceRoots: ClasspathAndSourceRoots by lazy { extractClasspathAndSourceRootsFromKotlinTasks() }
+ var multiplatform: NamedDomainObjectContainer<GradlePassConfigurationImpl>
+ @Suppress("UNCHECKED_CAST")
+ get() = DslObject(this).extensions.getByName(MULTIPLATFORM_EXTENSION_NAME) as NamedDomainObjectContainer<GradlePassConfigurationImpl>
+ internal set(value) = DslObject(this).extensions.add(MULTIPLATFORM_EXTENSION_NAME, value)
+
+ var configuration: GradlePassConfigurationImpl
+ @Suppress("UNCHECKED_CAST")
+ get() = DslObject(this).extensions.getByName(CONFIGURATION_EXTENSION_NAME) as GradlePassConfigurationImpl
+ internal set(value) = DslObject(this).extensions.add(CONFIGURATION_EXTENSION_NAME, value)
protected var externalDocumentationLinks: MutableList<DokkaConfiguration.ExternalDocumentationLink> = mutableListOf()
private var kotlinTasksConfigurator: () -> List<Any?>? = { defaultKotlinTasks() }
private val kotlinTasks: List<Task> by lazy { extractKotlinCompileTasks() }
+ @Deprecated("Use manual configuration of source roots or subProjects{} closure")
fun kotlinTasks(taskSupplier: Callable<List<Any>>) {
kotlinTasksConfigurator = { taskSupplier.call() }
}
+ @Deprecated("Use manual configuration of source roots or subProjects{} closure")
fun kotlinTasks(closure: Closure<Any?>) {
kotlinTasksConfigurator = { closure.call() as? List<Any?> }
}
+ @Input
+ var subProjects: List<String> = emptyList()
fun tryResolveFatJar(project: Project): Set<File> {
return try {
@@ -111,9 +112,6 @@ open class DokkaTask : DefaultTask() {
}
}
- internal data class ClasspathAndSourceRoots(val classpathFileCollection: FileCollection, val sourceRoots: List<File>) :
- Serializable
-
private fun extractKotlinCompileTasks(): List<Task> {
val inputList = (kotlinTasksConfigurator.invoke() ?: emptyList()).filterNotNull()
val (paths, other) = inputList.partition { it is String }
@@ -134,45 +132,14 @@ open class DokkaTask : DefaultTask() {
return (tasksByPath + other) as List<Task>
}
- private fun extractClasspathAndSourceRootsFromKotlinTasks(): ClasspathAndSourceRoots {
-
- val allTasks = kotlinTasks
-
- val allClasspath = mutableSetOf<File>()
- var allClasspathFileCollection: FileCollection = project.files()
- val allSourceRoots = mutableSetOf<File>()
-
- allTasks.forEach {
- logger.debug("Dokka found AbstractKotlinCompile task: $it")
- with(ReflectDsl) {
- val taskSourceRoots: List<File> = it["sourceRootsContainer"]["sourceRoots"].v()
-
- val abstractKotlinCompileClz = getAbstractKotlinCompileFor(it)!!
-
- val taskClasspath: Iterable<File> =
- (it["getClasspath", AbstractCompile::class].takeIfIsFunc()?.invoke()
- ?: it["compileClasspath", abstractKotlinCompileClz].takeIfIsProp()?.v()
- ?: it["getClasspath", abstractKotlinCompileClz]())
-
- if (taskClasspath is FileCollection) {
- allClasspathFileCollection += taskClasspath
- } else {
- allClasspath += taskClasspath
- }
- allSourceRoots += taskSourceRoots.filter { it.exists() }
- }
- }
-
- return ClasspathAndSourceRoots(allClasspathFileCollection + project.files(allClasspath), allSourceRoots.toList())
- }
-
private fun Iterable<File>.toSourceRoots(): List<GradleSourceRootImpl> = this.filter { it.exists() }.map { GradleSourceRootImpl().apply { path = it.path } }
+ private fun Iterable<String>.toProjects(): List<Project> = project.subprojects.toList().filter { this.contains(it.name) }
protected open fun collectSuppressedFiles(sourceRoots: List<SourceRoot>): List<String> = emptyList()
@TaskAction
fun generate() {
- if (dokkaRuntime == null){
+ if (dokkaRuntime == null) {
dokkaRuntime = project.configurations.getByName("dokkaRuntime")
}
@@ -181,10 +148,6 @@ open class DokkaTask : DefaultTask() {
System.setProperty(COLORS_ENABLED_PROPERTY, "false")
try {
loadFatJar()
- // TODO: implement extracting source roots from kotlin tasks
- val (_, tasksSourceRoots) = kotlinCompileBasedClasspathAndSourceRoots
-
- val sourceRoots = collectSourceRoots() + tasksSourceRoots.toSourceRoots()
val bootstrapClass = ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl")
val bootstrapInstance = bootstrapClass.constructors.first().newInstance()
@@ -193,16 +156,8 @@ open class DokkaTask : DefaultTask() {
val gson = GsonBuilder().setPrettyPrinting().create()
- val passConfigurationExtension: GradlePassConfigurationImpl = extensions.findByName(
- CONFIGURATION_EXTENSION_NAME) as GradlePassConfigurationImpl
- val passConfigurationsContainer =
- (extensions.getByName(MULTIPLATFORM_EXTENSION_NAME) as Iterable<GradlePassConfigurationImpl>).toList()
-
- passConfigurationExtension.sourceRoots.addAll(sourceRoots)
-
- val passConfigurationList =
- (if (passConfigurationsContainer.isEmpty()) listOf(passConfigurationExtension) else passConfigurationsContainer)
- .map { defaultPassConfiguration(it) }
+ val passConfigurationList = collectConfigurations()
+ .map { defaultPassConfiguration(it) }
val configuration = GradleDokkaConfigurationImpl()
configuration.outputDir = outputDirectory
@@ -230,39 +185,83 @@ open class DokkaTask : DefaultTask() {
}
}
- private fun defaultPassConfiguration(passConfig: GradlePassConfigurationImpl): GradlePassConfigurationImpl {
- val (tasksClasspath, _) = kotlinCompileBasedClasspathAndSourceRoots
-
- val fullClasspath = tasksClasspath + classpath
- passConfig.moduleName = moduleName
- passConfig.classpath = fullClasspath.map { it.absolutePath }
- passConfig.samples = passConfig.samples.map { project.file(it).absolutePath }
- passConfig.includes = passConfig.includes.map { project.file(it).absolutePath }
- passConfig.collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
- passConfig.suppressedFiles = collectSuppressedFiles(passConfig.sourceRoots)
- passConfig.externalDocumentationLinks.addAll(externalDocumentationLinks)
- if(passConfig.platform.isNotEmpty()){
- passConfig.analysisPlatform = Platform.fromString(passConfig.platform)
+ private fun collectConfigurations(): List<GradlePassConfigurationImpl> =
+ if (multiplatform.toList().isNotEmpty()) collectFromMultiPlatform() else collectFromSinglePlatform()
+
+ private fun collectFromMultiPlatform(): List<GradlePassConfigurationImpl> {
+ val baseConfig = mergeUserAndAutoConfigurations(
+ multiplatform.toList(),
+ ConfigurationExtractor.extractFromMultiPlatform(project).orEmpty()
+ )
+ return if (subProjects.isEmpty())
+ baseConfig
+ else
+ subProjects.toProjects().fold(baseConfig, { list, project ->
+ mergeUserAndAutoConfigurations(list, ConfigurationExtractor.extractFromMultiPlatform(project).orEmpty())})
+ }
+
+ private fun collectFromSinglePlatform(): List<GradlePassConfigurationImpl> {
+ val autoConfig = ConfigurationExtractor.extractFromSinglePlatform(project)
+ val baseConfig = if (autoConfig != null)
+ listOf(mergeUserConfigurationAndPlatformData(configuration, autoConfig))
+ else
+ collectFromSinglePlatformOldPlugin()
+
+ return if (subProjects.isNotEmpty()) {
+ try {
+ subProjects.toProjects().fold(baseConfig, { list, project ->
+ listOf(mergeUserConfigurationAndPlatformData(list.first(), ConfigurationExtractor.extractFromSinglePlatform(project)!!))
+ })
+ } catch(e: NoClassDefFoundError) {
+ logger.warn("Cannot extract sources from subProjects. Please update Kotlin plugin to version 1.3.30+")
+ baseConfig
+ }
+ } else {
+ baseConfig
}
+ }
- return passConfig
+ private fun collectFromSinglePlatformOldPlugin(): List<GradlePassConfigurationImpl> {
+ val kotlinTasks = ConfigurationExtractor.extractFromKotlinTasks(kotlinTasks, project)
+ return if (kotlinTasks != null) {
+ listOf(mergeUserConfigurationAndPlatformData(configuration, kotlinTasks))
+ } else {
+ val javaPlugin = ConfigurationExtractor.extractFromJavaPlugin(project)
+ if (javaPlugin != null)
+ listOf(mergeUserConfigurationAndPlatformData(configuration, javaPlugin)) else listOf(configuration)
+ }
}
- private fun collectSourceRoots(): List<SourceRoot> {
- val sourceDirs = when {
- sourceDirs.any() -> {
- logger.info("Dokka: Taking source directories provided by the user")
- sourceDirs.toSet()
- }
- kotlinTasks.isEmpty() -> project.convention.findPlugin(JavaPluginConvention::class.java)?.let { javaPluginConvention ->
- logger.info("Dokka: Taking source directories from default java plugin")
- val sourceSets = javaPluginConvention.sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME)
- sourceSets?.allSource?.srcDirs
- }
- else -> emptySet()
+ private fun mergeUserAndAutoConfigurations(userConfigurations: List<GradlePassConfigurationImpl>,
+ autoConfigurations: List<ConfigurationExtractor.PlatformData>) =
+ userConfigurations.map { userConfig ->
+ val autoConfig = autoConfigurations.find { autoConfig -> autoConfig.name == userConfig.name }
+ if (autoConfig != null) mergeUserConfigurationAndPlatformData(userConfig, autoConfig) else userConfig
}
- return sourceRoots + (sourceDirs?.toSourceRoots() ?: emptyList())
+
+ private fun mergeUserConfigurationAndPlatformData(user: GradlePassConfigurationImpl,
+ auto: ConfigurationExtractor.PlatformData): GradlePassConfigurationImpl {
+ user.sourceRoots.addAll(auto.sourceRoots.toSourceRoots())
+ user.classpath += auto.classpath.map { it.absolutePath }
+ if (user.platform == null)
+ user.platform = auto.platform
+ return user
+ }
+
+ private fun defaultPassConfiguration(config: GradlePassConfigurationImpl): GradlePassConfigurationImpl {
+ if (config.moduleName == "") {
+ config.moduleName = moduleName
+ }
+ config.samples = config.samples.map { project.file(it).absolutePath }
+ config.includes = config.includes.map { project.file(it).absolutePath }
+ config.collectInheritedExtensionsFromLibraries = collectInheritedExtensionsFromLibraries
+ config.suppressedFiles += collectSuppressedFiles(config.sourceRoots)
+ config.externalDocumentationLinks.addAll(externalDocumentationLinks)
+ if (config.platform != null && config.platform.toString().isNotEmpty()){
+ config.analysisPlatform = Platform.fromString(config.platform.toString())
+ }
+ return config
}
/**
@@ -275,17 +274,14 @@ open class DokkaTask : DefaultTask() {
* Needed for Gradle incremental build
*/
@InputFiles
- fun getInputFiles(): FileCollection {
- val (_, tasksSourceRoots) = extractClasspathAndSourceRootsFromKotlinTasks()
- return project.files(tasksSourceRoots.map { project.fileTree(it) }) +
- project.files(collectSourceRoots().map { project.fileTree(File(it.path)) })
- }
+ fun getInputFiles(): FileCollection =
+ project.files(collectConfigurations().flatMap { it.sourceRoots }.map { project.fileTree(File(it.path)) })
companion object {
const val COLORS_ENABLED_PROPERTY = "kotlin.colors.enabled"
const val ABSTRACT_KOTLIN_COMPILE = "org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile"
- private fun getAbstractKotlinCompileFor(task: Task) = try {
+ internal fun getAbstractKotlinCompileFor(task: Task) = try {
task.project.buildscript.classLoader.loadClass(ABSTRACT_KOTLIN_COMPILE)
} catch (e: ClassNotFoundException) {
null
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt
index 85671c5b..c9c0d15d 100644
--- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt
@@ -41,7 +41,7 @@ open class GradlePassConfigurationImpl(@Transient val name: String = ""): PassCo
override var suppressedFiles: List<String> = emptyList()
override var collectInheritedExtensionsFromLibraries: Boolean = false
override var analysisPlatform: Platform = Platform.DEFAULT
- var platform: String = ""
+ var platform: String? = null
override var targets: List<String> = emptyList()
override var sinceKotlin: String? = null
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt
index d04ed5f0..7cc19900 100644
--- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt
@@ -2,18 +2,11 @@ package org.jetbrains.dokka.gradle
import org.gradle.api.Plugin
import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import java.io.File
import java.io.InputStream
import java.util.*
-/*
-* Extension names, which are used in a build.gradle file as closure names:
-* dokka {
-* configuration { // extension name
-*
-* }
-* }
-* */
internal const val CONFIGURATION_EXTENSION_NAME = "configuration"
internal const val MULTIPLATFORM_EXTENSION_NAME = "multiplatform"
@@ -22,15 +15,17 @@ open class DokkaPlugin : Plugin<Project> {
override fun apply(project: Project) {
DokkaVersion.loadFrom(javaClass.getResourceAsStream("/META-INF/gradle-plugins/org.jetbrains.dokka.properties"))
+ // TODO: Register instead of create for Gradle >= 4.10
project.tasks.create("dokka", DokkaTask::class.java).apply {
dokkaRuntime = project.configurations.create("dokkaRuntime")
moduleName = project.name
outputDirectory = File(project.buildDir, "dokka").absolutePath
}
+
project.tasks.withType(DokkaTask::class.java) { task ->
val passConfiguration = project.container(GradlePassConfigurationImpl::class.java)
- task.extensions.add(MULTIPLATFORM_EXTENSION_NAME, passConfiguration)
- task.extensions.create(CONFIGURATION_EXTENSION_NAME, GradlePassConfigurationImpl::class.java, "")
+ task.multiplatform = passConfiguration
+ task.configuration = GradlePassConfigurationImpl()
}
}
}