diff options
-rw-r--r-- | .idea/jarRepositories.xml | 80 | ||||
-rw-r--r-- | core/src/main/kotlin/plugability/DokkaContext.kt | 52 | ||||
-rw-r--r-- | core/src/main/kotlin/plugability/DokkaPlugin.kt | 4 | ||||
-rw-r--r-- | core/src/main/kotlin/plugability/extensions.kt | 41 |
4 files changed, 162 insertions, 15 deletions
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 00000000..d92018c5 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="RemoteRepositoriesConfiguration"> + <remote-repository> + <option name="id" value="central" /> + <option name="name" value="Maven Central repository" /> + <option name="url" value="https://repo1.maven.org/maven2" /> + </remote-repository> + <remote-repository> + <option name="id" value="jboss.community" /> + <option name="name" value="JBoss Community repository" /> + <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven8" /> + <option name="name" value="maven8" /> + <option name="url" value="https://www.jetbrains.com/intellij-repository/snapshots" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven5" /> + <option name="name" value="maven5" /> + <option name="url" value="https://kotlin.bintray.com/kotlinx" /> + </remote-repository> + <remote-repository> + <option name="id" value="MavenRepo" /> + <option name="name" value="MavenRepo" /> + <option name="url" value="https://repo.maven.apache.org/maven2/" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven4" /> + <option name="name" value="maven4" /> + <option name="url" value="https://teamcity.jetbrains.com/guestAuth/repository/download/Kotlin_dev_CompilerAllPlugins/1.3.20-dev-564/maven" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven7" /> + <option name="name" value="maven7" /> + <option name="url" value="https://dl.bintray.com/orangy/maven" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven" /> + <option name="name" value="maven" /> + <option name="url" value="https://dl.bintray.com/jetbrains/markdown" /> + </remote-repository> + <remote-repository> + <option name="id" value="BintrayJCenter" /> + <option name="name" value="BintrayJCenter" /> + <option name="url" value="https://jcenter.bintray.com/" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven9" /> + <option name="name" value="maven9" /> + <option name="url" value="https://www.jetbrains.com/intellij-repository/releases" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven2" /> + <option name="name" value="maven2" /> + <option name="url" value="https://dl.bintray.com/kotlin/kotlin-eap" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven3" /> + <option name="name" value="maven3" /> + <option name="url" value="https://dl.bintray.com/kotlin/kotlin-dev" /> + </remote-repository> + <remote-repository> + <option name="id" value="MavenLocal" /> + <option name="name" value="MavenLocal" /> + <option name="url" value="file:$MAVEN_REPOSITORY$" /> + </remote-repository> + <remote-repository> + <option name="id" value="maven6" /> + <option name="name" value="maven6" /> + <option name="url" value="https://dl.bintray.com/kotlin/kotlinx" /> + </remote-repository> + <remote-repository> + <option name="id" value="Google" /> + <option name="name" value="Google" /> + <option name="url" value="https://dl.google.com/dl/android/maven2/" /> + </remote-repository> + </component> +</project>
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt index 7b1c1306..8709b74f 100644 --- a/core/src/main/kotlin/plugability/DokkaContext.kt +++ b/core/src/main/kotlin/plugability/DokkaContext.kt @@ -36,6 +36,7 @@ interface DokkaContext : DokkaExtensionHandler { .also { checkClasspath(it) } .let { ServiceLoader.load(DokkaPlugin::class.java, it) } .forEach { install(it) } + applyExtensions() }.also { it.logInitialisationInfo() } } } @@ -54,7 +55,7 @@ fun <T, E> DokkaContext.single(point: E): T where T : Any, E : ExtensionPoint<T> } interface DokkaContextConfiguration { - fun addExtension(extension: Extension<*>) + fun addExtensionDependencies(extension: Extension<*>) } private class DokkaContextConfigurationImpl( @@ -63,11 +64,43 @@ private class DokkaContextConfigurationImpl( override val platforms: Map<PlatformData, EnvironmentAndFacade> ) : DokkaContext, DokkaContextConfiguration { private val plugins = mutableMapOf<KClass<*>, DokkaPlugin>() - private val pluginStubs = mutableMapOf<KClass<*>, DokkaPlugin>() - internal val extensions = mutableMapOf<ExtensionPoint<*>, MutableList<Extension<*>>>() + private enum class State { + UNVISITED, + VISITING, + VISITED; + } + + internal val verticesWithState = mutableMapOf<Extension<*>, State>() + internal val adjacencyList: MutableMap<Extension<*>, MutableList<Extension<*>>> = mutableMapOf() + + private fun topologicalSort() { + + val result: MutableList<Extension<*>> = mutableListOf() + + fun visit(n: Extension<*>) { + val state = verticesWithState[n] + if(state == State.VISITED) + return + if(state == State.VISITING) + throw Error("Detected cycle in plugins graph") + verticesWithState[n] = State.VISITING + adjacencyList[n]?.forEach { visit(it) } + verticesWithState[n] = State.VISITED + result += n + } + + for((vertex, state) in verticesWithState) { + if(state == State.UNVISITED) + visit(vertex) + } + result.asReversed().forEach { + extensions.getOrPut(it.extensionPoint, ::mutableListOf) += it + } + } + @Suppress("UNCHECKED_CAST") override operator fun <T, E> get(point: E, askDefault: AskDefault) where T : Any, E : ExtensionPoint<T> = when (askDefault) { @@ -91,8 +124,13 @@ private class DokkaContextConfigurationImpl( plugin.internalInstall(this) } - override fun addExtension(extension: Extension<*>) { - extensions.getOrPut(extension.extensionPoint, ::mutableListOf) += extension + override fun addExtensionDependencies(extension: Extension<*>) { + val orderDsl = OrderDsl() + extension.ordering?.invoke(orderDsl) + + verticesWithState += extension to State.UNVISITED + adjacencyList.getOrPut(extension, ::mutableListOf) += orderDsl.following.toList() + orderDsl.previous.forEach { adjacencyList.getOrPut(it, ::mutableListOf) += extension } } fun logInitialisationInfo() { @@ -105,6 +143,10 @@ private class DokkaContextConfigurationImpl( logger.progress("Loaded: $loadedListForDebug") } + + fun applyExtensions() { + topologicalSort() + } } private fun checkClasspath(classLoader: URLClassLoader) { diff --git a/core/src/main/kotlin/plugability/DokkaPlugin.kt b/core/src/main/kotlin/plugability/DokkaPlugin.kt index 7a968b8b..3f82000d 100644 --- a/core/src/main/kotlin/plugability/DokkaPlugin.kt +++ b/core/src/main/kotlin/plugability/DokkaPlugin.kt @@ -40,8 +40,6 @@ abstract class DokkaPlugin { extensionDelegates.asSequence() .filterIsInstance<KProperty1<DokkaPlugin, Extension<*>>>() // should be always true .map { it.get(this) } - .forEach { ctx.addExtension(it) } + .forEach { ctx.addExtensionDependencies(it) } } - - }
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/extensions.kt b/core/src/main/kotlin/plugability/extensions.kt index 3039cb5a..8d1a7ba0 100644 --- a/core/src/main/kotlin/plugability/extensions.kt +++ b/core/src/main/kotlin/plugability/extensions.kt @@ -7,7 +7,7 @@ data class ExtensionPoint<T : Any> internal constructor( override fun toString() = "ExtensionPoint: $pluginClass/$pointName" } -class Extension<T : Any> internal constructor( +abstract class Extension<T : Any> internal constructor( internal val extensionPoint: ExtensionPoint<T>, internal val pluginClass: String, internal val extensionName: String, @@ -17,12 +17,39 @@ class Extension<T : Any> internal constructor( override fun toString() = "Extension: $pluginClass/$extensionName" override fun equals(other: Any?) = - if (other is Extension<*>) this.pluginClass == other.extensionName && this.extensionName == other.extensionName + if (other is Extension<*>) this.pluginClass == other.pluginClass && this.extensionName == other.extensionName else false override fun hashCode() = listOf(pluginClass, extensionName).hashCode() } +class ExtensionOrdered<T : Any>( + extensionPoint: ExtensionPoint<T>, + pluginClass: String, + extensionName: String, + action: T, + ordering: (OrderDsl.() -> Unit) +) : Extension<T>( + extensionPoint, + pluginClass, + extensionName, + action, + ordering +) + +class ExtensionUnordered<T : Any>( + extensionPoint: ExtensionPoint<T>, + pluginClass: String, + extensionName: String, + action: T +) : Extension<T>( + extensionPoint, + pluginClass, + extensionName, + action, + null +) + internal data class Ordering(val previous: Set<Extension<*>>, val following: Set<Extension<*>>) @DslMarker @@ -31,16 +58,16 @@ annotation class ExtensionsDsl @ExtensionsDsl class ExtendingDSL(private val pluginClass: String, private val extensionName: String) { infix fun <T: Any> ExtensionPoint<T>.with(action: T) = - Extension(this, this@ExtendingDSL.pluginClass, extensionName, action) + ExtensionUnordered(this, this@ExtendingDSL.pluginClass, extensionName, action) - infix fun <T: Any> Extension<T>.order(block: OrderDsl.() -> Unit) = - Extension(extensionPoint, pluginClass, extensionName, action, block) + infix fun <T: Any> ExtensionUnordered<T>.order(block: OrderDsl.() -> Unit) = + ExtensionOrdered(extensionPoint, pluginClass, extensionName, action, block) } @ExtensionsDsl class OrderDsl { - private val previous = mutableSetOf<Extension<*>>() - private val following = mutableSetOf<Extension<*>>() + internal val previous = mutableSetOf<Extension<*>>() + internal val following = mutableSetOf<Extension<*>>() fun after(vararg extensions: Extension<*>) { previous += extensions |