From 8525326620eab855c2a0af83acfd47efb431d253 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Thu, 9 Jul 2020 16:19:57 +0200 Subject: Refactor dokka tasks classpath configuration --- .../gradle/projects/it-basic/build.gradle.kts | 5 ++ .../jetbrains/dokka/gradle/DokkaCollectorTask.kt | 33 ++++++------ .../jetbrains/dokka/gradle/DokkaDependencies.kt | 17 +++++++ .../jetbrains/dokka/gradle/DokkaMultimoduleTask.kt | 20 +++++--- .../kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt | 6 ++- .../main/kotlin/org/jetbrains/dokka/gradle/main.kt | 59 ++++++++++++++-------- .../kotlin/org/jetbrains/dokka/gradle/utils.kt | 22 +++++--- 7 files changed, 109 insertions(+), 53 deletions(-) create mode 100644 runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaDependencies.kt diff --git a/integration-tests/gradle/projects/it-basic/build.gradle.kts b/integration-tests/gradle/projects/it-basic/build.gradle.kts index e5a44555..58f97b6c 100644 --- a/integration-tests/gradle/projects/it-basic/build.gradle.kts +++ b/integration-tests/gradle/projects/it-basic/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.dokka.gradle.DokkaTask + plugins { kotlin("jvm") id("org.jetbrains.dokka") @@ -5,7 +7,10 @@ plugins { apply(from = "../template.root.gradle.kts") +val customDokkaTask by tasks.register("customDokka") + dependencies { implementation(kotlin("stdlib")) } + 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 index 823206e3..7aa7c0fa 100644 --- 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 @@ -4,6 +4,7 @@ import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.UnknownTaskException import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.TaskAction import java.lang.IllegalStateException @@ -17,25 +18,26 @@ open class DokkaCollectorTask : DefaultTask() { private lateinit var configuration: GradleDokkaConfigurationImpl + @Input + val dokkaTaskNames: MutableSet = mutableSetOf() + @TaskAction fun collect() { - val sourceSets = getProjects(project).filter { it.name in modules }.flatMap { - val tasks = try { - it.tasks.withType(DokkaTask::class.java) - } catch (e: UnknownTaskException) { - throw IllegalStateException("No dokka task declared in module ${it.name}") - } - tasks.map { it.getConfigurationOrNull() } - }.filterNotNull() + val configurations = project.allDescendentProjects().toList() + .filter { subProject -> subProject.name in modules } + .flatMap { subProject -> dokkaTaskNames.mapNotNull(subProject.tasks::findByName) } + .filterIsInstance() + .mapNotNull { dokkaTask -> dokkaTask.getConfigurationOrNull() } + val initial = GradleDokkaConfigurationImpl().apply { outputDir = outputDirectory - cacheRoot = sourceSets.first().cacheRoot - format = sourceSets.first().format + cacheRoot = configurations.first().cacheRoot } - configuration = sourceSets.fold(initial) { acc, it: GradleDokkaConfigurationImpl -> - if(acc.format != it.format || acc.cacheRoot != it.cacheRoot) + // TODO this certainly not the ideal solution + configuration = configurations.fold(initial) { acc, it: GradleDokkaConfigurationImpl -> + if (acc.format != it.format || acc.cacheRoot != it.cacheRoot) throw IllegalStateException("Dokka task configurations differ on core arguments (format, cacheRoot)") acc.sourceSets = acc.sourceSets + it.sourceSets acc.pluginsClasspath = (acc.pluginsClasspath + it.pluginsClasspath).distinct() @@ -45,10 +47,11 @@ open class DokkaCollectorTask : DefaultTask() { } init { - finalizedBy(project.tasks.getByName(DOKKA_TASK_NAME)) + // TODO: This this certainly not the ideal solution + dokkaTaskNames.forEach { dokkaTaskName -> + finalizedBy(dokkaTaskName) + } } - private fun getProjects(project: Project): Set = - project.subprojects + project.subprojects.flatMap { getProjects(it) } } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaDependencies.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaDependencies.kt new file mode 100644 index 00000000..2ee1d479 --- /dev/null +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaDependencies.kt @@ -0,0 +1,17 @@ +package org.jetbrains.dokka.gradle + +import org.gradle.api.Project +import org.jetbrains.dokka.DokkaVersion + +internal val Project.dokkaDependencies get() = DokkaDependencies(this) + +internal class DokkaDependencies(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/DokkaMultimoduleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt index d04ad258..3ed81054 100644 --- 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 @@ -4,6 +4,7 @@ import com.google.gson.GsonBuilder import org.gradle.api.DefaultTask import org.gradle.api.artifacts.Configuration import org.gradle.api.attributes.Usage +import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal @@ -25,6 +26,9 @@ open class DokkaMultimoduleTask : DefaultTask(), Configurable { @Input var outputDirectory: String = "" + @Input + val dokkaTaskNames: MutableSet = mutableSetOf() + @Classpath val runtime = project.configurations.create("${name}Runtime").apply { defaultDependencies { dependencies -> @@ -73,14 +77,14 @@ open class DokkaMultimoduleTask : DefaultTask(), Configurable { pluginsClasspath = plugins.resolve().toList() pluginsConfiguration = this@DokkaMultimoduleTask.pluginsConfiguration modules = project.subprojects - .mapNotNull { subproject -> - subproject.tasks.withType(DokkaTask::class.java).firstOrNull()?.let { dokkaTask -> - GradleDokkaModuleDescription().apply { - name = subproject.name - path = subproject.projectDir.resolve(dokkaTask.outputDirectory) - .toRelativeString(project.file(outputDirectory)) - docFile = subproject.projectDir.resolve(documentationFileName).absolutePath - } + .flatMap { subProject -> dokkaTaskNames.mapNotNull(subProject.tasks::findByName) } + .filterIsInstance() + .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 } } } 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 9bcbe9e0..09088968 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 @@ -51,7 +51,6 @@ open class DokkaTask : DefaultTask(), Configurable { @Input var outputDirectory: String = "" - @Input var subProjects: List = emptyList() @@ -65,12 +64,15 @@ open class DokkaTask : DefaultTask(), Configurable { @Classpath val runtime = project.configurations.create("${name}Runtime").apply { defaultDependencies { dependencies -> - dependencies.add(project.dependencies.create("org.jetbrains.dokka:dokka-core:${DokkaVersion.version}")) + dependencies.add(project.dokkaDependencies.dokkaCore) } } @Classpath val plugins: Configuration = project.configurations.create("${name}Plugin").apply { + defaultDependencies { dependencies -> + dependencies.add(project.dokkaDependencies.dokkaBase) + } attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, "java-runtime")) isCanBeConsumed = false } 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 60750373..b32a3967 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,38 +2,53 @@ package org.jetbrains.dokka.gradle import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.kotlin.dsl.register -import org.jetbrains.dokka.DokkaVersion +import org.gradle.kotlin.dsl.create import java.io.File -internal const val DOKKA_TASK_NAME = "dokka" -internal const val DOKKA_COLLECTOR_TASK_NAME = "dokkaCollector" -internal const val DOKKA_MULTIMODULE_TASK_NAME = "dokkaMultimodule" - open class DokkaPlugin : Plugin { override fun apply(project: Project) { - addDokkaTasks(project) - addDokkaCollectorTasks(project) - addDokkaMultimoduleTasks(project.rootProject) - } + project.createDokkaTasks("dokka") - private fun addDokkaTasks(project: Project) { - project.tasks.register(DOKKA_TASK_NAME) { - val dokkaBase = project.dependencies.create("org.jetbrains.dokka:dokka-base:${DokkaVersion.version}") - plugins.dependencies.add(dokkaBase) - outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath + project.createDokkaTasks("dokkaJavadoc") { + plugins.dependencies.add(project.dokkaDependencies.javadocPlugin) + } + + project.createDokkaTasks("dokkaGfm") { + plugins.dependencies.add(project.dokkaDependencies.gfmPlugin) } - } - private fun addDokkaCollectorTasks(project: Project) { - project.tasks.register(DOKKA_COLLECTOR_TASK_NAME) { - outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath + project.createDokkaTasks("dokkaJekyll") { + plugins.dependencies.add(project.dokkaDependencies.jekyllPlugin) } } - private fun addDokkaMultimoduleTasks(project: Project) { - project.tasks.register(DOKKA_MULTIMODULE_TASK_NAME) { - outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath + /** + * Creates [DokkaTask], [DokkaMultimoduleTask] and [DokkaCollectorTask] for the given + * name and configuration. + * + * The tasks are created, not registered to enable gradle's accessor generation like + * ``` + * dependencies { + * dokkaPlugin(":my-group:my-plugin:my-version) + * } + * ``` + * + * There is no heavy processing done during configuration of those tasks (I promise). + */ + private fun Project.createDokkaTasks(name: String, configuration: DokkaTask.() -> Unit = {}) { + project.tasks.create(name) { + outputDirectory = File(buildDir, name).absolutePath + configuration() + } + + project.tasks.create("${name}Collector") { + outputDirectory = File(buildDir, name).absolutePath + dokkaTaskNames.add(name) + } + + project.tasks.create("${name}Multimodule") { + outputDirectory = File(buildDir, name).absolutePath + dokkaTaskNames.add(name) } } } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt index a4bf65ee..f613f6a7 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt @@ -10,9 +10,9 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinTarget internal fun Project.isAndroidProject() = try { project.extensions.getByName("android") true -} catch(e: UnknownDomainObjectException) { +} catch (e: UnknownDomainObjectException) { false -} catch(e: ClassNotFoundException) { +} catch (e: ClassNotFoundException) { false } @@ -21,12 +21,22 @@ internal fun Project.isNotMultiplatformProject() = !isMultiplatformProject() internal fun Project.isMultiplatformProject() = try { project.extensions.getByType(KotlinMultiplatformExtension::class.java) true -} catch(e: UnknownDomainObjectException) { +} catch (e: UnknownDomainObjectException) { false -} catch (e: NoClassDefFoundError){ +} catch (e: NoClassDefFoundError) { false -} catch(e: ClassNotFoundException) { +} catch (e: ClassNotFoundException) { false } -internal fun KotlinTarget.isAndroidTarget() = this.platformType == KotlinPlatformType.androidJvm \ No newline at end of file +internal fun KotlinTarget.isAndroidTarget() = this.platformType == KotlinPlatformType.androidJvm + +// TODO NOW: Test +internal fun Project.allDescendentProjects(): Sequence { + return sequence { + yieldAll(subprojects) + subprojects.forEach { subproject -> + yieldAll(subproject.allDescendentProjects()) + } + } +} -- cgit