From 6dc9498ca849645ecb4ec923bb7116b245dca706 Mon Sep 17 00:00:00 2001
From: Błażej Kardyś <bkardys@virtuslab.com>
Date: Wed, 27 May 2020 01:16:48 +0200
Subject: All modules page generation

---
 .../jetbrains/dokka/gradle/DokkaMultimoduleTask.kt | 97 ++++++++++++++++++++++
 .../dokka/gradle/configurationImplementations.kt   |  7 ++
 .../main/kotlin/org/jetbrains/dokka/gradle/main.kt | 24 +++++-
 3 files changed, 127 insertions(+), 1 deletion(-)
 create mode 100644 runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt

(limited to 'runners/gradle-plugin/src')

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..a1bfdb96
--- /dev/null
+++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultimoduleTask.kt
@@ -0,0 +1,97 @@
+package org.jetbrains.dokka.gradle
+
+import com.google.gson.GsonBuilder
+import org.gradle.api.DefaultTask
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.TaskAction
+import org.jetbrains.dokka.DokkaBootstrap
+import org.jetbrains.dokka.plugability.Configurable
+import java.net.URLClassLoader
+import java.util.function.BiConsumer
+
+open class DokkaMultimoduleTask : DefaultTask(), Configurable {
+
+    @Input
+    var documentationFileName: String = "README.md"
+
+    @Input
+    var outputFormat: String = "html"
+
+    @Input
+    var outputDirectory: String = ""
+
+    @Classpath
+    lateinit var pluginsConfig: Configuration
+
+    var dokkaRuntime: Configuration? = null
+
+    override val pluginsConfiguration: Map<String, String> = mutableMapOf()
+
+    @TaskAction
+    fun dokkaMultiplatform() {
+        val kotlinColorsEnabledBefore = System.getProperty(DokkaTask.COLORS_ENABLED_PROPERTY) ?: "false"
+        System.setProperty(DokkaTask.COLORS_ENABLED_PROPERTY, "false")
+
+        try {
+            loadFatJar()
+            val bootstrapClass =
+                ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaMultimoduleBootstrapImpl")
+            val bootstrapInstance = bootstrapClass.constructors.first().newInstance()
+            val bootstrapProxy: DokkaBootstrap = automagicTypedProxy(
+                javaClass.classLoader,
+                bootstrapInstance
+            )
+            val gson = GsonBuilder().setPrettyPrinting().create()
+            val configuration = getConfiguration()
+            bootstrapProxy.configure(
+                BiConsumer { level, message ->
+                    when (level) {
+                        "debug" -> logger.debug(message)
+                        "info" -> logger.info(message)
+                        "progress" -> logger.lifecycle(message)
+                        "warn" -> logger.warn(message)
+                        "error" -> logger.error(message)
+                    }
+                },
+                gson.toJson(configuration)
+            )
+
+            bootstrapProxy.generate()
+        } finally {
+            System.setProperty(DokkaTask.COLORS_ENABLED_PROPERTY, kotlinColorsEnabledBefore)
+        }
+    }
+
+    internal fun getConfiguration(): GradleDokkaConfigurationImpl =
+        GradleDokkaConfigurationImpl().apply {
+            outputDir = project.file(outputDirectory).absolutePath
+            format = outputFormat
+            pluginsClasspath = pluginsConfig.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
+                        }
+                    }
+                }
+        }
+
+    private fun loadFatJar() {
+        if (ClassloaderContainer.fatJarClassLoader == null) {
+            val jars = dokkaRuntime!!.resolve()
+            ClassloaderContainer.fatJarClassLoader = URLClassLoader(
+                jars.map { it.toURI().toURL() }.toTypedArray(),
+                ClassLoader.getSystemClassLoader().parent
+            )
+        }
+    }
+}
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 5c300cc3..7fdadd41 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
@@ -120,6 +120,12 @@ class GradleExternalDocumentationLinkImpl : ExternalDocumentationLink, Serializa
     override var packageListUrl: URL = URL("http://")
 }
 
+class GradleDokkaModuleDescription: DokkaModuleDescription {
+    override var name: String = ""
+    override var path: String = ""
+    override var docFile: String = ""
+}
+
 class GradleDokkaConfigurationImpl: DokkaConfiguration {
     override var outputDir: String = ""
     override var format: String = "html"
@@ -129,6 +135,7 @@ class GradleDokkaConfigurationImpl: DokkaConfiguration {
     override var passesConfigurations: List<GradlePassConfigurationImpl> = emptyList()
     override var pluginsClasspath: List<File> = emptyList()
     override var pluginsConfiguration: Map<String, String> = mutableMapOf()
+    override var modules: List<GradleDokkaModuleDescription> = emptyList()
 }
 
 class GradlePackageOptionsImpl: PackageOptions, Serializable {
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 fea0d864..1049656e 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
@@ -12,6 +12,7 @@ internal const val CONFIGURATION_EXTENSION_NAME = "configuration"
 internal const val SOURCE_SETS_EXTENSION_NAME = "dokkaSourceSets"
 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<Project> {
 
@@ -23,6 +24,7 @@ open class DokkaPlugin : Plugin<Project> {
         }
         addDokkaTasks(project, dokkaRuntimeConfiguration, pluginsConfiguration, DokkaTask::class.java)
         addDokkaCollectorTasks(project, DokkaCollectorTask::class.java)
+        addDokkaMultimoduleTasks(project.rootProject, dokkaRuntimeConfiguration, pluginsConfiguration, DokkaMultimoduleTask::class.java)
     }
 
     private fun loadDokkaVersion() =
@@ -49,7 +51,7 @@ open class DokkaPlugin : Plugin<Project> {
             task.configuration = GradlePassConfigurationImpl()
             task.dokkaRuntime = runtimeConfiguration
             task.pluginsConfig = pluginsConfiguration
-            task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath
+            task.outputDirectory = File(project.rootProject.buildDir, "$DOKKA_TASK_NAME/${project.name}").absolutePath
         }
     }
 
@@ -67,6 +69,26 @@ open class DokkaPlugin : Plugin<Project> {
             task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath
         }
     }
+
+    private fun addDokkaMultimoduleTasks(
+        project: Project,
+        runtimeConfiguration: Configuration,
+        pluginsConfiguration: Configuration,
+        taskClass: Class<out DokkaMultimoduleTask>
+    ) {
+        if (project.tasks.find { it.name == DOKKA_MULTIMODULE_TASK_NAME } == null) {
+            if (GradleVersion.current() >= GradleVersion.version("4.10")) {
+                project.tasks.register(DOKKA_MULTIMODULE_TASK_NAME, taskClass)
+            } else {
+                project.tasks.create(DOKKA_MULTIMODULE_TASK_NAME, taskClass)
+            }
+            project.tasks.withType(taskClass) { task ->
+                task.dokkaRuntime = runtimeConfiguration
+                task.pluginsConfig = pluginsConfiguration
+                task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath
+            }
+        }
+    }
 }
 
 object DokkaVersion {
-- 
cgit