diff options
9 files changed, 97 insertions, 34 deletions
diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index 19835fa4..34671c4e 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -33,6 +33,7 @@ interface DokkaConfiguration { val passesConfigurations: List<PassConfiguration> val impliedPlatforms: List<String> val pluginsClasspath: List<File> + val pluginsConfiguration: Map<String, String> interface PassConfiguration { val moduleName: String @@ -100,3 +101,5 @@ interface DokkaConfiguration { } } } + + diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index b0c12015..ae674ea1 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -10,7 +10,8 @@ data class DokkaConfigurationImpl( override val cacheRoot: String?, override val impliedPlatforms: List<String>, override val passesConfigurations: List<PassConfigurationImpl>, - override var pluginsClasspath: List<File> + override val pluginsClasspath: List<File>, + override val pluginsConfiguration: Map<String, String> ) : DokkaConfiguration data class PassConfigurationImpl ( diff --git a/core/src/main/kotlin/plugability/DokkaPlugin.kt b/core/src/main/kotlin/plugability/DokkaPlugin.kt index d8fb7892..24f417d8 100644 --- a/core/src/main/kotlin/plugability/DokkaPlugin.kt +++ b/core/src/main/kotlin/plugability/DokkaPlugin.kt @@ -1,9 +1,12 @@ package org.jetbrains.dokka.plugability +import com.google.gson.Gson import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.kotlin.utils.addToStdlib.cast import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty import kotlin.reflect.KProperty1 +import kotlin.reflect.full.createInstance private typealias ExtensionDelegate<T> = ReadOnlyProperty<DokkaPlugin, Extension<T>> @@ -49,6 +52,18 @@ abstract class DokkaPlugin { } } +interface Configurable { + val pluginsConfiguration: Map<String, String> +} + +interface ConfigurableBlock + +inline fun <reified P : DokkaPlugin, reified T : ConfigurableBlock> Configurable.pluginConfiguration(block: T.() -> Unit) { + val instance = T::class.createInstance().apply(block) + pluginsConfiguration.cast<MutableMap<String, String>>()[P::class.qualifiedName!!] = + Gson().toJson(instance, T::class.java) +} + inline fun <reified P : DokkaPlugin, reified E : Any> P.query(extension: P.() -> ExtensionPoint<E>): List<E> = context?.let { it[extension()] } ?: throwIllegalQuery() @@ -57,3 +72,14 @@ inline fun <reified P : DokkaPlugin, reified E : Any> P.querySingle(extension: P fun throwIllegalQuery(): Nothing = throw IllegalStateException("Querying about plugins is only possible with dokka context initialised") + +inline fun <reified T : DokkaPlugin, reified R : ConfigurableBlock> configuration(context: DokkaContext): ReadOnlyProperty<Any?, R> { + return object : ReadOnlyProperty<Any?, R> { + override fun getValue(thisRef: Any?, property: KProperty<*>): R { + return context.configuration.pluginsConfiguration.get(T::class.qualifiedName + ?: throw AssertionError("Plugin must be named class")).let { + Gson().fromJson(it, R::class.java) + } + } + } +}
\ No newline at end of file diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 50aadf00..dca97ec6 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -54,6 +54,8 @@ open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { ) { Arguments(parser).also { if(it.moduleName.isEmpty()) DokkaConsoleLogger.warn("Not specified module name. It can result in unexpected behaviour while including documentation for module") } } + + override val pluginsConfiguration: Map<String, String> = mutableMapOf() } class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfiguration { 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 fda1017a..2018d3af 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,5 +1,6 @@ package org.jetbrains.dokka.gradle +import com.google.gson.Gson import com.google.gson.GsonBuilder import org.gradle.api.* import org.gradle.api.artifacts.Configuration @@ -14,13 +15,14 @@ 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.dokka.plugability.Configurable 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 : DefaultTask(), Configurable { 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 @@ -58,12 +60,14 @@ open class DokkaTask : DefaultTask() { @Input var impliedPlatforms: MutableList<String> = arrayListOf() + override val pluginsConfiguration: Map<String, String> = mutableMapOf() + @Optional @Input var cacheRoot: String? = null @Classpath - lateinit var pluginsConfiguration: Configuration + lateinit var pluginsConfig: Configuration var multiplatform: NamedDomainObjectContainer<GradlePassConfigurationImpl> @Suppress("UNCHECKED_CAST") @@ -80,19 +84,26 @@ open class DokkaTask : DefaultTask() { // Configure Dokka with closure in Gradle Kotlin DSL fun configuration(action: Action<in GradlePassConfigurationImpl>) = action.execute(configuration) - private val kotlinTasks: List<Task> by lazy { extractKotlinCompileTasks(configuration.collectKotlinTasks ?: { defaultKotlinTasks() }) } + private val kotlinTasks: List<Task> by lazy { + extractKotlinCompileTasks( + configuration.collectKotlinTasks ?: { defaultKotlinTasks() }) + } private val configExtractor = ConfigurationExtractor(project) @Input var disableAutoconfiguration: Boolean = false - private var outputDiagnosticInfo: Boolean = false // Workaround for Gradle, which fires some methods (like collectConfigurations()) multiple times in its lifecycle + private var outputDiagnosticInfo: Boolean = + false // Workaround for Gradle, which fires some methods (like collectConfigurations()) multiple times in its lifecycle private fun loadFatJar() { if (ClassloaderContainer.fatJarClassLoader == null) { val jars = dokkaRuntime!!.resolve() - ClassloaderContainer.fatJarClassLoader = URLClassLoader(jars.map { it.toURI().toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader().parent) + ClassloaderContainer.fatJarClassLoader = URLClassLoader( + jars.map { it.toURI().toURL() }.toTypedArray(), + ClassLoader.getSystemClassLoader().parent + ) } } @@ -102,7 +113,9 @@ open class DokkaTask : DefaultTask() { val taskContainer = project.tasks - val tasksByPath = paths.map { taskContainer.findByPath(it as String) ?: throw IllegalArgumentException("Task with path '$it' not found") } + val tasksByPath = paths.map { + taskContainer.findByPath(it as String) ?: throw IllegalArgumentException("Task with path '$it' not found") + } other .filter { it !is Task || it isNotInstance getAbstractKotlinCompileFor(it) } @@ -116,11 +129,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) } private fun collectSuppressedFiles(sourceRoots: List<SourceRoot>) = - if(project.isAndroidProject()) { + if (project.isAndroidProject()) { val generatedRoot = project.buildDir.resolve("generated").absoluteFile sourceRoots .map { File(it.path) } @@ -143,7 +159,8 @@ open class DokkaTask : DefaultTask() { try { loadFatJar() - val bootstrapClass = ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl") + val bootstrapClass = + ClassloaderContainer.fatJarClassLoader!!.loadClass("org.jetbrains.dokka.DokkaBootstrapImpl") val bootstrapInstance = bootstrapClass.constructors.first().newInstance() val bootstrapProxy: DokkaBootstrap = automagicTypedProxy(javaClass.classLoader, bootstrapInstance) @@ -181,7 +198,8 @@ open class DokkaTask : DefaultTask() { cacheRoot = cacheRoot impliedPlatforms = impliedPlatforms passesConfigurations = defaultModulesConfiguration - pluginsClasspath = pluginsConfiguration.resolve().toList() + pluginsClasspath = pluginsConfig.resolve().toList() + pluginsConfiguration = this@DokkaTask.pluginsConfiguration } } @@ -206,15 +224,17 @@ open class DokkaTask : DefaultTask() { val baseConfig = configExtractor.extractConfiguration(userConfig.name, userConfig.androidVariant) ?.let { mergeUserConfigurationAndPlatformData(userConfig, it) } - ?: if (this.isMultiplatformProject()) { - if (outputDiagnosticInfo) - logger.warn("Could not find target with name: ${userConfig.name} in Kotlin Gradle Plugin, " + - "using only user provided configuration for this target") - userConfig - } else { - logger.warn("Could not find target with name: ${userConfig.name} in Kotlin Gradle Plugin") - collectFromSinglePlatformOldPlugin() - } + ?: if (this.isMultiplatformProject()) { + if (outputDiagnosticInfo) + logger.warn( + "Could not find target with name: ${userConfig.name} in Kotlin Gradle Plugin, " + + "using only user provided configuration for this target" + ) + userConfig + } else { + logger.warn("Could not find target with name: ${userConfig.name} in Kotlin Gradle Plugin") + collectFromSinglePlatformOldPlugin() + } return if (subProjects.isNotEmpty()) { try { @@ -224,9 +244,11 @@ open class DokkaTask : DefaultTask() { ConfigurationExtractor(subProject).extractConfiguration(config.name, config.androidVariant)!! ) } - } catch(e: NullPointerException) { - logger.warn("Cannot extract sources from subProjects. Do you have the Kotlin plugin in version 1.3.30+ " + - "and the Kotlin plugin applied in the root project?") + } catch (e: NullPointerException) { + logger.warn( + "Cannot extract sources from subProjects. Do you have the Kotlin plugin in version 1.3.30+ " + + "and the Kotlin plugin applied in the root project?" + ) baseConfig } } else { @@ -237,11 +259,14 @@ open class DokkaTask : DefaultTask() { private fun collectFromSinglePlatformOldPlugin() = configExtractor.extractFromKotlinTasks(kotlinTasks) ?.let { mergeUserConfigurationAndPlatformData(configuration, it) } - ?: configExtractor.extractFromJavaPlugin() - ?.let { mergeUserConfigurationAndPlatformData(configuration, it) } - ?: configuration - - private fun mergeUserConfigurationAndPlatformData(userConfig: GradlePassConfigurationImpl, autoConfig: PlatformData) = + ?: configExtractor.extractFromJavaPlugin() + ?.let { mergeUserConfigurationAndPlatformData(configuration, it) } + ?: configuration + + private fun mergeUserConfigurationAndPlatformData( + userConfig: GradlePassConfigurationImpl, + autoConfig: PlatformData + ) = userConfig.copy().apply { sourceRoots.addAll(userConfig.sourceRoots.union(autoConfig.sourceRoots.toSourceRoots()).distinct()) classpath = userConfig.classpath.union(autoConfig.classpath.map { it.absolutePath }).distinct() @@ -256,10 +281,11 @@ open class DokkaTask : DefaultTask() { if (config.moduleName == "") { config.moduleName = project.name } - if (config.targets.isEmpty() && multiplatform.isNotEmpty()){ + if (config.targets.isEmpty() && multiplatform.isNotEmpty()) { config.targets = listOf(config.name) } - config.classpath = (config.classpath as List<Any>).map { it.toString() }.distinct() // Workaround for Groovy's GStringImpl + config.classpath = + (config.classpath as List<Any>).map { it.toString() }.distinct() // Workaround for Groovy's GStringImpl config.sourceRoots = config.sourceRoots.distinct().toMutableList() config.samples = config.samples.map { project.file(it).absolutePath } config.includes = config.includes.map { project.file(it).absolutePath } @@ -314,3 +340,4 @@ open class DokkaTask : DefaultTask() { } } } + 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 3b3b3f96..570da5f3 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 @@ -125,6 +125,7 @@ class GradleDokkaConfigurationImpl: DokkaConfiguration { override var impliedPlatforms: List<String> = emptyList() override var passesConfigurations: List<GradlePassConfigurationImpl> = emptyList() override var pluginsClasspath: List<File> = emptyList() + override var pluginsConfiguration: Map<String, String> = mutableMapOf() } 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 2ece238f..1d93a310 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 @@ -48,7 +48,7 @@ open class DokkaPlugin : Plugin<Project> { task.multiplatform = project.container(GradlePassConfigurationImpl::class.java) task.configuration = GradlePassConfigurationImpl() task.dokkaRuntime = runtimeConfiguration - task.pluginsConfiguration = pluginsConfiguration + task.pluginsConfig = pluginsConfiguration task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath } } diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index 49c6fba6..24d95ab4 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -249,7 +249,8 @@ abstract class AbstractDokkaMojo : AbstractMojo() { }, generateIndexPages = generateIndexPages, pluginsClasspath = getArtifactByAether("org.jetbrains.dokka", "dokka-base", dokkaVersion) + - dokkaPlugins.map { getArtifactByAether(it.groupId, it.artifactId, it.version) }.flatten() + dokkaPlugins.map { getArtifactByAether(it.groupId, it.artifactId, it.version) }.flatten(), + pluginsConfiguration = mutableMapOf() //TODO implement as it is in Gradle ) val gen = DokkaGenerator(configuration, logger) diff --git a/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt b/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt index 26b9a4b6..6c132d3c 100644 --- a/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt +++ b/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt @@ -140,6 +140,7 @@ abstract class AbstractCoreTest { var generateIndexPages: Boolean = true var cacheRoot: String? = null var pluginsClasspath: List<File> = emptyList() + var pluginsConfigurations: Map<String, String> = emptyMap() private val passesConfigurations = mutableListOf<PassConfigurationImpl>() fun build() = DokkaConfigurationImpl( outputDir = outputDir, @@ -148,7 +149,8 @@ abstract class AbstractCoreTest { cacheRoot = cacheRoot, impliedPlatforms = emptyList(), passesConfigurations = passesConfigurations, - pluginsClasspath = pluginsClasspath + pluginsClasspath = pluginsClasspath, + pluginsConfiguration = pluginsConfigurations ) fun passes(block: Passes.() -> Unit) { |