mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 08:27:12 -07:00
Expect plug-ins to use the new plug-in architecture.
This commit is contained in:
parent
7a81b8169f
commit
87ce55c1ea
5 changed files with 76 additions and 52 deletions
|
@ -12,13 +12,12 @@ import com.beust.kobalt.misc.KFiles
|
|||
import com.beust.kobalt.misc.KobaltExecutors
|
||||
import com.beust.kobalt.misc.log
|
||||
import com.beust.kobalt.plugin.KobaltDefaultPlugin
|
||||
import com.beust.kobalt.plugin.packaging.JarUtils
|
||||
import com.google.inject.Provider
|
||||
import java.io.FileInputStream
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import java.net.URLClassLoader
|
||||
import java.util.*
|
||||
import java.util.jar.JarInputStream
|
||||
import java.util.jar.JarFile
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -27,17 +26,12 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
|
|||
val files: KFiles,
|
||||
val depFactory: DepFactory,
|
||||
val localRepo: LocalRepo,
|
||||
val executors: KobaltExecutors) {
|
||||
val executors: KobaltExecutors,
|
||||
val pluginInfo: PluginInfo) {
|
||||
|
||||
companion object {
|
||||
public val MANIFEST_PLUGIN_CLASS : String = "Kobalt-Plugin-Class"
|
||||
|
||||
private var pluginMap = hashMapOf<String, Plugin>()
|
||||
|
||||
fun addPlugin(pluginClass : Class<out Plugin>) {
|
||||
addPluginInstance(Kobalt.INJECTOR.getInstance(pluginClass))
|
||||
}
|
||||
|
||||
fun addPluginInstance(plugin: Plugin) {
|
||||
pluginMap.put(plugin.name, plugin)
|
||||
}
|
||||
|
@ -141,18 +135,6 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
|
|||
|
||||
val dependencies = arrayListOf<IClasspathDependency>()
|
||||
|
||||
public fun instantiateClassName(classLoader: ClassLoader, className : String) : Class<*> {
|
||||
try {
|
||||
log(2, "Instantiating $className")
|
||||
return classLoader.loadClass(className)
|
||||
} catch(ex: Exception) {
|
||||
val urls = Arrays.toString((classLoader as URLClassLoader).urLs)
|
||||
val message = "Couldn't instantiate $className\n with classLoader $urls: $ex"
|
||||
println(message)
|
||||
throw KobaltException(message)
|
||||
}
|
||||
}
|
||||
|
||||
val allTasks : List<PluginTask>
|
||||
get() = Plugins.plugins.flatMap { it.tasks }
|
||||
|
||||
|
@ -165,23 +147,19 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
|
|||
depFactory.create(it.id, executor)
|
||||
|
||||
//
|
||||
// Inspect the jar, open the manifest, instantiate the main class and add it to the plugin repo
|
||||
// Open the jar, parse its plugin.xml and add the resulting PluginInfo to pluginInfo
|
||||
//
|
||||
FileInputStream(it.jarFile.get()).use { fis ->
|
||||
JarInputStream(fis).use { jis ->
|
||||
val manifest = jis.manifest
|
||||
val mainClass = manifest.mainAttributes.getValue(Plugins.MANIFEST_PLUGIN_CLASS) ?:
|
||||
throw KobaltException("Couldn't find \"${Plugins.MANIFEST_PLUGIN_CLASS}\" in the " +
|
||||
"manifest of $it")
|
||||
|
||||
val pluginClassName = mainClass.removeSuffix(" ")
|
||||
val c = instantiateClassName(classLoader, pluginClassName)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
Plugins.addPlugin(c as Class<BasePlugin>)
|
||||
log(1, "Added plugin $c")
|
||||
val pluginXml = JarUtils.extractTextFile(JarFile(it.jarFile.get()), PluginInfo.PLUGIN_XML)
|
||||
if (pluginXml != null) {
|
||||
val thisPluginInfo = PluginInfo.readPluginXml(pluginXml, classLoader)
|
||||
pluginInfo.addPluginInfo(thisPluginInfo)
|
||||
thisPluginInfo.plugins.forEach {
|
||||
Plugins.addPluginInstance(it)
|
||||
}
|
||||
} else {
|
||||
throw KobaltException("Plugin $it doesn't contain a ${PluginInfo.PLUGIN_XML} file")
|
||||
}
|
||||
}
|
||||
}
|
||||
executor.shutdown()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.beust.kobalt.api
|
||||
|
||||
import com.beust.kobalt.maven.IClasspathDependency
|
||||
import com.beust.kobalt.misc.log
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
@ -41,7 +43,10 @@ interface IFactory {
|
|||
fun <T> instanceOf(c: Class<T>) : T
|
||||
}
|
||||
|
||||
class ContributorFactory : IFactory {
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
|
||||
|
@ -116,7 +121,7 @@ class ClassNameXml {
|
|||
* 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) {
|
||||
class PluginInfo(val xml: KobaltPluginXml, val classLoader: ClassLoader?) {
|
||||
val plugins = arrayListOf<Plugin>()
|
||||
val projectContributors = arrayListOf<IProjectContributor>()
|
||||
val classpathContributors = arrayListOf<IClasspathContributor>()
|
||||
|
@ -130,48 +135,71 @@ class PluginInfo(val xml: KobaltPluginXml) {
|
|||
// repos
|
||||
|
||||
companion object {
|
||||
val PLUGIN_XML = "META-INF/plugin.xml" // Plugins.PLUGIN_XML)
|
||||
|
||||
/**
|
||||
* Read Kobalt's own plugin.xml.
|
||||
*/
|
||||
fun readKobaltPluginXml() : PluginInfo {
|
||||
fun readKobaltPluginXml(): PluginInfo {
|
||||
// Note: use forward slash here since we're looking up this file in a .jar file
|
||||
val pluginXml = "META-INF/plugin.xml" // Plugins.PLUGIN_XML)
|
||||
val url = Kobalt::class.java.classLoader.getResource(pluginXml)
|
||||
val url = Kobalt::class.java.classLoader.getResource(PLUGIN_XML)
|
||||
if (url != null) {
|
||||
return readPluginXml(url.openConnection().inputStream)
|
||||
} else {
|
||||
throw AssertionError("Couldn't find $pluginXml")
|
||||
throw AssertionError("Couldn't find $PLUGIN_XML")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a general plugin.xml.
|
||||
*/
|
||||
private fun readPluginXml(ins: InputStream): PluginInfo {
|
||||
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)
|
||||
return PluginInfo(kotlinPlugin, classLoader)
|
||||
}
|
||||
|
||||
fun readPluginXml(s: String, classLoader: ClassLoader? = null)
|
||||
= readPluginXml(ByteArrayInputStream(s.toByteArray(Charsets.UTF_8)), classLoader)
|
||||
}
|
||||
|
||||
init {
|
||||
val factory = Class.forName(xml.factoryClassName).newInstance() as IFactory
|
||||
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)
|
||||
|
||||
xml.plugins?.className?.forEach {
|
||||
plugins.add(factory.instanceOf(Class.forName(it)) as Plugin)
|
||||
plugins.add(factory.instanceOf(forName(it)) as Plugin)
|
||||
}
|
||||
xml.classpathClassName?.className?.forEach {
|
||||
classpathContributors.add(factory.instanceOf(Class.forName(it)) as IClasspathContributor)
|
||||
classpathContributors.add(factory.instanceOf(forName(it)) as IClasspathContributor)
|
||||
}
|
||||
xml.projectClassName?.className?.forEach {
|
||||
projectContributors.add(factory.instanceOf(Class.forName(it)) as IProjectContributor)
|
||||
projectContributors.add(factory.instanceOf(forName(it)) as IProjectContributor)
|
||||
}
|
||||
xml.initClassName?.className?.forEach {
|
||||
initContributors.add(factory.instanceOf(Class.forName(it)) as IInitContributor)
|
||||
initContributors.add(factory.instanceOf(forName(it)) as IInitContributor)
|
||||
}
|
||||
xml.repoClassName?.className?.forEach {
|
||||
repoContributors.add(factory.instanceOf(Class.forName(it)) as IRepoContributor)
|
||||
repoContributors.add(factory.instanceOf(forName(it)) as IRepoContributor)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,9 @@ public class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val b
|
|||
}
|
||||
|
||||
private fun isSameVersionFile(directory: File) =
|
||||
File(directory, VERSION_FILE).readText() == Kobalt.version
|
||||
with(File(directory, VERSION_FILE)) {
|
||||
! exists() || (exists() && readText() == Kobalt.version)
|
||||
}
|
||||
|
||||
private fun generateJarFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File) {
|
||||
val kotlintDeps = jvmCompiler.calculateDependencies(null, context, listOf<IClasspathDependency>())
|
||||
|
|
|
@ -2,11 +2,13 @@ package com.beust.kobalt.plugin.packaging
|
|||
|
||||
import com.beust.kobalt.IFileSpec
|
||||
import com.beust.kobalt.misc.log
|
||||
import com.google.common.io.CharStreams
|
||||
import java.io.*
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.JarInputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
public class JarUtils {
|
||||
|
@ -92,6 +94,20 @@ public class JarUtils {
|
|||
}
|
||||
}
|
||||
|
||||
fun extractTextFile(zip : ZipFile, fileName: String) : String? {
|
||||
val enumEntries = zip.entries()
|
||||
while (enumEntries.hasMoreElements()) {
|
||||
val file = enumEntries.nextElement()
|
||||
if (file.name == fileName) {
|
||||
log(2, "Found $fileName in $zip")
|
||||
zip.getInputStream(file).use { ins ->
|
||||
return CharStreams.toString(InputStreamReader(ins, "UTF-8"))
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun extractJarFile(jarFile: File, destDir: File) {
|
||||
val jar = java.util.jar.JarFile(jarFile)
|
||||
val enumEntries = jar.entries()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<kobalt-plugin>
|
||||
<name>kobalt</name>
|
||||
<factory-class-name>com.beust.kobalt.api.ContributorFactory</factory-class-name>
|
||||
<factory-class-name>com.beust.kobalt.api.GuiceFactory</factory-class-name>
|
||||
<plugins>
|
||||
<class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name>
|
||||
<class-name>com.beust.kobalt.plugin.application.ApplicationPlugin</class-name>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue