aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Utilities
diff options
context:
space:
mode:
authorDmitry Jemerov <yole@jetbrains.com>2015-12-03 16:22:11 +0100
committerDmitry Jemerov <yole@jetbrains.com>2015-12-03 16:22:49 +0100
commit39631054c58df5841ea268b7002b820ec55f6e0a (patch)
treecefedd8411c859243bd181568e16fcdd372a38c8 /core/src/main/kotlin/Utilities
parent797cb4732c53bf1e3b2091add8cf731fc436607f (diff)
downloaddokka-39631054c58df5841ea268b7002b820ec55f6e0a.tar.gz
dokka-39631054c58df5841ea268b7002b820ec55f6e0a.tar.bz2
dokka-39631054c58df5841ea268b7002b820ec55f6e0a.zip
restructure Dokka build to use Gradle for everything except for the Maven plugin
Diffstat (limited to 'core/src/main/kotlin/Utilities')
-rw-r--r--core/src/main/kotlin/Utilities/DokkaModule.kt73
-rw-r--r--core/src/main/kotlin/Utilities/Html.kt8
-rw-r--r--core/src/main/kotlin/Utilities/Path.kt5
-rw-r--r--core/src/main/kotlin/Utilities/ServiceLocator.kt78
4 files changed, 164 insertions, 0 deletions
diff --git a/core/src/main/kotlin/Utilities/DokkaModule.kt b/core/src/main/kotlin/Utilities/DokkaModule.kt
new file mode 100644
index 00000000..1eb82313
--- /dev/null
+++ b/core/src/main/kotlin/Utilities/DokkaModule.kt
@@ -0,0 +1,73 @@
+package org.jetbrains.dokka.Utilities
+
+import com.google.inject.Binder
+import com.google.inject.Module
+import com.google.inject.Provider
+import com.google.inject.name.Names
+import org.jetbrains.dokka.*
+import org.jetbrains.dokka.Formats.FormatDescriptor
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import java.io.File
+
+class DokkaModule(val environment: AnalysisEnvironment,
+ val options: DocumentationOptions,
+ val logger: DokkaLogger) : Module {
+ override fun configure(binder: Binder) {
+ binder.bind(File::class.java).annotatedWith(Names.named("outputDir")).toInstance(File(options.outputDir))
+
+ binder.bindNameAnnotated<LocationService, SingleFolderLocationService>("singleFolder")
+ binder.bindNameAnnotated<FileLocationService, SingleFolderLocationService>("singleFolder")
+ binder.bindNameAnnotated<LocationService, FoldersLocationService>("folders")
+ binder.bindNameAnnotated<FileLocationService, FoldersLocationService>("folders")
+
+ // defaults
+ binder.bind(LocationService::class.java).to(FoldersLocationService::class.java)
+ binder.bind(FileLocationService::class.java).to(FoldersLocationService::class.java)
+ binder.bind(LanguageService::class.java).to(KotlinLanguageService::class.java)
+
+ binder.bind(HtmlTemplateService::class.java).toProvider(object : Provider<HtmlTemplateService> {
+ override fun get(): HtmlTemplateService = HtmlTemplateService.default("style.css")
+ })
+
+ binder.registerCategory<LanguageService>("language")
+ binder.registerCategory<OutlineFormatService>("outline")
+ binder.registerCategory<FormatService>("format")
+ binder.registerCategory<Generator>("generator")
+
+ val descriptor = ServiceLocator.lookup<FormatDescriptor>("format", options.outputFormat)
+
+ descriptor.outlineServiceClass?.let { clazz ->
+ binder.bind(OutlineFormatService::class.java).to(clazz.java)
+ }
+ descriptor.formatServiceClass?.let { clazz ->
+ binder.bind(FormatService::class.java).to(clazz.java)
+ }
+ binder.bind<PackageDocumentationBuilder>().to(descriptor.packageDocumentationBuilderClass.java)
+ binder.bind<JavaDocumentationBuilder>().to(descriptor.javaDocumentationBuilderClass.java)
+
+ binder.bind<Generator>().to(descriptor.generatorServiceClass.java)
+
+ val coreEnvironment = environment.createCoreEnvironment()
+ binder.bind<KotlinCoreEnvironment>().toInstance(coreEnvironment)
+
+ val dokkaResolutionFacade = environment.createResolutionFacade(coreEnvironment)
+ binder.bind<DokkaResolutionFacade>().toInstance(dokkaResolutionFacade)
+
+ binder.bind<DocumentationOptions>().toInstance(options)
+ binder.bind<DokkaLogger>().toInstance(logger)
+ }
+}
+
+private inline fun <reified T: Any> Binder.registerCategory(category: String) {
+ ServiceLocator.allServices(category).forEach {
+ @Suppress("UNCHECKED_CAST")
+ bind(T::class.java).annotatedWith(Names.named(it.name)).to(T::class.java.classLoader.loadClass(it.className) as Class<T>)
+ }
+}
+
+private inline fun <reified Base : Any, reified T : Base> Binder.bindNameAnnotated(name: String) {
+ bind(Base::class.java).annotatedWith(Names.named(name)).to(T::class.java)
+}
+
+
+inline fun <reified T: Any> Binder.bind() = bind(T::class.java)
diff --git a/core/src/main/kotlin/Utilities/Html.kt b/core/src/main/kotlin/Utilities/Html.kt
new file mode 100644
index 00000000..ce3a1982
--- /dev/null
+++ b/core/src/main/kotlin/Utilities/Html.kt
@@ -0,0 +1,8 @@
+package org.jetbrains.dokka
+
+
+/**
+ * Replaces symbols reserved in HTML with their respective entities.
+ * Replaces & with &amp;, < with &lt; and > with &gt;
+ */
+public fun String.htmlEscape(): String = replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
diff --git a/core/src/main/kotlin/Utilities/Path.kt b/core/src/main/kotlin/Utilities/Path.kt
new file mode 100644
index 00000000..05838499
--- /dev/null
+++ b/core/src/main/kotlin/Utilities/Path.kt
@@ -0,0 +1,5 @@
+package org.jetbrains.dokka
+
+import java.io.File
+
+fun File.appendExtension(extension: String) = if (extension.isEmpty()) this else File(path + "." + extension)
diff --git a/core/src/main/kotlin/Utilities/ServiceLocator.kt b/core/src/main/kotlin/Utilities/ServiceLocator.kt
new file mode 100644
index 00000000..7a5aff79
--- /dev/null
+++ b/core/src/main/kotlin/Utilities/ServiceLocator.kt
@@ -0,0 +1,78 @@
+package org.jetbrains.dokka.Utilities
+
+import java.io.File
+import java.util.*
+import java.util.jar.JarFile
+import java.util.zip.ZipEntry
+
+data class ServiceDescriptor(val name: String, val category: String, val description: String?, val className: String)
+
+class ServiceLookupException(message: String) : Exception(message)
+
+public object ServiceLocator {
+ public fun <T : Any> lookup(clazz: Class<T>, category: String, implementationName: String): T {
+ val descriptor = lookupDescriptor(category, implementationName)
+ val loadedClass = javaClass.classLoader.loadClass(descriptor.className)
+ val constructor = loadedClass.constructors
+ .filter { it.parameterTypes.isEmpty() }
+ .firstOrNull() ?: throw ServiceLookupException("Class ${descriptor.className} has no corresponding constructor")
+
+ val implementationRawType: Any = if (constructor.parameterTypes.isEmpty()) constructor.newInstance() else constructor.newInstance(constructor)
+
+ if (!clazz.isInstance(implementationRawType)) {
+ throw ServiceLookupException("Class ${descriptor.className} is not a subtype of ${clazz.name}")
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ return implementationRawType as T
+ }
+
+ private fun lookupDescriptor(category: String, implementationName: String): ServiceDescriptor {
+ val properties = javaClass.classLoader.getResourceAsStream("dokka/$category/$implementationName.properties")?.use { stream ->
+ Properties().let { properties ->
+ properties.load(stream)
+ properties
+ }
+ } ?: throw ServiceLookupException("No implementation with name $implementationName found in category $category")
+
+ val className = properties["class"]?.toString() ?: throw ServiceLookupException("Implementation $implementationName has no class configured")
+
+ return ServiceDescriptor(implementationName, category, properties["description"]?.toString(), className)
+ }
+
+ fun allServices(category: String): List<ServiceDescriptor> {
+ val entries = this.javaClass.classLoader.getResources("dokka/$category")?.toList() ?: emptyList()
+
+ return entries.flatMap {
+ when (it.protocol) {
+ "file" -> File(it.file).listFiles()?.filter { it.extension == "properties" }?.map { lookupDescriptor(category, it.nameWithoutExtension) } ?: emptyList()
+ "jar" -> {
+ val file = JarFile(it.file.removePrefix("file:").substringBefore("!"))
+ try {
+ val jarPath = it.file.substringAfterLast("!").removePrefix("/")
+ file.entries()
+ .asSequence()
+ .filter { entry -> !entry.isDirectory && entry.path == jarPath && entry.extension == "properties" }
+ .map { entry ->
+ lookupDescriptor(category, entry.fileName.substringBeforeLast("."))
+ }.toList()
+ } finally {
+ file.close()
+ }
+ }
+ else -> emptyList<ServiceDescriptor>()
+ }
+ }
+ }
+}
+
+public inline fun <reified T : Any> ServiceLocator.lookup(category: String, implementationName: String): T = lookup(T::class.java, category, implementationName)
+
+private val ZipEntry.fileName: String
+ get() = name.substringAfterLast("/", name)
+
+private val ZipEntry.path: String
+ get() = name.substringBeforeLast("/", "").removePrefix("/")
+
+private val ZipEntry.extension: String?
+ get() = fileName.let { fn -> if ("." in fn) fn.substringAfterLast(".") else null }