1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 16:28:12 -07:00
kobalt/src/main/kotlin/com/beust/kobalt/internal/KobaltPluginXml.kt
Cedric Beust eaf2c0dd70 Comment.
2015-12-05 17:16:42 -08:00

170 lines
7.3 KiB
Kotlin

package com.beust.kobalt.internal
import com.beust.kobalt.api.*
import com.beust.kobalt.misc.log
import java.io.ByteArrayInputStream
import java.io.File
import java.io.InputStream
import javax.xml.bind.JAXBContext
import javax.xml.bind.annotation.XmlElement
import javax.xml.bind.annotation.XmlRootElement
//
// Operations related to the parsing of kobalt-plugin.xml: XML parsing, PluginInfo, etc...
//
/**
* If a plug-in didn't specify a factory, we use our own injector to instantiate all its components.
*/
class GuiceFactory : IFactory {
override fun <T> instanceOf(c: Class<T>) : T = Kobalt.INJECTOR.getInstance(c)
}
/////
// XML parsing
//
// The following classes are used by JAXB to parse the kobalt-plugin.xml file.
/**
* The root element of kobalt-plugin.xml
*/
@XmlRootElement(name = "kobalt-plugin")
class KobaltPluginXml {
@XmlElement @JvmField
var name: String? = null
@XmlElement(name = "plugin-actors") @JvmField
var pluginActors : ClassNameXml? = null
@XmlElement(name = "factory-class-name") @JvmField
var factoryClassName: String? = null
}
class ContributorXml {
@XmlElement @JvmField
val name: String? = null
}
class ClassNameXml {
@XmlElement(name = "class-name") @JvmField
var className: List<String> = arrayListOf()
}
/**
* Turn a KobaltPluginXml (the raw content of kobalt-plugin.xml mapped to POJO's) into a PluginInfo object, which
* contains all the contributors instantiated and other information that Kobalt can actually use. Kobalt code that
* needs to access plug-in info can then just inject a PluginInfo object.
*/
class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) {
val plugins = arrayListOf<IPlugin>()
val projectContributors = arrayListOf<IProjectContributor>()
val classpathContributors = arrayListOf<IClasspathContributor>()
val initContributors = arrayListOf<IInitContributor<File>>()
val repoContributors = arrayListOf<IRepoContributor>()
val compilerFlagContributors = arrayListOf<ICompilerFlagContributor>()
val compilerInterceptors = arrayListOf<ICompilerInterceptor>()
val sourceDirectoriesInterceptors = arrayListOf<ISourceDirectoryIncerceptor>()
val buildDirectoryInterceptors = arrayListOf<IBuildDirectoryIncerceptor>()
val runnerContributors = arrayListOf<IRunnerContributor>()
val testRunnerContributors = arrayListOf<ITestRunnerContributor>()
val classpathInterceptors = arrayListOf<IClasspathInterceptor>()
val compilerContributors = arrayListOf<ICompilerContributor>()
val docContributors = arrayListOf<IDocContributor>()
val sourceDirContributors = arrayListOf<ISourceDirectoryContributor>()
val buildConfigFieldContributors = arrayListOf<IBuildConfigFieldContributor>()
val taskContributors = arrayListOf<ITaskContributor>()
companion object {
val PLUGIN_XML = "META-INF/kobalt-plugin.xml" // Plugins.PLUGIN_XML)
/**
* Read Kobalt's own kobalt-plugin.xml.
*/
fun readKobaltPluginXml(): PluginInfo {
// Note: use forward slash here since we're looking up this file in a .jar file
val url = Kobalt::class.java.classLoader.getResource(PLUGIN_XML)
if (url != null) {
return readPluginXml(url.openConnection().inputStream)
} else {
throw AssertionError("Couldn't find $PLUGIN_XML")
}
}
/**
* Read a general kobalt-plugin.xml.
*/
fun readPluginXml(ins: InputStream, classLoader: ClassLoader? = null): PluginInfo {
val jaxbContext = JAXBContext.newInstance(KobaltPluginXml::class.java)
val kotlinPlugin: KobaltPluginXml = jaxbContext.createUnmarshaller().unmarshal(ins)
as KobaltPluginXml
return PluginInfo(kotlinPlugin, classLoader)
}
fun readPluginXml(s: String, classLoader: ClassLoader? = null)
= readPluginXml(ByteArrayInputStream(s.toByteArray(Charsets.UTF_8)), classLoader)
}
init {
val factory = if (xml.factoryClassName != null) {
Class.forName(xml.factoryClassName).newInstance() as IFactory
} else {
GuiceFactory()
}
fun forName(className: String) =
if (classLoader != null) classLoader.loadClass(className)
else Class.forName(className)
//
// Populate pluginInfo with what was found in Kobalt's own kobalt-plugin.xml
//
xml.pluginActors?.className?.forEach {
with(factory.instanceOf(forName(it))) {
// Note: can't use "when" here since the same instance can implement multiple interfaces
if (this is IBuildConfigFieldContributor) buildConfigFieldContributors.add(this)
if (this is IBuildDirectoryIncerceptor) buildDirectoryInterceptors.add(this)
if (this is IClasspathContributor) classpathContributors.add(this)
if (this is IClasspathInterceptor) classpathInterceptors.add(this)
if (this is ICompilerContributor) compilerContributors.add(this)
if (this is ICompilerFlagContributor) compilerFlagContributors.add(this)
if (this is ICompilerInterceptor) compilerInterceptors.add(this)
if (this is IDocContributor) docContributors.add(this)
if (this is IInitContributor<*>) initContributors.add(this as IInitContributor<File>)
if (this is IPlugin) plugins.add(this)
if (this is IProjectContributor) projectContributors.add(this)
if (this is IRepoContributor) repoContributors.add(this)
if (this is IRunnerContributor) runnerContributors.add(this)
if (this is ISourceDirectoryContributor) sourceDirContributors.add(this)
if (this is ISourceDirectoryIncerceptor) sourceDirectoriesInterceptors.add(this)
if (this is ITestRunnerContributor) testRunnerContributors.add(this)
}
}
}
/**
* Populate pluginInfo with what was found in the plug-in's kobalt-plugin.xml
*/
fun addPluginInfo(pluginInfo: PluginInfo) {
log(2, "Found new plug-in, adding it to pluginInfo: $pluginInfo")
plugins.addAll(pluginInfo.plugins)
classpathContributors.addAll(pluginInfo.classpathContributors)
projectContributors.addAll(pluginInfo.projectContributors)
initContributors.addAll(pluginInfo.initContributors)
repoContributors.addAll(pluginInfo.repoContributors)
compilerFlagContributors.addAll(pluginInfo.compilerFlagContributors)
compilerInterceptors.addAll(pluginInfo.compilerInterceptors)
sourceDirectoriesInterceptors.addAll(pluginInfo.sourceDirectoriesInterceptors)
buildDirectoryInterceptors.addAll(pluginInfo.buildDirectoryInterceptors)
runnerContributors.addAll(pluginInfo.runnerContributors)
testRunnerContributors.addAll(pluginInfo.testRunnerContributors)
classpathInterceptors.addAll(pluginInfo.classpathInterceptors)
compilerContributors.addAll(pluginInfo.compilerContributors)
docContributors.addAll(pluginInfo.docContributors)
sourceDirContributors.addAll(pluginInfo.sourceDirContributors)
buildConfigFieldContributors.addAll(pluginInfo.buildConfigFieldContributors)
taskContributors.addAll(pluginInfo.taskContributors)
}
}