aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin
diff options
context:
space:
mode:
authorPaweł Marks <pmarks@virtuslab.com>2019-11-25 15:34:47 +0100
committerPaweł Marks <pmarks@virtuslab.com>2019-11-26 15:27:04 +0100
commita945617725e8df084270aacd5af76da2b911111e (patch)
treef752ceb1427108d052575440c339b61bcd6bb5a9 /core/src/main/kotlin
parent4b1a3a2cbe62f98c9f1b472e70d754645d7f8641 (diff)
downloaddokka-a945617725e8df084270aacd5af76da2b911111e.tar.gz
dokka-a945617725e8df084270aacd5af76da2b911111e.tar.bz2
dokka-a945617725e8df084270aacd5af76da2b911111e.zip
Interface segregation in plugins api
Diffstat (limited to 'core/src/main/kotlin')
-rw-r--r--core/src/main/kotlin/DokkaGenerator.kt4
-rw-r--r--core/src/main/kotlin/plugability/DokkaContext.kt82
-rw-r--r--core/src/main/kotlin/plugability/DokkaPlugin.kt14
3 files changed, 54 insertions, 46 deletions
diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt
index b29a0da2..05eb3054 100644
--- a/core/src/main/kotlin/DokkaGenerator.kt
+++ b/core/src/main/kotlin/DokkaGenerator.kt
@@ -25,9 +25,7 @@ class DokkaGenerator(
fun generate(): Unit {
logger.debug("Initializing plugins")
- val context = DokkaContext.from(configuration.pluginsClasspath)
- logger.progress("Loaded plugins: ${context.pluginNames}")
- logger.progress("Loaded: ${context.loadedListForDebug}")
+ val context = DokkaContext.create(configuration.pluginsClasspath, logger)
configuration.passesConfigurations.map { pass ->
AnalysisEnvironment(DokkaMessageCollector(logger), pass.analysisPlatform).run {
diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt
index dcd3398e..7727329c 100644
--- a/core/src/main/kotlin/plugability/DokkaContext.kt
+++ b/core/src/main/kotlin/plugability/DokkaContext.kt
@@ -1,55 +1,75 @@
package org.jetbrains.dokka.plugability
+import org.jetbrains.dokka.DokkaLogger
import java.io.File
import java.net.URLClassLoader
import java.util.*
import kotlin.reflect.KClass
+interface DokkaContext {
+ operator fun <T : Any, E : ExtensionPoint<T>> get(point: E): List<Extension<T>>
-class DokkaContext private constructor() {
+ fun <T : DokkaPlugin> plugin(kclass: KClass<T>): T?
+
+ val logger: DokkaLogger
+
+ companion object {
+ fun create(pluginsClasspath: Iterable<File>, logger: DokkaLogger): DokkaContext =
+ DokkaContextConfigurationImpl(logger).apply {
+ pluginsClasspath.map { it.relativeTo(File(".").absoluteFile).toURI().toURL() }
+ .toTypedArray()
+ .let { URLClassLoader(it, this.javaClass.classLoader) }
+ .also { checkClasspath(it) }
+ .let { ServiceLoader.load(DokkaPlugin::class.java, it) }
+ .forEach { install(it) }
+ }.also { it.logInitialisationInfo() }
+ }
+}
+
+interface DokkaContextConfiguration {
+ fun addExtension(extension: Extension<*>)
+}
+
+private class DokkaContextConfigurationImpl(
+ override val logger: DokkaLogger
+) : DokkaContext, DokkaContextConfiguration {
private val plugins = mutableMapOf<KClass<*>, DokkaPlugin>()
internal val extensions = mutableMapOf<ExtensionPoint<*>, MutableList<Extension<*>>>()
@Suppress("UNCHECKED_CAST")
- operator fun <T: Any, E: ExtensionPoint<T>> get(point: E) = extensions[point] as List<Extension<T>>
-
- @PublishedApi
- internal fun plugin(kclass: KClass<*>) = plugins[kclass]
-
- val pluginNames: List<String>
- get() = plugins.values.map { it::class.qualifiedName.toString() }
+ override operator fun <T : Any, E : ExtensionPoint<T>> get(point: E) = extensions[point] as List<Extension<T>>
- val loadedListForDebug
- get() = extensions.run { keys + values.flatten() }.toList()
- .joinToString(prefix = "[\n", separator = ",\n", postfix = "\n]") { "\t$it" }
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : DokkaPlugin> plugin(kclass: KClass<T>) = plugins[kclass] as T
- private fun install(plugin: DokkaPlugin) {
+ fun install(plugin: DokkaPlugin) {
plugins[plugin::class] = plugin
+ plugin.context = this
plugin.internalInstall(this)
}
- companion object {
- fun from(pluginsClasspath: Iterable<File>) = DokkaContext().apply {
- pluginsClasspath.map { it.relativeTo(File(".").absoluteFile).toURI().toURL() }
- .toTypedArray()
- .let { URLClassLoader(it, this.javaClass.classLoader) }
- .also { checkClasspath(it) }
- .let { ServiceLoader.load(DokkaPlugin::class.java, it) }
- .forEach { install(it) }
- }
+ override fun addExtension(extension: Extension<*>) {
+ extensions.getOrPut(extension.extensionPoint, ::mutableListOf) += extension
}
- private fun checkClasspath(classLoader: URLClassLoader) {
- classLoader.findResource(javaClass.name.replace('.', '/') + ".class")?.also {
- throw AssertionError(
- "Dokka API found on plugins classpath. This will lead to subtle bugs. " +
- "Please fix your plugins dependencies or exclude dokka api artifact from plugin classpath"
- )
- }
- }
+ fun logInitialisationInfo() {
+ val pluginNames: List<String> = plugins.values.map { it::class.qualifiedName.toString() }
+
+ val loadedListForDebug = extensions.run { keys + values.flatten() }.toList()
+ .joinToString(prefix = "[\n", separator = ",\n", postfix = "\n]") { "\t$it" }
+
+ logger.progress("Loaded plugins: ${pluginNames}")
+ logger.progress("Loaded: ${loadedListForDebug}")
- internal fun addExtension(it: Extension<*>) {
- extensions.getOrPut(it.extensionPoint, ::mutableListOf) += it
}
}
+
+private fun checkClasspath(classLoader: URLClassLoader) {
+ classLoader.findResource(DokkaContext::class.java.name.replace('.', '/') + ".class")?.also {
+ throw AssertionError(
+ "Dokka API found on plugins classpath. This will lead to subtle bugs. " +
+ "Please fix your plugins dependencies or exclude dokka api artifact from plugin classpath"
+ )
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/plugability/DokkaPlugin.kt b/core/src/main/kotlin/plugability/DokkaPlugin.kt
index 60ca245c..663cf88e 100644
--- a/core/src/main/kotlin/plugability/DokkaPlugin.kt
+++ b/core/src/main/kotlin/plugability/DokkaPlugin.kt
@@ -3,12 +3,7 @@ package org.jetbrains.dokka.plugability
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
-import kotlin.reflect.KTypeProjection
import kotlin.reflect.full.createInstance
-import kotlin.reflect.full.createType
-import kotlin.reflect.full.declaredMemberProperties
-import kotlin.reflect.jvm.isAccessible
-import kotlin.reflect.jvm.jvmErasure
private typealias ExtensionDelegate<T> = ReadOnlyProperty<DokkaPlugin, Extension<T>>
@@ -18,10 +13,8 @@ abstract class DokkaPlugin {
@PublishedApi
internal var context: DokkaContext? = null
- protected open fun install(context: DokkaContext) {}
-
protected inline fun <reified T : DokkaPlugin> plugin(): T =
- context?.plugin(T::class) as? T ?: T::class.createInstance().also { it.context = this.context }
+ context?.plugin(T::class) ?: T::class.createInstance().also { it.context = this.context }
protected fun <T : Any> extensionPoint() =
object : ReadOnlyProperty<DokkaPlugin, ExtensionPoint<T>> {
@@ -44,10 +37,7 @@ abstract class DokkaPlugin {
}.also { thisRef.extensionDelegates += property }
}
- internal fun internalInstall(ctx: DokkaContext) {
- context = ctx
- install(ctx)
-
+ internal fun internalInstall(ctx: DokkaContextConfiguration) {
extensionDelegates.asSequence()
.filterIsInstance<KProperty1<DokkaPlugin, Extension<*>>>() // always true
.map { it.get(this) }