aboutsummaryrefslogtreecommitdiff
path: root/runners/gradle-plugin/src/main
diff options
context:
space:
mode:
authorPaweł Marks <pmarks@virtuslab.com>2020-07-17 16:36:09 +0200
committerPaweł Marks <pmarks@virtuslab.com>2020-07-17 16:36:09 +0200
commit6996b1135f61c7d2cb60b0652c6a2691dda31990 (patch)
treed568096c25e31c28d14d518a63458b5a7526b896 /runners/gradle-plugin/src/main
parentde56cab76f556e5b4af0b8c8cb08d8b482b86d0a (diff)
parent1c3530dcbb50c347f80bef694829dbefe89eca77 (diff)
downloaddokka-6996b1135f61c7d2cb60b0652c6a2691dda31990.tar.gz
dokka-6996b1135f61c7d2cb60b0652c6a2691dda31990.tar.bz2
dokka-6996b1135f61c7d2cb60b0652c6a2691dda31990.zip
Merge branch 'dev-0.11.0'
Diffstat (limited to 'runners/gradle-plugin/src/main')
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt45
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ConfigurationExtractor.kt222
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt17
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaBootstrapFactory.kt18
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt58
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt68
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaSourceSetIDFactory.kt10
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt330
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ProxyUtils.kt23
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/ReflectDsl.kt72
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt234
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/defaultDokkaOutputDirectory.kt13
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/dokkaConfigurations.kt41
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt72
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt24
15 files changed, 799 insertions, 448 deletions
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt
new file mode 100644
index 00000000..846f021c
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt
@@ -0,0 +1,45 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Usage
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.TaskAction
+import org.gradle.kotlin.dsl.dependencies
+import org.jetbrains.dokka.DokkaBootstrap
+import org.jetbrains.dokka.plugability.Configurable
+
+
+abstract class AbstractDokkaTask : DefaultTask(), Configurable {
+ @Input
+ var outputDirectory: String = defaultDokkaOutputDirectory().absolutePath
+
+ @Input
+ override val pluginsConfiguration: Map<String, String> = mutableMapOf()
+
+ @Classpath
+ val plugins: Configuration = project.maybeCreateDokkaPluginConfiguration(name)
+
+ @Classpath
+ val runtime: Configuration = project.maybeCreateDokkaRuntimeConfiguration(name)
+
+ @TaskAction
+ protected fun run() {
+ val kotlinColorsEnabledBefore = System.getProperty(DokkaTask.COLORS_ENABLED_PROPERTY) ?: "false"
+ System.setProperty(DokkaTask.COLORS_ENABLED_PROPERTY, "false")
+ try {
+ generate()
+ } finally {
+ System.setProperty(DokkaTask.COLORS_ENABLED_PROPERTY, kotlinColorsEnabledBefore)
+ }
+ }
+
+ protected abstract fun generate()
+
+ protected fun DokkaBootstrap(bootstrapClassFQName: String): DokkaBootstrap {
+ return DokkaBootstrap(runtime, bootstrapClassFQName)
+ }
+}
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
index 39672b9a..1bfd2c78 100644
--- 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
@@ -1,9 +1,5 @@
package org.jetbrains.dokka.gradle
-import com.android.build.gradle.*
-import com.android.build.gradle.api.BaseVariant
-import com.android.builder.core.BuilderConstants
-import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.UnknownDomainObjectException
@@ -13,90 +9,71 @@ 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.KotlinProjectExtension
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 org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import java.io.File
import java.io.Serializable
class ConfigurationExtractor(private val project: Project) {
-
- fun extractConfiguration(targetName: String, variantNames: List<String>) =
- if (project.isMultiplatformProject()) {
- extractFromMultiPlatform(targetName, variantNames)
- } else {
- extractFromSinglePlatform(variantNames)
+ fun extractConfiguration(sourceSetName: String): PlatformData? {
+ val projectExtension = project.extensions.findByType(KotlinProjectExtension::class.java) ?: run {
+ project.logger.error("Missing kotlin project extension")
+ return null
}
- private fun extractFromSinglePlatform(variantNames: List<String>): PlatformData? {
- val target: KotlinTarget
- try {
- target = project.extensions.getByType(KotlinSingleTargetExtension::class.java).target
- } catch (e: Throwable) {
- when (e) {
- is UnknownDomainObjectException, is NoClassDefFoundError, is ClassNotFoundException ->
- return null
- else -> throw e
- }
+ val sourceSet = projectExtension.sourceSets.findByName(sourceSetName) ?: run {
+ project.logger.error("No source set with name '$sourceSetName' found")
+ return null
}
- return try {
- PlatformData(
- null,
- accumulateClassPaths(variantNames, target),
- accumulateSourceSets(variantNames, target),
- getPlatformName(target.platformType)
- )
- } catch (e: NoSuchMethodError) {
+ val compilation = try {
+ when (projectExtension) {
+ is KotlinMultiplatformExtension -> {
+ val targets = projectExtension.targets.flatMap { it.compilations }
+ targets.find { it.name == sourceSetName }
+ ?: targets.find { it.kotlinSourceSets.contains(sourceSet) }
+ }
+ is KotlinSingleTargetExtension -> projectExtension.target.compilations.find {
+ it.kotlinSourceSets.contains(sourceSet)
+ }
+ else -> null
+ }
+ } catch (e: NoClassDefFoundError) { // Old Kotlin plugin versions
null
}
+
+ val sourceRoots = sourceSet.sourceFiles
+ val classpath = compilation?.classpath
+ ?: sourceRoots + sourceSet.allParentSourceFiles()
+
+ return PlatformData(
+ sourceSetName,
+ classpath.filter { it.exists() },
+ sourceRoots,
+ sourceSet.dependsOn.map { it.name },
+ compilation?.target?.platformType?.name ?: "common"
+ )
}
- private fun extractFromMultiPlatform(targetName: String, variantNames: List<String>): PlatformData? =
- try {
- project.extensions.getByType(KotlinMultiplatformExtension::class.java).targets
- } catch (e: Throwable) {
- when (e) {
- is UnknownDomainObjectException, is NoClassDefFoundError, is ClassNotFoundException ->
- null
- else -> throw e
- }
- }?.let {
- val fixedName = if (targetName.toLowerCase() == "common") "metadata" else targetName.toLowerCase()
- it.find { target -> target.name.toLowerCase() == fixedName }?.let { target ->
- PlatformData(
- fixedName,
- accumulateClassPaths(variantNames, target),
- accumulateSourceSets(variantNames, target),
- target.platformType.toString()
- )
- }
- }
+ private fun KotlinSourceSet.allParentSourceFiles(): List<File> =
+ sourceFiles + dependsOn.flatMap { it.allParentSourceFiles() }
fun extractFromJavaPlugin(): PlatformData? =
project.convention.findPlugin(JavaPluginConvention::class.java)
?.run { sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME)?.allSource?.srcDirs }
- ?.let { PlatformData(null, emptyList(), it.toList(), "") }
+ ?.let { PlatformData(null, emptyList(), it.toList(), emptyList(), "") }
- fun extractFromKotlinTasks(kotlinTasks: List<Task>): PlatformData? =
+ fun extractFromKotlinTasks(kotlinTasks: List<Task>): List<PlatformData> =
try {
- kotlinTasks.map { extractFromKotlinTask(it) }.let { platformDataList ->
- PlatformData(
- null,
- platformDataList.flatMap { it.classpath },
- platformDataList.flatMap { it.sourceRoots },
- ""
- )
- }
+ kotlinTasks.map { extractFromKotlinTask(it) }
} catch (e: Throwable) {
when (e) {
is UnknownDomainObjectException, is NoClassDefFoundError, is ClassNotFoundException ->
- extractFromKotlinTasksTheHardWay(kotlinTasks)
+ listOfNotNull(extractFromKotlinTasksTheHardWay(kotlinTasks))
else -> throw e
}
}
@@ -110,10 +87,18 @@ class ConfigurationExtractor(private val project: Project) {
when (e) {
is UnknownDomainObjectException, is NoClassDefFoundError, is ClassNotFoundException ->
project.extensions.getByType(KotlinMultiplatformExtension::class.java).targets
- .firstNotNullResult { target -> target.compilations.find { it.compileKotlinTask == task } }
+ .flatMap { it.compilations }.firstOrNull { it.compileKotlinTask == task }
else -> throw e
}
- }.let { PlatformData(task.name, getClasspath(it), getSourceSet(it), it?.platformType?.toString() ?: "") }
+ }.let { compilation ->
+ PlatformData(
+ task.name,
+ compilation?.classpath.orEmpty(),
+ compilation?.sourceFiles.orEmpty(),
+ compilation?.dependentSourceSets?.map { it.name }.orEmpty(),
+ compilation?.platformType?.toString() ?: ""
+ )
+ }
private fun extractFromKotlinTasksTheHardWay(kotlinTasks: List<Task>): PlatformData? {
val allClasspath = mutableSetOf<File>()
@@ -134,8 +119,8 @@ class ConfigurationExtractor(private val project: Project) {
val taskClasspath: Iterable<File> =
(it["getClasspath", AbstractCompile::class].takeIfIsFunc()?.invoke()
- ?: it["compileClasspath", abstractKotlinCompileClz].takeIfIsProp()?.v()
- ?: it["getClasspath", abstractKotlinCompileClz]())
+ ?: it["compileClasspath", abstractKotlinCompileClz].takeIfIsProp()?.v()
+ ?: it["getClasspath", abstractKotlinCompileClz]())
if (taskClasspath is FileCollection) {
allClasspathFileCollection += taskClasspath
@@ -152,97 +137,42 @@ class ConfigurationExtractor(private val project: Project) {
}
classpath.addAll(project.files(allClasspath).toList())
- return PlatformData(null, classpath, allSourceRoots.toList(), "")
+ return PlatformData(null, classpath, allSourceRoots.toList(), emptyList(), "")
}
- private fun getSourceSet(target: KotlinTarget, variantName: String): List<File> =
- if (target.isAndroidTarget())
- getSourceSet(getCompilation(target, variantName))
- else
- getSourceSet(getMainCompilation(target))
-
- private fun getClasspath(target: KotlinTarget, variantName: String): List<File> =
- if (target.isAndroidTarget())
- getClasspathFromAndroidTask(getCompilation(target, variantName))
- else
- getClasspath(getMainCompilation(target))
-
- private fun getSourceSet(compilation: KotlinCompilation<*>?): List<File> = compilation
- ?.allKotlinSourceSets
- ?.flatMap { it.kotlin.sourceDirectories }
- ?.filter { it.exists() }
- .orEmpty()
-
- private fun getClasspath(compilation: KotlinCompilation<*>?): List<File> = compilation
- ?.compileDependencyFiles
- ?.files
- ?.toList()
- ?.filter { it.exists() }
- .orEmpty()
-
- // This is a workaround for KT-33893
- private fun getClasspathFromAndroidTask(compilation: KotlinCompilation<*>): List<File> = (compilation
- .compileKotlinTask as? KotlinCompile)
- ?.classpath?.files?.toList() ?: getClasspath(compilation)
-
- private fun getMainCompilation(target: KotlinTarget) =
- getCompilation(target, getMainCompilationName(target))
-
- private fun getCompilation(target: KotlinTarget, name: String) =
- target.compilations.getByName(name)
-
- private fun getMainCompilationName(target: KotlinTarget) = if (target.isAndroidTarget())
- getVariants(project).filter { it.buildType.name == BuilderConstants.RELEASE }.map { it.name }.first()
- else
- KotlinCompilation.MAIN_COMPILATION_NAME
-
- private fun getVariants(project: Project): Set<BaseVariant> {
- val androidExtension = project.extensions.getByName("android")
- val baseVariants = when (androidExtension) {
- is AppExtension -> androidExtension.applicationVariants.toSet()
- is LibraryExtension -> {
- androidExtension.libraryVariants.toSet() +
- if (androidExtension is FeatureExtension) {
- androidExtension.featureVariants.toSet()
- } else {
- emptySet<BaseVariant>()
- }
- }
- is TestExtension -> androidExtension.applicationVariants.toSet()
- else -> emptySet()
- }
- val testVariants = if (androidExtension is TestedExtension) {
- androidExtension.testVariants.toSet() + androidExtension.unitTestVariants.toSet()
- } else {
- emptySet<BaseVariant>()
- }
+ private val KotlinCompilation<*>.sourceFiles: List<File>
+ get() = kotlinSourceSets.flatMap { it.sourceFiles }
- return baseVariants + testVariants
- }
+ private val KotlinSourceSet.sourceFiles: List<File>
+ get() = kotlin.sourceDirectories.filter { it.exists() }.toList()
- private fun getPlatformName(platform: KotlinPlatformType): String =
- if (platform == KotlinPlatformType.androidJvm) KotlinPlatformType.jvm.toString() else platform.toString()
+ private val KotlinCompilation<*>.dependentSourceSets: Set<KotlinSourceSet>
+ get() = (allKotlinSourceSets - kotlinSourceSets)
- private fun accumulateClassPaths(variantNames: List<String>, target: KotlinTarget) =
- if (variantNames.isNotEmpty()) {
- variantNames.flatMap { getClasspath(target, it) }.distinct()
+ private val KotlinCompilation<*>.classpath: List<File>
+ get() = if (target.isAndroidTarget()) {
+ getClasspathFromAndroidTask(this)
} else {
- if (target.isAndroidTarget())
- getClasspathFromAndroidTask(getMainCompilation(target))
- else
- getClasspath(getMainCompilation(target))
+ getClasspathFromRegularTask(this)
}
- private fun accumulateSourceSets(variantNames: List<String>, target: KotlinTarget) =
- if (variantNames.isNotEmpty())
- variantNames.flatMap { getSourceSet(target, it) }.distinct()
- else
- getSourceSet(getMainCompilation(target))
+ // This is a workaround for KT-33893
+ private fun getClasspathFromAndroidTask(compilation: KotlinCompilation<*>): List<File> = (compilation
+ .compileKotlinTask as? KotlinCompile)
+ ?.classpath?.files?.toList() ?: getClasspathFromRegularTask(compilation)
+
+ private fun getClasspathFromRegularTask(compilation: KotlinCompilation<*>): List<File> =
+ compilation
+ .compileDependencyFiles
+ .files
+ .toList()
+ .filter { it.exists() }
data class PlatformData(
val name: String?,
val classpath: List<File>,
val sourceRoots: List<File>,
+ val dependentSourceSets: List<String>,
val platform: String
) : Serializable
-} \ No newline at end of file
+}
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt
new file mode 100644
index 00000000..90d51015
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaArtifacts.kt
@@ -0,0 +1,17 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.api.Project
+import org.jetbrains.dokka.DokkaVersion
+
+internal val Project.dokkaArtifacts get() = DokkaArtifacts(this)
+
+internal class DokkaArtifacts(private val project: Project) {
+ private fun fromModuleName(name: String) =
+ project.dependencies.create("org.jetbrains.dokka:$name:${DokkaVersion.version}")
+
+ val dokkaCore get() = fromModuleName("dokka-core")
+ val dokkaBase get() = fromModuleName("dokka-base")
+ val javadocPlugin get() = fromModuleName("javadoc-plugin")
+ val gfmPlugin get() = fromModuleName("gfm-plugin")
+ val jekyllPlugin get() = fromModuleName("jekyll-plugin")
+}
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaBootstrapFactory.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaBootstrapFactory.kt
new file mode 100644
index 00000000..df29c19b
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaBootstrapFactory.kt
@@ -0,0 +1,18 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.api.artifacts.Configuration
+import org.jetbrains.dokka.DokkaBootstrap
+import java.net.URLClassLoader
+
+
+fun DokkaBootstrap(configuration: Configuration, bootstrapClassFQName: String): DokkaBootstrap {
+ val runtimeJars = configuration.resolve()
+ val runtimeClassLoader = URLClassLoader(
+ runtimeJars.map { it.toURI().toURL() }.toTypedArray(),
+ ClassLoader.getSystemClassLoader().parent
+ )
+
+ val bootstrapClass = runtimeClassLoader.loadClass(bootstrapClassFQName)
+ val bootstrapInstance = bootstrapClass.constructors.first().newInstance()
+ return automagicTypedProxy(DokkaPlugin::class.java.classLoader, bootstrapInstance)
+}
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt
new file mode 100644
index 00000000..37952ea8
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt
@@ -0,0 +1,58 @@
+package org.jetbrains.dokka.gradle
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.plugins.JavaBasePlugin.DOCUMENTATION_GROUP
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.TaskAction
+import java.lang.IllegalStateException
+
+open class DokkaCollectorTask : DefaultTask() {
+
+ @Input
+ var modules: List<String> = emptyList()
+
+ @Input
+ var outputDirectory: String = defaultDokkaOutputDirectory().absolutePath
+
+ private lateinit var configuration: GradleDokkaConfigurationImpl
+
+ @Input
+ var dokkaTaskNames: Set<String> = setOf()
+
+ @TaskAction
+ fun collect() {
+ val configurations = project.subprojects
+ .filter { subProject -> subProject.name in modules }
+ .flatMap { subProject -> dokkaTaskNames.mapNotNull(subProject.tasks::findByName) }
+ .filterIsInstance<DokkaTask>()
+ .mapNotNull { dokkaTask -> dokkaTask.getConfigurationOrNull() }
+
+
+ val initial = GradleDokkaConfigurationImpl().apply {
+ outputDir = outputDirectory
+ cacheRoot = configurations.first().cacheRoot
+ }
+
+ // TODO this certainly not the ideal solution
+ configuration = configurations.fold(initial) { acc, it: GradleDokkaConfigurationImpl ->
+ if (acc.cacheRoot != it.cacheRoot)
+ throw IllegalStateException("Dokka task configurations differ on core argument cacheRoot")
+ acc.sourceSets = acc.sourceSets + it.sourceSets
+ acc.pluginsClasspath = (acc.pluginsClasspath + it.pluginsClasspath).distinct()
+ acc
+ }
+ project.tasks.withType(DokkaTask::class.java).configureEach { it.enforcedConfiguration = configuration }
+ }
+
+ init {
+ // TODO: This this certainly not the ideal solution
+ dokkaTaskNames.forEach { dokkaTaskName ->
+ finalizedBy(dokkaTaskName)
+ }
+
+ group = DOCUMENTATION_GROUP
+ }
+
+
+}
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt
new file mode 100644
index 00000000..6fd58afe
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt
@@ -0,0 +1,68 @@
+package org.jetbrains.dokka.gradle
+
+import com.google.gson.GsonBuilder
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.plugins.JavaBasePlugin.DOCUMENTATION_GROUP
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Internal
+import org.jetbrains.dokka.plugability.Configurable
+
+open class DokkaMultimoduleTask : AbstractDokkaTask(), Configurable {
+
+ @Input
+ var documentationFileName: String = "README.md"
+
+
+ @Input
+ var dokkaTaskNames: Set<String> = setOf()
+ set(value) {
+ field = value.toSet()
+ setDependsOn(getSubprojectDokkaTasks(value))
+ }
+
+
+ override fun generate() {
+ val bootstrap = DokkaBootstrap("org.jetbrains.dokka.DokkaMultimoduleBootstrapImpl")
+ val gson = GsonBuilder().setPrettyPrinting().create()
+ val configuration = getConfiguration()
+ bootstrap.configure(gson.toJson(configuration)) { level, message ->
+ when (level) {
+ "debug" -> logger.debug(message)
+ "info" -> logger.info(message)
+ "progress" -> logger.lifecycle(message)
+ "warn" -> logger.warn(message)
+ "error" -> logger.error(message)
+ }
+ }
+ bootstrap.generate()
+ }
+
+ @Internal
+ internal fun getConfiguration(): GradleDokkaConfigurationImpl =
+ GradleDokkaConfigurationImpl().apply {
+ outputDir = project.file(outputDirectory).absolutePath
+ pluginsClasspath = plugins.resolve().toList()
+ pluginsConfiguration = this@DokkaMultimoduleTask.pluginsConfiguration
+ modules = getSubprojectDokkaTasks(dokkaTaskNames).map { dokkaTask ->
+ GradleDokkaModuleDescription().apply {
+ name = dokkaTask.project.name
+ path = dokkaTask.project.projectDir.resolve(dokkaTask.outputDirectory)
+ .toRelativeString(project.file(outputDirectory))
+ docFile = dokkaTask.project.projectDir.resolve(documentationFileName).absolutePath
+ }
+ }
+ }
+
+ private fun getSubprojectDokkaTasks(dokkaTaskName: String): List<DokkaTask> {
+ return project.subprojects
+ .mapNotNull { subproject -> subproject.tasks.findByName(dokkaTaskName) as? DokkaTask }
+ }
+
+ private fun getSubprojectDokkaTasks(dokkaTaskNames: Set<String>): List<DokkaTask> {
+ return dokkaTaskNames.flatMap { dokkaTaskName -> getSubprojectDokkaTasks(dokkaTaskName) }
+ }
+
+ init {
+ group = DOCUMENTATION_GROUP
+ }
+}
diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaSourceSetIDFactory.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaSourceSetIDFactory.kt
new file mode 100644
index 00000000..3fadb4fd
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaSourceSetIDFactory.kt
@@ -0,0 +1,10 @@
+@file:Suppress("FunctionName")
+
+package org.jetbrains.dokka.gradle
+
+import org.gradle.api.Project
+import org.jetbrains.dokka.DokkaSourceSetID
+
+internal fun DokkaSourceSetID(project: Project, sourceSetName: String): DokkaSourceSetID {
+ return DokkaSourceSetID(moduleName = project.path, sourceSetName = sourceSetName)
+}
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 bafe657e..0d7e74a3 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
@@ -1,28 +1,26 @@
package org.jetbrains.dokka.gradle
import com.google.gson.GsonBuilder
-import org.gradle.api.*
-import org.gradle.api.artifacts.Configuration
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.plugins.DslObject
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.tasks.*
-import org.jetbrains.dokka.DokkaBootstrap
import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink.Builder
import org.jetbrains.dokka.DokkaConfiguration.SourceRoot
+import org.jetbrains.dokka.DokkaException
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.ReflectDsl
import org.jetbrains.dokka.ReflectDsl.isNotInstance
import org.jetbrains.dokka.gradle.ConfigurationExtractor.PlatformData
-import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import java.io.File
-import java.net.URLClassLoader
import java.util.concurrent.Callable
-import java.util.function.BiConsumer
-open class DokkaTask : DefaultTask() {
+open class DokkaTask : AbstractDokkaTask() {
private val ANDROID_REFERENCE_URL = Builder("https://developer.android.com/reference/").build()
- private val GLOBAL_PLATFORM_NAME = "global" // Used for copying perPackageOptions to other platforms
+ private val configExtractor = ConfigurationExtractor(project)
@Suppress("MemberVisibilityCanBePrivate")
fun defaultKotlinTasks(): List<Task> = with(ReflectDsl) {
@@ -44,60 +42,50 @@ open class DokkaTask : DefaultTask() {
dependsOn(Callable { kotlinTasks.map { it.taskDependencies } })
}
- @Input
- var outputFormat: String = "html"
-
- @Input
- var outputDirectory: String = ""
-
- var dokkaRuntime: Configuration? = null
-
- @Input
- var subProjects: List<String> = emptyList()
-
- @Input
- var impliedPlatforms: MutableList<String> = arrayListOf()
-
@Optional
@Input
var cacheRoot: String? = null
- var multiplatform: NamedDomainObjectContainer<GradlePassConfigurationImpl>
- @Suppress("UNCHECKED_CAST")
- @Nested 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")
- @Nested get() = DslObject(this).extensions.getByType(GradlePassConfigurationImpl::class.java)
- internal set(value) = DslObject(this).extensions.add(CONFIGURATION_EXTENSION_NAME, value)
+ /**
+ * Hack used by DokkaCollector to enforce a different configuration to be used.
+ */
+ @get:Internal
+ internal var enforcedConfiguration: GradleDokkaConfigurationImpl? = null
- // Configure Dokka with closure in Gradle Kotlin DSL
- fun configuration(action: Action<in GradlePassConfigurationImpl>) = action.execute(configuration)
+ @get:Nested
+ val dokkaSourceSets: NamedDomainObjectContainer<GradleDokkaSourceSet> =
+ project.container(GradleDokkaSourceSet::class.java) { name -> GradleDokkaSourceSet(name, project) }
+ .also { container -> DslObject(this).extensions.add("dokkaSourceSets", container) }
- private val kotlinTasks: List<Task> by lazy { extractKotlinCompileTasks(configuration.collectKotlinTasks ?: { defaultKotlinTasks() }) }
- private val configExtractor = ConfigurationExtractor(project)
+ private val kotlinTasks: List<Task> by lazy {
+ extractKotlinCompileTasks(
+ dokkaSourceSets.mapNotNull {
+ it.collectKotlinTasks?.invoke()
+ }.takeIf { it.isNotEmpty() }?.flatten() ?: defaultKotlinTasks()
+ )
+ }
@Input
var disableAutoconfiguration: Boolean = false
- private var outputDiagnosticInfo: Boolean = false // Workaround for Gradle, which fires some methods (like collectConfigurations()) multiple times in its lifecycle
+ @Input
+ var failOnWarning: Boolean = false
- private fun loadFatJar() {
- if (ClassloaderContainer.fatJarClassLoader == null) {
- val jars = dokkaRuntime!!.resolve().toList()
- ClassloaderContainer.fatJarClassLoader = URLClassLoader(jars.map { it.toURI().toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader().parent)
- }
- }
+ @Input
+ var offlineMode: Boolean = false
- private fun extractKotlinCompileTasks(collectTasks: () -> List<Any?>?): List<Task> {
- val inputList = (collectTasks.invoke() ?: emptyList()).filterNotNull()
- val (paths, other) = inputList.partition { it is String }
+ private var outputDiagnosticInfo: Boolean =
+ false // Workaround for Gradle, which fires some methods (like collectConfigurations()) multiple times in its lifecycle
- val taskContainer = project.tasks
+ protected fun extractKotlinCompileTasks(collectTasks: List<Any?>?): List<Task> {
+ val inputList = (collectTasks ?: emptyList()).filterNotNull()
+ val (paths, other) = inputList.partition { it is String }
- val tasksByPath = paths.map { taskContainer.findByPath(it as String) ?: throw IllegalArgumentException("Task with path '$it' not found") }
+ val tasksByPath = paths.map {
+ project.tasks.findByPath(it as String) ?: throw IllegalArgumentException("Task with path '$it' not found")
+ }
other
.filter { it !is Task || it isNotInstance getAbstractKotlinCompileFor(it) }
@@ -111,11 +99,14 @@ open class DokkaTask : DefaultTask() {
return (tasksByPath + other) as List<Task>
}
- 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) }
+ 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>) =
- if(project.isAndroidProject()) {
+ if (project.isAndroidProject()) {
val generatedRoot = project.buildDir.resolve("generated").absoluteFile
sourceRoots
.map { File(it.path) }
@@ -126,153 +117,152 @@ open class DokkaTask : DefaultTask() {
emptyList()
}
- @TaskAction
- fun generate() {
+ override fun generate() = enforcedConfiguration?.let { generate(it) } ?: generate(getConfigurationOrThrow())
+
+ protected open fun generate(configuration: GradleDokkaConfigurationImpl) {
outputDiagnosticInfo = true
- val kotlinColorsEnabledBefore = System.getProperty(COLORS_ENABLED_PROPERTY) ?: "false"
- System.setProperty(COLORS_ENABLED_PROPERTY, "false")
- try {
- loadFatJar()
-
- val bootstrapClass = ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl")
- val bootstrapInstance = bootstrapClass.constructors.first().newInstance()
- val bootstrapProxy: DokkaBootstrap =
- automagicTypedProxy(javaClass.classLoader, bootstrapInstance)
-
- val gson = GsonBuilder().setPrettyPrinting().create()
-
- val globalConfig = multiplatform.toList().find { it.name.toLowerCase() == GLOBAL_PLATFORM_NAME }
- val passConfigurationList = collectConfigurations()
- .map { defaultPassConfiguration(it, globalConfig) }
-
- val configuration = GradleDokkaConfigurationImpl()
- configuration.outputDir